From 473322ec66a0969c3c59e8006f9ac72768b91adf Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Tue, 14 Oct 2014 14:58:26 +0200 Subject: Implement pinned public key in GSKit backend --- lib/vtls/gskit.c | 20 +++++++++++++++++++- lib/x509asn1.c | 15 ++++++++++++--- lib/x509asn1.h | 4 +++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index 0f8b08f2c..ae878c7bc 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -804,6 +804,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) const gsk_cert_data_elem *p; const char *cert = (const char *) NULL; const char *certend; + const char *ptr; int i; CURLcode cc; @@ -857,6 +858,23 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) } } + /* Check pinned public key. */ + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(cc == CURLE_OK && ptr) { + curl_X509certificate x509; + curl_asn1Element *p; + + if(!cert) + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + Curl_parseX509(&x509, cert, certend); + p = &x509.subjectPublicKeyInfo; + cc = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header); + if(cc != CURLE_OK) { + failf(data, "SSL: public key does not match pinned public key!"); + return cc; + } + } + connssl->connecting_state = ssl_connect_done; return CURLE_OK; } diff --git a/lib/x509asn1.c b/lib/x509asn1.c index 31ea5de00..e100e07f4 100644 --- a/lib/x509asn1.c +++ b/lib/x509asn1.c @@ -122,6 +122,7 @@ const char * Curl_getASN1Element(curl_asn1Element * elem, return (const char *) NULL; /* Process header byte. */ + elem->header = beg; b = (unsigned char) *beg++; elem->constructed = (b & 0x20) != 0; elem->class = (b >> 6) & 3; @@ -682,6 +683,7 @@ void Curl_parseX509(curl_X509certificate * cert, Syntax is assumed to have already been checked by the SSL backend. See RFC 5280. */ + cert->certificate.header = NULL; cert->certificate.beg = beg; cert->certificate.end = end; @@ -701,6 +703,7 @@ void Curl_parseX509(curl_X509certificate * cert, beg = tbsCertificate.beg; end = tbsCertificate.end; /* Get optional version, get serialNumber. */ + cert->version.header = NULL; cert->version.beg = &defaultVersion; cert->version.end = &defaultVersion + sizeof defaultVersion;; beg = Curl_getASN1Element(&elem, beg, end); @@ -720,15 +723,19 @@ void Curl_parseX509(curl_X509certificate * cert, /* Get subject. */ beg = Curl_getASN1Element(&cert->subject, beg, end); /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */ - beg = Curl_getASN1Element(&elem, beg, end); + beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end); ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm, - elem.beg, elem.end); - Curl_getASN1Element(&cert->subjectPublicKey, ccp, elem.end); + cert->subjectPublicKeyInfo.beg, + cert->subjectPublicKeyInfo.end); + Curl_getASN1Element(&cert->subjectPublicKey, ccp, + cert->subjectPublicKeyInfo.end); /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; cert->extensions.tag = elem.tag = 0; + cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; + cert->extensions.header = NULL; cert->extensions.beg = cert->extensions.end = ""; if(beg < end) beg = Curl_getASN1Element(&elem, beg, end); @@ -771,6 +778,7 @@ static const char * dumpAlgo(curl_asn1Element * param, /* Get algorithm parameters and return algorithm name. */ beg = Curl_getASN1Element(&oid, beg, end); + param->header = NULL; param->tag = 0; param->beg = param->end = end; if(beg < end) @@ -1140,6 +1148,7 @@ CURLcode Curl_verifyhost(struct connectdata * conn, } /* Process subject. */ + name.header = NULL; name.beg = name.end = ""; q = cert.subject.beg; /* we have to look to the last occurrence of a commonName in the diff --git a/lib/x509asn1.h b/lib/x509asn1.h index 274d728b7..075c424f3 100644 --- a/lib/x509asn1.h +++ b/lib/x509asn1.h @@ -76,8 +76,9 @@ /* ASN.1 parsed element. */ typedef struct { + const char * header; /* Pointer to header byte. */ const char * beg; /* Pointer to element data. */ - const char * end; /* Pointer to 1st byte after element data. */ + const char * end; /* Pointer to 1st byte after element. */ unsigned char class; /* ASN.1 element class. */ unsigned char tag; /* ASN.1 element tag. */ bool constructed; /* Element is constructed. */ @@ -102,6 +103,7 @@ typedef struct { curl_asn1Element notBefore; curl_asn1Element notAfter; curl_asn1Element subject; + curl_asn1Element subjectPublicKeyInfo; curl_asn1Element subjectPublicKeyAlgorithm; curl_asn1Element subjectPublicKey; curl_asn1Element issuerUniqueID; -- cgit v1.2.3