]> granicus.if.org Git - curl/commitdiff
PolarSSL: Implement public key pinning
authormoparisthebest <admin@moparisthebest.com>
Fri, 22 Apr 2016 01:21:45 +0000 (21:21 -0400)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 24 Apr 2016 10:27:39 +0000 (12:27 +0200)
docs/curl.1
docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
lib/vtls/polarssl.c
lib/vtls/polarssl.h
tests/runtests.pl

index 2ed24dba01fd12854b24fa20b5412f2c286f801b..8f7c4763fb752ea6d1c5fb6a2930a05dada6e1ea 100644 (file)
@@ -589,9 +589,16 @@ indicating its identity. A public key is extracted from this certificate and
 if it does not exactly match the public key provided to this option, curl will
 abort the connection before sending or receiving any data.
 
-Added in 7.39.0 for OpenSSL, GnuTLS and GSKit. Added in 7.43.0 for NSS and
-wolfSSL/CyaSSL. sha256 support added in 7.44.0 for OpenSSL,
-GnuTLS, NSS and wolfSSL/CyaSSL. Other SSL backends not supported.
+PEM/DER support:
+  7.39.0: OpenSSL, GnuTLS and GSKit
+  7.43.0: NSS and wolfSSL/CyaSSL
+  7.47.0: mbedtls
+  7.49.0: PolarSSL
+sha256 support:
+  7.44.0: OpenSSL, GnuTLS, NSS and wolfSSL/CyaSSL.
+  7.47.0: mbedtls
+  7.49.0: PolarSSL
+Other SSL backends not supported.
 
 If this option is used several times, the last one will be used.
 .IP "--cert-status"
index ff1fe740ea475a89c22460aa3515ec881f435601..4e673bd4dbd2ac43f76793ff21ca538864efe565 100644 (file)
@@ -90,10 +90,16 @@ footer:
 -----END PUBLIC KEY-----
 .fi
 .SH AVAILABILITY
-Added in 7.39.0 for OpenSSL, GnuTLS and GSKit. Added in 7.43.0 for
-NSS and wolfSSL/CyaSSL. Added for mbedtls in 7.47.0, sha256 support
-added in 7.44.0 for OpenSSL, GnuTLS, NSS and wolfSSL/CyaSSL. Other
-SSL backends not supported.
+PEM/DER support:
+  7.39.0: OpenSSL, GnuTLS and GSKit
+  7.43.0: NSS and wolfSSL/CyaSSL
+  7.47.0: mbedtls
+  7.49.0: PolarSSL
+sha256 support:
+  7.44.0: OpenSSL, GnuTLS, NSS and wolfSSL/CyaSSL.
+  7.47.0: mbedtls
+  7.49.0: PolarSSL
+Other SSL backends not supported.
 .SH RETURN VALUE
 Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
 CURLE_OUT_OF_MEMORY if there was insufficient heap space.
index fcce60f051748957ab0823c4a87ea6fe65df5d3d..0c6ef239e9d5ba754ce5d58092d55fa7ecb7e3be 100644 (file)
@@ -36,6 +36,7 @@
 #include <polarssl/certs.h>
 #include <polarssl/x509.h>
 #include <polarssl/version.h>
+#include <polarssl/sha256.h>
 
 #if POLARSSL_VERSION_NUMBER < 0x01030000
 #error too old PolarSSL
 /* The last #include file should be: */
 #include "memdebug.h"
 
+/* See https://tls.mbed.org/discussions/generic/
+   howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
+*/
+#define RSA_PUB_DER_MAX_BYTES   (38 + 2 * POLARSSL_MPI_MAX_SIZE)
+#define ECP_PUB_DER_MAX_BYTES   (30 + 2 * POLARSSL_ECP_MAX_BYTES)
+
+#define PUB_DER_MAX_BYTES   (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+                             RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+
 /* apply threading? */
 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 #define THREADING_SUPPORT
@@ -453,6 +463,61 @@ polarssl_connect_step2(struct connectdata *conn,
       infof(data, "Dumping cert info:\n%s\n", buffer);
   }
 
+  /* adapted from mbedtls.c */
+  if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+    int size;
+    CURLcode result;
+    x509_crt *p;
+    unsigned char pubkey[PUB_DER_MAX_BYTES];
+    const x509_crt *peercert;
+
+    peercert = ssl_get_peer_cert(&connssl->ssl);
+
+    if(!peercert || !peercert->raw.p || !peercert->raw.len) {
+      failf(data, "Failed due to missing peer certificate");
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    p = calloc(1, sizeof(*p));
+
+    if(!p)
+      return CURLE_OUT_OF_MEMORY;
+
+    x509_crt_init(p);
+
+    /* Make a copy of our const peercert because pk_write_pubkey_der
+       needs a non-const key, for now.
+       https://github.com/ARMmbed/mbedtls/issues/396 */
+    if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
+      failf(data, "Failed copying peer certificate");
+      x509_crt_free(p);
+      free(p);
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
+
+    if(size <= 0) {
+      failf(data, "Failed copying public key from peer certificate");
+      x509_crt_free(p);
+      free(p);
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    /* pk_write_pubkey_der writes data at the end of the buffer. */
+    result = Curl_pin_peer_pubkey(data,
+                                  data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+                                  &pubkey[PUB_DER_MAX_BYTES - size], size);
+    if(result) {
+      x509_crt_free(p);
+      free(p);
+      return result;
+    }
+
+    x509_crt_free(p);
+    free(p);
+  }
+
 #ifdef HAS_ALPN
   if(data->set.ssl_enable_alpn) {
     const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl);
index 1ab5a841f85628d6d06987f0b6fe59c9761c1a93..49548e907abb5f53c8d7e23b362f677878094b01 100644 (file)
@@ -26,6 +26,8 @@
 
 #ifdef USE_POLARSSL
 
+#include <polarssl/sha256.h>
+
 /* Called on first use PolarSSL, setup threading if supported */
 int  Curl_polarssl_init(void);
 void Curl_polarssl_cleanup(void);
@@ -65,6 +67,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex);
 #define curlssl_version Curl_polarssl_version
 #define curlssl_check_cxn(x) ((void)x, -1)
 #define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
+#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0)
 
 /* This might cause libcurl to use a weeker random!
    TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that
index f2b73f69d5ec6da401b1e1708b773b3b2ed439b8..0128e448117e2c5360fd8913f2261cbd7282e264 100755 (executable)
@@ -2358,6 +2358,7 @@ sub checksystem {
            }
            elsif ($libcurl =~ /polarssl/i) {
                $has_polarssl=1;
+               $has_sslpinning=1;
                $ssllib="polarssl";
            }
            elsif ($libcurl =~ /axtls/i) {