Revert "Update to 7.40.1"
[platform/upstream/curl.git] / lib / vtls / openssl.c
index 7374c13..c489600 100644 (file)
@@ -62,6 +62,7 @@
 #include <openssl/dh.h>
 #include <openssl/err.h>
 #include <openssl/md5.h>
+#include <openssl/conf.h>
 #else
 #include <rand.h>
 #include <x509v3.h>
@@ -538,6 +539,7 @@ int cert_stuff(struct connectdata *conn,
 
       if(!cert_done)
         return 0; /* failure! */
+      break;
 #else
       failf(data, "file type P12 for certificate not supported");
       return 0;
@@ -739,6 +741,7 @@ int Curl_ossl_init(void)
     return 0;
 
   OpenSSL_add_all_algorithms();
+  OPENSSL_config(NULL);
 
   return 1;
 }
@@ -1400,6 +1403,21 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
 #endif
 
 #ifdef USE_NGHTTP2
+
+#undef HAS_ALPN
+#if defined(HAVE_SSL_CTX_SET_ALPN_PROTOS) && \
+  defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
+#  define HAS_ALPN 1
+#endif
+
+#if !defined(HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB) || \
+  defined(OPENSSL_NO_NEXTPROTONEG)
+#  if !defined(HAS_ALPN)
+#    error http2 builds require OpenSSL with NPN or ALPN support
+#  endif
+#endif
+
+
 /*
  * in is a list of lenght prefixed strings. this function has to select
  * the protocol we want to use from the list and write its string into out.
@@ -1415,21 +1433,50 @@ select_next_proto_cb(SSL *ssl,
   (void)ssl;
 
   if(retval == 1) {
-    infof(conn->data, "NPN, negotiated HTTP2\n");
-    conn->negnpn = NPN_HTTP2_DRAFT09;
+    infof(conn->data, "NPN, negotiated HTTP2 (%s)\n",
+          NGHTTP2_PROTO_VERSION_ID);
+    conn->negnpn = NPN_HTTP2;
   }
   else if(retval == 0) {
     infof(conn->data, "NPN, negotiated HTTP1.1\n");
     conn->negnpn = NPN_HTTP1_1;
   }
   else {
-    infof(conn->data, "NPN, no overlap, negotiated nothing\n");
+    infof(conn->data, "NPN, no overlap, use HTTP1.1\n",
+          NGHTTP2_PROTO_VERSION_ID);
+    *out = (unsigned char*)"http/1.1";
+    *outlen = sizeof("http/1.1") - 1;
+    conn->negnpn = NPN_HTTP1_1;
   }
 
   return SSL_TLSEXT_ERR_OK;
 }
 #endif
 
+static const char *
+get_ssl_version_txt(SSL_SESSION *session)
+{
+  if(NULL == session)
+    return "";
+
+  switch(session->ssl_version) {
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+  case TLS1_2_VERSION:
+    return "TLSv1.2";
+  case TLS1_1_VERSION:
+    return "TLSv1.1";
+#endif
+  case TLS1_VERSION:
+    return "TLSv1.0";
+  case SSL3_VERSION:
+    return "SSLv3";
+  case SSL2_VERSION:
+    return "SSLv2";
+  }
+  return "unknown";
+}
+
+
 static CURLcode
 ossl_connect_step1(struct connectdata *conn,
                    int sockindex)
@@ -1451,12 +1498,17 @@ ossl_connect_step1(struct connectdata *conn,
   struct in_addr addr;
 #endif
 #endif
+#ifdef HAS_ALPN
+  unsigned char protocols[128];
+#endif
 
   DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
 
   /* Make funny stuff to get random input */
   Curl_ossl_seed(data);
 
