diff options
author | Kamil Dudka <kdudka@redhat.com> | 2015-03-25 13:48:41 +0100 |
---|---|---|
committer | Kamil Dudka <kdudka@redhat.com> | 2015-04-22 13:21:31 +0200 |
commit | b47c17d67c9b5c9e985375b090f0140bf43cb146 (patch) | |
tree | eae985fca8853c0dcbf72e5556d070637f86db56 /lib | |
parent | 1fd33e3ec8fcfe6f5797b212980ececd6bdb9d03 (diff) |
nss: implement public key pinning for NSS backend
Bug: https://bugzilla.redhat.com/1195771
Diffstat (limited to 'lib')
-rw-r--r-- | lib/vtls/nss.c | 53 |
1 files changed, 53 insertions, 0 deletions
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 <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: |