Parse custom extensions after SNI.
authorDr. Stephen Henson <steve@openssl.org>
Mon, 20 Oct 2014 16:17:52 +0000 (17:17 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 23 Oct 2014 13:45:30 +0000 (14:45 +0100)
Since SNI will typically switch the SSL_CTX structure to the one
corresponding to the appopriate server we need to parse custom
extensions using the switched SSL_CTX not the original one. This
is done by parsing custom extensions *after* SNI.
Reviewed-by: Emilia Käsper <emilia@openssl.org>
ssl/t1_lib.c

index 29864326972dde1a122ad09d5c3d8ffe80166c26..fb0b736d1c26ce53c661eb9cc8a1c193ed0ff912 100644 (file)
@@ -2424,17 +2424,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                                                              al))
                                return 0;
                         }
-               /* If this ClientHello extension was unhandled and this is 
-                * a nonresumed connection, check whether the extension is a 
-                * custom TLS Extension (has a custom_srv_ext_record), and if
-                * so call the callback and record the extension number so that
-                * an appropriate ServerHello may be later returned.
-                */
-               else if (!s->hit)
-                       {
-                       if (custom_ext_parse(s, 1, type, data, size, al) <= 0)
-                               return 0;
-                       }
 
                data+=size;
                }
@@ -2460,10 +2449,51 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
        return 1;
        }
 
+/*
+ * Parse any custom extensions found.  "data" is the start of the extension data
+ * and "limit" is the end of the record. TODO: add strict syntax checking.
+ */
+
+static int ssl_scan_clienthello_custom_tlsext(SSL *s, const unsigned char *data, const unsigned char *limit, int *al) 
+       {       
+       unsigned short type, size, len;
+       /* If resumed session or no custom extensions nothing to do */
+       if (s->hit || s->cert->srv_ext.meths_count == 0)
+               return 1;
+
+       if (data >= limit - 2)
+               return 1;
+       n2s(data, len);
+
+       if (data > limit - len) 
+               return 1;
+
+       while (data <= limit - 4)
+               {
+               n2s(data, type);
+               n2s(data, size);
+
+               if (data+size > limit)
+                       return 1;
+               if (custom_ext_parse(s, 1 /* server */, type, data, size, al) <= 0)
+                       return 0;
+
+               data+=size;
+               }
+
+       return 1;
+       }
+
 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n) 
        {
        int al = -1;
-       custom_ext_init(&s->cert->srv_ext);
+       unsigned char *ptmp = *p;
+       /*
+        * Internally supported extensions are parsed first so SNI can be handled
+        * before custom extensions. An application processing SNI will typically
+        * switch the parent context using SSL_set_SSL_CTX and custom extensions
+        * need to be handled by the new SSL_CTX structure.
+        */
        if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0) 
                {
                ssl3_send_alert(s,SSL3_AL_FATAL,al); 
@@ -2475,6 +2505,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,SSL_R_CLIENTHELLO_TLSEXT);
                return 0;
                }
+
+       custom_ext_init(&s->cert->srv_ext);
+       if (ssl_scan_clienthello_custom_tlsext(s, ptmp, d + n, &al) <= 0) 
+               {
+               ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+               return 0;
+               }
+
        return 1;
 }