ssl: add server cert's "sha256//" hash to verbose
Add a "pinnedpubkey" section to the "Server Certificate" verbose Bug: https://github.com/bagder/curl/issues/410 Reported-by: W. Mark Kubacki Closes #430 Closes #410
This commit is contained in:
parent
c979a3d0c4
commit
30c131f51f
@ -434,7 +434,8 @@ cyassl_connect_step2(struct connectdata *conn,
|
|||||||
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Curl_pin_peer_pubkey(data->set.str[STRING_SSL_PINNEDPUBLICKEY],
|
result = Curl_pin_peer_pubkey(data,
|
||||||
|
data->set.str[STRING_SSL_PINNEDPUBLICKEY],
|
||||||
(const unsigned char *)pubkey->header,
|
(const unsigned char *)pubkey->header,
|
||||||
(size_t)(pubkey->end - pubkey->header));
|
(size_t)(pubkey->end - pubkey->header));
|
||||||
if(result) {
|
if(result) {
|
||||||
|
@ -874,7 +874,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
|
|||||||
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
||||||
Curl_parseX509(&x509, cert, certend);
|
Curl_parseX509(&x509, cert, certend);
|
||||||
p = &x509.subjectPublicKeyInfo;
|
p = &x509.subjectPublicKeyInfo;
|
||||||
result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header);
|
result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
|
||||||
if(result) {
|
if(result) {
|
||||||
failf(data, "SSL: public key does not match pinned public key!");
|
failf(data, "SSL: public key does not match pinned public key!");
|
||||||
return result;
|
return result;
|
||||||
|
@ -724,7 +724,8 @@ gtls_connect_step1(struct connectdata *conn,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert,
|
static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data,
|
||||||
|
gnutls_x509_crt_t cert,
|
||||||
const char *pinnedpubkey)
|
const char *pinnedpubkey)
|
||||||
{
|
{
|
||||||
/* Scratch */
|
/* Scratch */
|
||||||
@ -769,7 +770,7 @@ static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert,
|
|||||||
/* End Gyrations */
|
/* End Gyrations */
|
||||||
|
|
||||||
/* The one good exit point */
|
/* The one good exit point */
|
||||||
result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1);
|
result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
if(NULL != key)
|
if(NULL != key)
|
||||||
@ -1152,7 +1153,7 @@ gtls_connect_step3(struct connectdata *conn,
|
|||||||
|
|
||||||
ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
||||||
if(ptr) {
|
if(ptr) {
|
||||||
result = pkp_pin_peer_pubkey(x509_cert, ptr);
|
result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
|
||||||
if(result != CURLE_OK) {
|
if(result != CURLE_OK) {
|
||||||
failf(data, "SSL: public key does not match pinned public key!");
|
failf(data, "SSL: public key does not match pinned public key!");
|
||||||
gnutls_x509_crt_deinit(x509_cert);
|
gnutls_x509_crt_deinit(x509_cert);
|
||||||
|
@ -973,8 +973,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
|
|||||||
SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
|
SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
|
||||||
if(cert_der) {
|
if(cert_der) {
|
||||||
/* compare the public key with the pinned public key */
|
/* compare the public key with the pinned public key */
|
||||||
result = Curl_pin_peer_pubkey(pinnedpubkey,
|
result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
|
||||||
cert_der->data,
|
|
||||||
cert_der->len);
|
cert_der->len);
|
||||||
SECITEM_FreeItem(cert_der, PR_TRUE);
|
SECITEM_FreeItem(cert_der, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
@ -2420,7 +2420,8 @@ static CURLcode get_cert_chain(struct connectdata *conn,
|
|||||||
* Heavily modified from:
|
* Heavily modified from:
|
||||||
* https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
|
* https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
|
||||||
*/
|
*/
|
||||||
static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey)
|
static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, X509* cert,
|
||||||
|
const char *pinnedpubkey)
|
||||||
{
|
{
|
||||||
/* Scratch */
|
/* Scratch */
|
||||||
int len1 = 0, len2 = 0;
|
int len1 = 0, len2 = 0;
|
||||||
@ -2465,7 +2466,7 @@ static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey)
|
|||||||
/* End Gyrations */
|
/* End Gyrations */
|
||||||
|
|
||||||
/* The one good exit point */
|
/* The one good exit point */
|
||||||
result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1);
|
result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
/* https://www.openssl.org/docs/crypto/buffer.html */
|
/* https://www.openssl.org/docs/crypto/buffer.html */
|
||||||
@ -2629,7 +2630,7 @@ static CURLcode servercert(struct connectdata *conn,
|
|||||||
|
|
||||||
ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
||||||
if(!result && ptr) {
|
if(!result && ptr) {
|
||||||
result = pkp_pin_peer_pubkey(connssl->server_cert, ptr);
|
result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr);
|
||||||
if(result)
|
if(result)
|
||||||
failf(data, "SSL: public key does not match pinned public key!");
|
failf(data, "SSL: public key does not match pinned public key!");
|
||||||
}
|
}
|
||||||
|
@ -765,7 +765,8 @@ static CURLcode pubkey_pem_to_der(const char *pem,
|
|||||||
* Generic pinned public key check.
|
* Generic pinned public key check.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
|
CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data,
|
||||||
|
const char *pinnedpubkey,
|
||||||
const unsigned char *pubkey, size_t pubkeylen)
|
const unsigned char *pubkey, size_t pubkeylen)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -775,9 +776,10 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
|
|||||||
CURLcode pem_read;
|
CURLcode pem_read;
|
||||||
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
||||||
#ifdef curlssl_sha256sum
|
#ifdef curlssl_sha256sum
|
||||||
size_t pinkeylen;
|
CURLcode encode;
|
||||||
char *pinkeycopy, *begin_pos, *end_pos;
|
size_t encodedlen, pinkeylen;
|
||||||
unsigned char *sha256sumdigest = NULL, *expectedsha256sumdigest = NULL;
|
char *encoded, *pinkeycopy, *begin_pos, *end_pos;
|
||||||
|
unsigned char *sha256sumdigest = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* if a path wasn't specified, don't pin */
|
/* if a path wasn't specified, don't pin */
|
||||||
@ -796,11 +798,21 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
|
|||||||
curlssl_sha256sum(pubkey, pubkeylen,
|
curlssl_sha256sum(pubkey, pubkeylen,
|
||||||
sha256sumdigest, SHA256_DIGEST_LENGTH);
|
sha256sumdigest, SHA256_DIGEST_LENGTH);
|
||||||
|
|
||||||
|
encode = Curl_base64_encode(data, (char *)sha256sumdigest,
|
||||||
|
SHA256_DIGEST_LENGTH, &encoded, &encodedlen);
|
||||||
|
Curl_safefree(sha256sumdigest);
|
||||||
|
|
||||||
|
if(!encode) {
|
||||||
|
infof(data, "\t pinnedpubkey: sha256//%s\n", encoded);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return encode;
|
||||||
|
|
||||||
/* it starts with sha256//, copy so we can modify it */
|
/* it starts with sha256//, copy so we can modify it */
|
||||||
pinkeylen = strlen(pinnedpubkey) + 1;
|
pinkeylen = strlen(pinnedpubkey) + 1;
|
||||||
pinkeycopy = malloc(pinkeylen);
|
pinkeycopy = malloc(pinkeylen);
|
||||||
if(!pinkeycopy) {
|
if(!pinkeycopy) {
|
||||||
Curl_safefree(sha256sumdigest);
|
Curl_safefree(encoded);
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
|
memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
|
||||||
@ -815,20 +827,11 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
|
|||||||
if(end_pos)
|
if(end_pos)
|
||||||
end_pos[0] = '\0';
|
end_pos[0] = '\0';
|
||||||
|
|
||||||
/* decode base64 pinnedpubkey, 8 is length of "sha256//" */
|
/* compare base64 sha256 digests, 8 is the length of "sha256//" */
|
||||||
pem_read = Curl_base64_decode(begin_pos + 8,
|
if(encodedlen == strlen(begin_pos + 8) &&
|
||||||
&expectedsha256sumdigest, &size);
|
!memcmp(encoded, begin_pos + 8, encodedlen)) {
|
||||||
/* if not valid base64, don't bother comparing or freeing */
|
result = CURLE_OK;
|
||||||
if(!pem_read) {
|
break;
|
||||||
/* compare sha256 digests directly */
|
|
||||||
if(SHA256_DIGEST_LENGTH == size &&
|
|
||||||
!memcmp(sha256sumdigest, expectedsha256sumdigest,
|
|
||||||
SHA256_DIGEST_LENGTH)) {
|
|
||||||
result = CURLE_OK;
|
|
||||||
Curl_safefree(expectedsha256sumdigest);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Curl_safefree(expectedsha256sumdigest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -840,7 +843,7 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
|
|||||||
begin_pos = strstr(end_pos, "sha256//");
|
begin_pos = strstr(end_pos, "sha256//");
|
||||||
}
|
}
|
||||||
} while(end_pos && begin_pos);
|
} while(end_pos && begin_pos);
|
||||||
Curl_safefree(sha256sumdigest);
|
Curl_safefree(encoded);
|
||||||
Curl_safefree(pinkeycopy);
|
Curl_safefree(pinkeycopy);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,8 @@ CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
|
|||||||
unsigned char *md5sum, /* output */
|
unsigned char *md5sum, /* output */
|
||||||
size_t md5len);
|
size_t md5len);
|
||||||
/* Check pinned public key. */
|
/* Check pinned public key. */
|
||||||
CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
|
CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data,
|
||||||
|
const char *pinnedpubkey,
|
||||||
const unsigned char *pubkey, size_t pubkeylen);
|
const unsigned char *pubkey, size_t pubkeylen);
|
||||||
|
|
||||||
bool Curl_ssl_cert_status_request(void);
|
bool Curl_ssl_cert_status_request(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user