nss: implement public key pinning for NSS backend
Bug: https://bugzilla.redhat.com/1195771
This commit is contained in:
@@ -56,6 +56,7 @@
|
||||
#include <base64.h>
|
||||
#include <cert.h>
|
||||
#include <prerror.h>
|
||||
#include <keyhi.h> /* for SECKEY_DestroyPublicKey() */
|
||||
|
||||
#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH)
|
||||
|
||||
@@ -943,6 +944,53 @@ static SECStatus check_issuer_cert(PRFileDesc *sock,
|
||||
return res;
|
||||
}
|
||||
|
||||
static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
|
||||
const char *pinnedpubkey)
|
||||
{
|
||||
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
||||
struct SessionHandle *data = connssl->data;
|
||||
CERTCertificate *cert;
|
||||
|
||||
if(!pinnedpubkey)
|
||||
/* no pinned public key specified */
|
||||
return CURLE_OK;
|
||||
|
||||
/* get peer certificate */
|
||||
cert = SSL_PeerCertificate(connssl->handle);
|
||||
if(cert) {
|
||||
/* extract public key from peer certificate */
|
||||
SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
|
||||
if(pubkey) {
|
||||
/* encode the public key as DER */
|
||||
SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
|
||||
if(cert_der) {
|
||||
/* compare the public key with the pinned public key */
|
||||
result = Curl_pin_peer_pubkey(pinnedpubkey,
|
||||
cert_der->data,
|
||||
cert_der->len);
|
||||
SECITEM_FreeItem(cert_der, PR_TRUE);
|
||||
}
|
||||
SECKEY_DestroyPublicKey(pubkey);
|
||||
}
|
||||
CERT_DestroyCertificate(cert);
|
||||
}
|
||||
|
||||
/* report the resulting status */
|
||||
switch(result) {
|
||||
case CURLE_OK:
|
||||
infof(data, "pinned public key verified successfully!\n");
|
||||
break;
|
||||
case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
|
||||
failf(data, "failed to verify pinned public key");
|
||||
break;
|
||||
default:
|
||||
/* OOM, etc. */
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Callback to pick the SSL client certificate.
|
||||
@@ -1806,6 +1854,11 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
|
||||
}
|
||||
}
|
||||
|
||||
result = cmp_peer_pubkey(connssl, data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
|
||||
if(result)
|
||||
/* status already printed */
|
||||
goto error;
|
||||
|
||||
return CURLE_OK;
|
||||
|
||||
error:
|
||||
|
||||
Reference in New Issue
Block a user