+  data->set.ssl.certverifyresult = !X509_V_OK;
+
   /* check to see if we've been told to use an explicit SSL/TLS version */
 
   switch(data->set.ssl.version) {
@@ -1649,7 +1701,33 @@ ossl_connect_step1(struct connectdata *conn,
   SSL_CTX_set_options(connssl->ctx, ctx_options);
 
 #ifdef USE_NGHTTP2
-  SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn);
+  if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
+    if(data->set.ssl_enable_npn) {
+      SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb,
+          conn);
+    }
+
+#ifdef HAS_ALPN
+    if(data->set.ssl_enable_alpn) {
+      protocols[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
+      memcpy(&protocols[1], NGHTTP2_PROTO_VERSION_ID,
+          NGHTTP2_PROTO_VERSION_ID_LEN);
+
+      protocols[NGHTTP2_PROTO_VERSION_ID_LEN+1] = ALPN_HTTP_1_1_LENGTH;
+      memcpy(&protocols[NGHTTP2_PROTO_VERSION_ID_LEN+2], ALPN_HTTP_1_1,
+          ALPN_HTTP_1_1_LENGTH);
+
+      /* expects length prefixed preference ordered list of protocols in wire
+       * format
+       */
+      SSL_CTX_set_alpn_protos(connssl->ctx, protocols,
+          NGHTTP2_PROTO_VERSION_ID_LEN + ALPN_HTTP_1_1_LENGTH + 2);
+
+      infof(data, "ALPN, offering %s, %s\n", NGHTTP2_PROTO_VERSION_ID,
+            ALPN_HTTP_1_1);
+    }
+#endif
+  }
 #endif
 
   if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) {
@@ -1823,7 +1901,6 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
   struct SessionHandle *data = conn->data;
   int err;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
   DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
              || ssl_connect_2_reading == connssl->connecting_state
              || ssl_connect_2_writing == connssl->connecting_state);
@@ -1916,9 +1993,36 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
     connssl->connecting_state = ssl_connect_3;
 
     /* Informational message */
-    infof (data, "SSL connection using %s\n",
+    infof (data, "SSL connection using %s / %s\n",
+           get_ssl_version_txt(SSL_get_session(connssl->handle)),
            SSL_get_cipher(connssl->handle));
 
+#ifdef HAS_ALPN
+    /* Sets data and len to negotiated protocol, len is 0 if no protocol was
+     * negotiated
+     */
+    if(data->set.ssl_enable_alpn) {
+      const unsigned char* neg_protocol;
+      unsigned int len;
+      SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len);
+      if(len != 0) {
+        infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
+
+        if(len == NGHTTP2_PROTO_VERSION_ID_LEN &&
+           memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len) == 0) {
+             conn->negnpn = NPN_HTTP2;
+        }
+        else if(len == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1,
+            neg_protocol, ALPN_HTTP_1_1_LENGTH) == 0) {
+          conn->negnpn = NPN_HTTP1_1;
+        }
+      }
+      else {
+        infof(data, "ALPN, server did not agree to a protocol\n");
+      }
+    }
+#endif
+
     return CURLE_OK;
   }
 }
@@ -2022,7 +2126,7 @@ static int X509V3_ext(struct SessionHandle *data,
         sep=", ";
         j++; /* skip the newline */
       };
-      while((biomem->data[j] == ' ') && (j<(size_t)biomem->length))
+      while((j<(size_t)biomem->length) && (biomem->data[j] == ' '))
         j++;
       if(j<(size_t)biomem->length)
         ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
@@ -2064,8 +2168,6 @@ static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
 
   BIO_get_mem_ptr(bio_out, &biomem);
 
-  infof(data, "%s\n", biomem->data);
-
   Curl_ssl_push_certinfo_len(data, numcert,
                              "Cert", biomem->data, biomem->length);
 
@@ -2269,8 +2371,6 @@ static CURLcode servercert(struct connectdata *conn,
     /* we've been asked to gather certificate info! */
     (void)get_cert_chain(conn, connssl);
 
-  data->set.ssl.certverifyresult = !X509_V_OK;
-
   connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
   if(!connssl->server_cert) {
     if(strict)