Merge remote-tracking branch 'agl/1.0.2alpn' into agl-alpn
authorBen Laurie <ben@links.org>
Tue, 1 Oct 2013 11:20:02 +0000 (12:20 +0100)
committerBen Laurie <ben@links.org>
Tue, 1 Oct 2013 11:20:02 +0000 (12:20 +0100)
Conflicts:
ssl/ssl3.h
ssl/t1_lib.c

1  2 
apps/s_client.c
apps/s_server.c
ssl/s3_lib.c
ssl/ssl.h
ssl/ssl3.h
ssl/ssl_lib.c
ssl/t1_lib.c

diff --cc apps/s_client.c
Simple merge
diff --cc apps/s_server.c
Simple merge
diff --cc ssl/s3_lib.c
Simple merge
diff --cc ssl/ssl.h
Simple merge
diff --cc ssl/ssl3.h
index d64ad8e057ff91ba07d605c7602741f322eecdb6,05317005dec9a36405ad869d806d3ac06c14be98..57b568a4776d25fb4f4a5c21ef3664f458635dcc
@@@ -583,14 -581,16 +583,23 @@@ typedef struct ssl3_state_s
        unsigned short *tlsext_custom_types;
        size_t tlsext_custom_types_count; /* how many tlsext_custom_types */
  
- #endif /* !OPENSSL_NO_TLSEXT */
 +#ifndef OPENSSL_NO_EC
 +      /* This is set to true if we believe that this is a version of Safari
 +       * running on OS X 10.6 or newer. We wish to know this because Safari
 +       * on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */
 +      char is_probably_safari;
 +#endif /* !OPENSSL_NO_EC */
 +
+       /* ALPN information
+        * (we are in the process of transitioning from NPN to ALPN.) */
+       /* In a server these point to the selected ALPN protocol after the
+        * ClientHello has been processed. In a client these contain the
+        * protocol that the server selected once the ServerHello has been
+        * processed. */
+       unsigned char *alpn_selected;
+       unsigned alpn_selected_len;
+ #endif        /* OPENSSL_NO_TLSEXT */
        } SSL3_STATE;
  
  #endif
diff --cc ssl/ssl_lib.c
Simple merge
diff --cc ssl/t1_lib.c
index b3c7cb5df16ae0426143a8ab22349d4e8728c76c,41010ee64795d0535631980f4c81c7635d92f2ae..b91afc8f3a4487179281caa27c4e0a97fe1331d8
@@@ -1802,88 -1787,75 +1829,157 @@@ unsigned char *ssl_add_serverhello_tlse
        return ret;
        }
  
- #endif /* !OPENSSL_NO_EC */
 +#ifndef OPENSSL_NO_EC
 +/* ssl_check_for_safari attempts to fingerprint Safari using OS X
 + * SecureTransport using the TLS extension block in |d|, of length |n|.
 + * Safari, since 10.6, sends exactly these extensions, in this order:
 + *   SNI,
 + *   elliptic_curves
 + *   ec_point_formats
 + *
 + * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
 + * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
 + * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
 + * 10.8..10.8.3 (which don't work).
 + */
 +static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) {
 +      unsigned short type, size;
 +      static const unsigned char kSafariExtensionsBlock[] = {
 +              0x00, 0x0a,  /* elliptic_curves extension */
 +              0x00, 0x08,  /* 8 bytes */
 +              0x00, 0x06,  /* 6 bytes of curve ids */
 +              0x00, 0x17,  /* P-256 */
 +              0x00, 0x18,  /* P-384 */
 +              0x00, 0x19,  /* P-521 */
 +
 +              0x00, 0x0b,  /* ec_point_formats */
 +              0x00, 0x02,  /* 2 bytes */
 +              0x01,        /* 1 point format */
 +              0x00,        /* uncompressed */
 +      };
 +
 +      /* The following is only present in TLS 1.2 */
 +      static const unsigned char kSafariTLS12ExtensionsBlock[] = {
 +              0x00, 0x0d,  /* signature_algorithms */
 +              0x00, 0x0c,  /* 12 bytes */
 +              0x00, 0x0a,  /* 10 bytes */
 +              0x05, 0x01,  /* SHA-384/RSA */
 +              0x04, 0x01,  /* SHA-256/RSA */
 +              0x02, 0x01,  /* SHA-1/RSA */
 +              0x04, 0x03,  /* SHA-256/ECDSA */
 +              0x02, 0x03,  /* SHA-1/ECDSA */
 +      };
 +
 +      if (data >= (d+n-2))
 +              return;
 +      data += 2;
 +
 +      if (data > (d+n-4))
 +              return;
 +      n2s(data,type);
 +      n2s(data,size);
 +
 +      if (type != TLSEXT_TYPE_server_name)
 +              return;
 +
 +      if (data+size > d+n)
 +              return;
 +      data += size;
 +
 +      if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
 +              {
 +              const size_t len1 = sizeof(kSafariExtensionsBlock);
 +              const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
 +
 +              if (data + len1 + len2 != d+n)
 +                      return;
 +              if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
 +                      return;
 +              if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
 +                      return;
 +              }
 +      else
 +              {
 +              const size_t len = sizeof(kSafariExtensionsBlock);
 +
 +              if (data + len != d+n)
 +                      return;
 +              if (memcmp(data, kSafariExtensionsBlock, len) != 0)
 +                      return;
 +              }
 +
 +      s->s3->is_probably_safari = 1;
 +}
++
+ /* tls1_alpn_handle_client_hello is called to process the ALPN extension in a
+  * ClientHello.
+  *   data: the contents of the extension, not including the type and length.
+  *   data_len: the number of bytes in |data|
+  *   al: a pointer to the alert value to send in the event of a non-zero
+  *       return.
+  *
+  *   returns: 0 on success. */
+ static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data,
+                                        unsigned data_len, int *al)
+       {
+       unsigned i;
+       unsigned proto_len;
+       const unsigned char *selected;
+       unsigned char selected_len;
+       int r;
+       if (s->ctx->alpn_select_cb == NULL)
+               return 0;
+       if (data_len < 2)
+               goto parse_error;
+       /* data should contain a uint16 length followed by a series of 8-bit,
+        * length-prefixed strings. */
+       i = ((unsigned) data[0]) << 8 |
+           ((unsigned) data[1]);
+       data_len -= 2;
+       data += 2;
+       if (data_len != i)
+               goto parse_error;
+       if (data_len < 2)
+               goto parse_error;
+       for (i = 0; i < data_len;)
+               {
+               proto_len = data[i];
+               i++;
+               if (proto_len == 0)
+                       goto parse_error;
+               if (i + proto_len < i || i + proto_len > data_len)
+                       goto parse_error;
+               i += proto_len;
+               }
+       r = s->ctx->alpn_select_cb(s, &selected, &selected_len, data, data_len,
+                                  s->ctx->alpn_select_cb_arg);
+       if (r == SSL_TLSEXT_ERR_OK) {
+               if (s->s3->alpn_selected)
+                       OPENSSL_free(s->s3->alpn_selected);
+               s->s3->alpn_selected = OPENSSL_malloc(selected_len);
+               if (!s->s3->alpn_selected)
+                       {
+                       *al = SSL_AD_INTERNAL_ERROR;
+                       return -1;
+                       }
+               memcpy(s->s3->alpn_selected, selected, selected_len);
+               s->s3->alpn_selected_len = selected_len;
+       }
+       return 0;
+ parse_error:
+       *al = SSL_AD_DECODE_ERROR;
+       return -1;
+       }
  
  static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) 
        {       
        s->s3->next_proto_neg_seen = 0;
  #endif
  
 +      /* Clear observed custom extensions */
 +      s->s3->tlsext_custom_types_count = 0;
 +      if (s->s3->tlsext_custom_types != NULL)
 +              {
 +              OPENSSL_free(s->s3->tlsext_custom_types);
 +              s->s3->tlsext_custom_types = NULL;
 +              }               
 +
+       if (s->s3->alpn_selected)
+               {
+               OPENSSL_free(s->s3->alpn_selected);
+               s->s3->alpn_selected = NULL;
+               }
  #ifndef OPENSSL_NO_HEARTBEATS
        s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
                               SSL_TLSEXT_HB_DONT_SEND_REQUESTS);