From b47c17d67c9b5c9e985375b090f0140bf43cb146 Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Wed, 25 Mar 2015 13:48:41 +0100 Subject: nss: implement public key pinning for NSS backend Bug: https://bugzilla.redhat.com/1195771 --- lib/vtls/nss.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'lib') diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index feb00ca81..daf12a9d7 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -56,6 +56,7 @@ #include #include #include +#include /* 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: -- cgit v1.2.3