andre@1086: From e5c7feec5151299975fe03184cc322ea51fb45c2 Mon Sep 17 00:00:00 2001 andre@998: From: Andre Heinecke andre@1086: Date: Fri, 12 Sep 2014 13:01:07 +0200 andre@1086: Subject: [PATCH 2/2] Add CURLOPT_PEERCERT option to pin a peer cert andre@998: andre@1086: This is only implemented for a specific usecase with polarssl andre@998: --- andre@998: include/curl/curl.h | 3 +++ andre@998: include/curl/typecheck-gcc.h | 1 + andre@998: lib/url.c | 8 ++++++++ andre@998: lib/urldata.h | 1 + andre@1086: lib/vtls/polarssl.c | 41 +++++++++++++++++++++++++++++++++++++++++ andre@1086: 5 files changed, 54 insertions(+) andre@998: andre@998: diff --git a/include/curl/curl.h b/include/curl/curl.h andre@998: index d40b2db..20a9d82 100644 andre@998: --- a/include/curl/curl.h andre@998: +++ b/include/curl/curl.h andre@998: @@ -1611,6 +1611,9 @@ typedef enum { andre@998: /* Pass in a bitmask of "header options" */ andre@998: CINIT(HEADEROPT, LONG, 229), andre@998: andre@998: + /* Peer certificate */ andre@998: + CINIT(PEERCERT, OBJECTPOINT, 230), andre@998: + andre@998: CURLOPT_LASTENTRY /* the last unused */ andre@998: } CURLoption; andre@998: andre@998: diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h andre@998: index 69d41a2..241529d 100644 andre@998: --- a/include/curl/typecheck-gcc.h andre@998: +++ b/include/curl/typecheck-gcc.h andre@998: @@ -258,6 +258,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, andre@998: (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ andre@998: (option) == CURLOPT_CRLFILE || \ andre@998: (option) == CURLOPT_ISSUERCERT || \ andre@998: + (option) == CURLOPT_PEERCERT || \ andre@998: (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ andre@998: (option) == CURLOPT_SSH_KNOWNHOSTS || \ andre@998: (option) == CURLOPT_MAIL_FROM || \ andre@998: diff --git a/lib/url.c b/lib/url.c andre@1086: index 67126ab3..5721ee2 100644 andre@998: --- a/lib/url.c andre@998: +++ b/lib/url.c andre@998: @@ -2015,6 +2015,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, andre@998: result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT], andre@998: va_arg(param, char *)); andre@998: break; andre@998: + case CURLOPT_PEERCERT: andre@998: + /* andre@998: + * Set peer certificate file andre@998: + * to check peer certificate against andre@998: + */ andre@998: + result = setstropt(&data->set.str[STRING_SSL_PEERCERT], andre@998: + va_arg(param, char *)); andre@998: + break; andre@998: case CURLOPT_TELNETOPTIONS: andre@998: /* andre@998: * Set a linked list of telnet options andre@998: diff --git a/lib/urldata.h b/lib/urldata.h andre@998: index 8594c2f..a6dc1ae 100644 andre@998: --- a/lib/urldata.h andre@998: +++ b/lib/urldata.h andre@998: @@ -1391,6 +1391,7 @@ enum dupstring { andre@998: STRING_USERAGENT, /* User-Agent string */ andre@998: STRING_SSL_CRLFILE, /* crl file to check certificate */ andre@998: STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */ andre@998: + STRING_SSL_PEERCERT, /* issuer cert file to check certificate */ andre@998: STRING_USERNAME, /* , if used */ andre@998: STRING_PASSWORD, /* , if used */ andre@998: STRING_OPTIONS, /* , if used */ andre@998: diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c andre@1086: index 08dc4c6..8f34901 100644 andre@998: --- a/lib/vtls/polarssl.c andre@998: +++ b/lib/vtls/polarssl.c andre@1086: @@ -403,6 +403,44 @@ polarssl_connect_step1(struct connectdata *conn, andre@1086: return CURLE_OK; andre@1086: } andre@998: andre@1086: +static int andre@1086: +pinned_verify(void *pinned_cert_file_name, x509_crt *crt, andre@1086: + int depth, int *flags) andre@1086: +{ andre@1086: + x509_crt pinned_cert; andre@1086: + x509_crt *leaf = crt; andre@1086: + unsigned int i; andre@1086: + int ret; andre@998: + andre@1086: + if (pinned_cert_file_name == NULL || crt == NULL) { andre@1086: + *flags |= BADCERT_NOT_TRUSTED; andre@1086: + return *flags; andre@1086: + } andre@998: + andre@1086: + x509_crt_init(&pinned_cert); andre@1086: + ret = x509_crt_parse_file(&pinned_cert, pinned_cert_file_name); andre@998: + andre@1086: + if(ret) { andre@1086: + x509_crt_free(&pinned_cert); andre@1086: + *flags |= BADCERT_NOT_TRUSTED; andre@1086: + return *flags; andre@1086: + } andre@1086: + andre@1086: + while (leaf->next) { andre@1086: + leaf = leaf->next; andre@1086: + } andre@1086: + andre@1086: + ret = memcmp(pinned_cert.raw.p, leaf->raw.p, pinned_cert.raw.len); andre@1086: + x509_crt_free(&pinned_cert); andre@1086: + if (ret == 0) { andre@1086: + *flags = 0; andre@1086: + return 0; andre@1086: + } andre@1086: + andre@1086: + *flags |= BADCERT_NOT_TRUSTED; andre@1086: + return *flags; andre@1086: +} andre@1086: + andre@1086: static CURLcode andre@1086: polarssl_connect_step2(struct connectdata *conn, andre@1086: int sockindex) andre@1086: @@ -422,6 +460,9 @@ polarssl_connect_step2(struct connectdata *conn, andre@1086: conn->recv[sockindex] = polarssl_recv; andre@1086: conn->send[sockindex] = polarssl_send; andre@998: andre@1086: + if(data->set.str[STRING_SSL_PEERCERT]) andre@1086: + ssl_set_verify (&connssl->ssl, pinned_verify, data->set.str[STRING_SSL_PEERCERT]); andre@1086: + andre@1086: for(;;) { andre@1086: if(!(ret = ssl_handshake(&connssl->ssl))) andre@1086: break; andre@998: -- andre@998: 1.9.1 andre@998: