aboutsummaryrefslogtreecommitdiff
path: root/lib/vtls
diff options
context:
space:
mode:
authorKamil Dudka <kdudka@redhat.com>2015-03-25 13:48:41 +0100
committerKamil Dudka <kdudka@redhat.com>2015-04-22 13:21:31 +0200
commitb47c17d67c9b5c9e985375b090f0140bf43cb146 (patch)
treeeae985fca8853c0dcbf72e5556d070637f86db56 /lib/vtls
parent1fd33e3ec8fcfe6f5797b212980ececd6bdb9d03 (diff)
nss: implement public key pinning for NSS backend
Bug: https://bugzilla.redhat.com/1195771
Diffstat (limited to 'lib/vtls')
-rw-r--r--lib/vtls/nss.c53
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: