Extend the SERVERINFO file format to include an extensions context
authorMatt Caswell <matt@openssl.org>
Mon, 10 Apr 2017 15:13:20 +0000 (16:13 +0100)
committerMatt Caswell <matt@openssl.org>
Wed, 3 May 2017 13:37:42 +0000 (14:37 +0100)
This enables us to know what messages the extensions are relevant for in
TLSv1.3. The new file format is not compatible with the previous one so
we call it SERVERINFOV2.

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3298)

include/openssl/ssl.h
ssl/ssl_err.c
ssl/ssl_rsa.c
util/libssl.num

index b1da6c5..0fbd742 100644 (file)
@@ -1451,9 +1451,17 @@ __owur int SSL_use_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d,
 __owur int SSL_use_certificate(SSL *ssl, X509 *x);
 __owur int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
 
+
+/* serverinfo file format versions */
+# define SERVERINFOV1   1
+# define SERVERINFOV2   2
+
 /* Set serverinfo data for the current active cert. */
 __owur int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
                            size_t serverinfo_length);
+__owur int SSL_CTX_use_serverinfo_ex(SSL_CTX *ctx, unsigned int version,
+                                     const unsigned char *serverinfo,
+                                     size_t serverinfo_length);
 __owur int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file);
 
 #ifndef OPENSSL_NO_RSA
@@ -2328,6 +2336,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1             178
 # define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE             179
 # define SSL_F_SSL_CTX_USE_SERVERINFO                     336
+# define SSL_F_SSL_CTX_USE_SERVERINFO_EX                  543
 # define SSL_F_SSL_CTX_USE_SERVERINFO_FILE                337
 # define SSL_F_SSL_DANE_DUP                               403
 # define SSL_F_SSL_DANE_ENABLE                            395
index 296ce0d..a845dae 100644 (file)
@@ -174,6 +174,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE),
      "SSL_CTX_use_RSAPrivateKey_file"},
     {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO), "SSL_CTX_use_serverinfo"},
+    {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO_EX), "SSL_CTX_use_serverinfo_ex"},
     {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO_FILE),
      "SSL_CTX_use_serverinfo_file"},
     {ERR_FUNC(SSL_F_SSL_DANE_DUP), "ssl_dane_dup"},
index 87be646..a6824b0 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <stdio.h>
 #include "ssl_locl.h"
+#include "packet_locl.h"
 #include <openssl/bio.h>
 #include <openssl/objects.h>
 #include <openssl/evp.h>
@@ -693,50 +694,43 @@ static int serverinfo_find_extension(const unsigned char *serverinfo,
                                      const unsigned char **extension_data,
                                      size_t *extension_length)
 {
+    PACKET pkt, data;
+
     *extension_data = NULL;
     *extension_length = 0;
     if (serverinfo == NULL || serverinfo_length == 0)
         return -1;
+
+    if (!PACKET_buf_init(&pkt, serverinfo, serverinfo_length))
+        return -1;
+
     for (;;) {
         unsigned int type = 0;
-        size_t len = 0;
+        unsigned long context = 0;
 
         /* end of serverinfo */
-        if (serverinfo_length == 0)
+        if (PACKET_remaining(&pkt) == 0)
             return 0;           /* Extension not found */
 
-        /* read 2-byte type field */
-        if (serverinfo_length < 2)
-            return -1;          /* Error */
-        type = (serverinfo[0] << 8) + serverinfo[1];
-        serverinfo += 2;
-        serverinfo_length -= 2;
-
-        /* read 2-byte len field */
-        if (serverinfo_length < 2)
-            return -1;          /* Error */
-        len = (serverinfo[0] << 8) + serverinfo[1];
-        serverinfo += 2;
-        serverinfo_length -= 2;
-
-        if (len > serverinfo_length)
-            return -1;          /* Error */
+        if (!PACKET_get_net_4(&pkt, &context)
+                || !PACKET_get_net_2(&pkt, &type)
+                || !PACKET_get_length_prefixed_2(&pkt, &data))
+            return -1;
 
         if (type == extension_type) {
-            *extension_data = serverinfo;
-            *extension_length = len;
+            *extension_data = PACKET_data(&data);
+            *extension_length = PACKET_remaining(&data);;
             return 1;           /* Success */
         }
-
-        serverinfo += len;
-        serverinfo_length -= len;
     }
     /* Unreachable */
 }
 
-static int serverinfo_srv_parse_cb(SSL *s, unsigned int ext_type,
-                                   const unsigned char *in,
-                                   size_t inlen, int *al, void *arg)
+static int serverinfoex_srv_parse_cb(SSL *s, unsigned int ext_type,
+                                     unsigned int context,
+                                     const unsigned char *in,
+                                     size_t inlen, X509 *x, size_t chainidx,
+                                     int *al, void *arg)
 {
 
     if (inlen != 0) {
@@ -747,9 +741,19 @@ static int serverinfo_srv_parse_cb(SSL *s, unsigned int ext_type,
     return 1;
 }
 
-static int serverinfo_srv_add_cb(SSL *s, unsigned int ext_type,
-                                 const unsigned char **out, size_t *outlen,
-                                 int *al, void *arg)
+static int serverinfo_srv_parse_cb(SSL *s, unsigned int ext_type,
+                                   const unsigned char *in,
+                                   size_t inlen, int *al, void *arg)
+{
+    return serverinfoex_srv_parse_cb(s, ext_type, 0, in, inlen, NULL, 0, al,
+                                     arg);
+}
+
+static int serverinfoex_srv_add_cb(SSL *s, unsigned int ext_type,
+                                   unsigned int context,
+                                   const unsigned char **out,
+                                   size_t *outlen, X509 *x, size_t chainidx,
+                                   int *al, void *arg)
 {
     const unsigned char *serverinfo = NULL;
     size_t serverinfo_length = 0;
@@ -772,81 +776,90 @@ static int serverinfo_srv_add_cb(SSL *s, unsigned int ext_type,
                                  * extension */
 }
 
+static int serverinfo_srv_add_cb(SSL *s, unsigned int ext_type,
+                                 const unsigned char **out, size_t *outlen,
+                                 int *al, void *arg)
+{
+    return serverinfoex_srv_add_cb(s, ext_type, 0, out, outlen, NULL, 0, al,
+                                   arg);
+}
+
 /*
  * With a NULL context, this function just checks that the serverinfo data
  * parses correctly.  With a non-NULL context, it registers callbacks for
  * the included extensions.
  */
-static int serverinfo_process_buffer(const unsigned char *serverinfo,
+static int serverinfo_process_buffer(unsigned int version,
+                                     const unsigned char *serverinfo,
                                      size_t serverinfo_length, SSL_CTX *ctx)
 {
+    PACKET pkt;
+
     if (serverinfo == NULL || serverinfo_length == 0)
         return 0;
-    for (;;) {
-        unsigned int ext_type = 0;
-        size_t len = 0;
-
-        /* end of serverinfo */
-        if (serverinfo_length == 0)
-            return 1;
 
-        /* read 2-byte type field */
-        if (serverinfo_length < 2)
-            return 0;
-        /* FIXME: check for types we understand explicitly? */
-
-        /* Register callbacks for extensions */
-        ext_type = (serverinfo[0] << 8) + serverinfo[1];
-        if (ctx != NULL
-                && custom_ext_find(&ctx->cert->custext, ENDPOINT_SERVER,
-                                   ext_type, NULL)
-                   == NULL
-                && !SSL_CTX_add_server_custom_ext(ctx, ext_type,
-                                                  serverinfo_srv_add_cb,
-                                                  NULL, NULL,
-                                                  serverinfo_srv_parse_cb,
-                                                  NULL))
-            return 0;
+    if (version != SERVERINFOV1 && version != SERVERINFOV2)
+        return 0;
 
-        serverinfo += 2;
-        serverinfo_length -= 2;
+    if (!PACKET_buf_init(&pkt, serverinfo, serverinfo_length))
+        return 0;
 
-        /* read 2-byte len field */
-        if (serverinfo_length < 2)
-            return 0;
-        len = (serverinfo[0] << 8) + serverinfo[1];
-        serverinfo += 2;
-        serverinfo_length -= 2;
+    while (PACKET_remaining(&pkt)) {
+        unsigned long context = 0;
+        unsigned int ext_type = 0;
+        PACKET data;
 
-        if (len > serverinfo_length)
+        if (!PACKET_get_net_4(&pkt, &context)
+                || !PACKET_get_net_2(&pkt, &ext_type)
+                || !PACKET_get_length_prefixed_2(&pkt, &data))
             return 0;
 
-        serverinfo += len;
-        serverinfo_length -= len;
+        if (ctx == NULL)
+            continue;
+
+        if (version == SERVERINFOV1) {
+            if (!SSL_CTX_add_server_custom_ext(ctx, ext_type,
+                                               serverinfo_srv_add_cb,
+                                               NULL, NULL,
+                                               serverinfo_srv_parse_cb,
+                                               NULL))
+                return 0;
+        } else {
+            if (!SSL_CTX_add_custom_ext(ctx, ext_type, context,
+                                        serverinfoex_srv_add_cb,
+                                        NULL, NULL,
+                                        serverinfoex_srv_parse_cb,
+                                        NULL))
+                return 0;
+        }
     }
+
+    return 1;
 }
 
-int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
-                           size_t serverinfo_length)
+int SSL_CTX_use_serverinfo_ex(SSL_CTX *ctx, unsigned int version,
+                              const unsigned char *serverinfo,
+                              size_t serverinfo_length)
 {
     unsigned char *new_serverinfo;
 
     if (ctx == NULL || serverinfo == NULL || serverinfo_length == 0) {
-        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, ERR_R_PASSED_NULL_PARAMETER);
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
-    if (!serverinfo_process_buffer(serverinfo, serverinfo_length, NULL)) {
-        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, SSL_R_INVALID_SERVERINFO_DATA);
+    if (!serverinfo_process_buffer(version, serverinfo, serverinfo_length,
+                                   NULL)) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, SSL_R_INVALID_SERVERINFO_DATA);
         return 0;
     }
     if (ctx->cert->key == NULL) {
-        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, ERR_R_INTERNAL_ERROR);
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, ERR_R_INTERNAL_ERROR);
         return 0;
     }
     new_serverinfo = OPENSSL_realloc(ctx->cert->key->serverinfo,
                                      serverinfo_length);
     if (new_serverinfo == NULL) {
-        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, ERR_R_MALLOC_FAILURE);
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, ERR_R_MALLOC_FAILURE);
         return 0;
     }
     ctx->cert->key->serverinfo = new_serverinfo;
@@ -857,13 +870,21 @@ int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
      * Now that the serverinfo is validated and stored, go ahead and
      * register callbacks.
      */
-    if (!serverinfo_process_buffer(serverinfo, serverinfo_length, ctx)) {
-        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, SSL_R_INVALID_SERVERINFO_DATA);
+    if (!serverinfo_process_buffer(version, serverinfo, serverinfo_length,
+                                   ctx)) {
+        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_EX, SSL_R_INVALID_SERVERINFO_DATA);
         return 0;
     }
     return 1;
 }
 
+int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
+                           size_t serverinfo_length)
+{
+    return SSL_CTX_use_serverinfo_ex(ctx, SERVERINFOV1, serverinfo,
+                                     serverinfo_length);
+}
+
 int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)
 {
     unsigned char *serverinfo = NULL;
@@ -873,10 +894,12 @@ int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)
     long extension_length = 0;
     char *name = NULL;
     char *header = NULL;
-    char namePrefix[] = "SERVERINFO FOR ";
+    char namePrefix1[] = "SERVERINFO FOR ";
+    char namePrefix2[] = "SERVERINFOV2 FOR ";
     int ret = 0;
     BIO *bin = NULL;
-    size_t num_extensions = 0;
+    size_t num_extensions = 0, contextoff = 0;
+    unsigned int version;
 
     if (ctx == NULL || file == NULL) {
         SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_PASSED_NULL_PARAMETER);
@@ -907,32 +930,72 @@ int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)
                 break;
         }
         /* Check that PEM name starts with "BEGIN SERVERINFO FOR " */
-        if (strlen(name) < strlen(namePrefix)) {
+        if (strlen(name) < strlen(namePrefix1)) {
             SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_PEM_NAME_TOO_SHORT);
             goto end;
         }
-        if (strncmp(name, namePrefix, strlen(namePrefix)) != 0) {
-            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
-                   SSL_R_PEM_NAME_BAD_PREFIX);
-            goto end;
+        if (strncmp(name, namePrefix1, strlen(namePrefix1)) == 0) {
+            version = SERVERINFOV1;
+        } else {
+            if (strlen(name) < strlen(namePrefix2)) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
+                       SSL_R_PEM_NAME_TOO_SHORT);
+                goto end;
+            }
+            if (strncmp(name, namePrefix2, strlen(namePrefix2)) != 0) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
+                       SSL_R_PEM_NAME_BAD_PREFIX);
+                goto end;
+            }
+            version = SERVERINFOV2;
         }
         /*
          * Check that the decoded PEM data is plausible (valid length field)
          */
-        if (extension_length < 4
-            || (extension[2] << 8) + extension[3] != extension_length - 4) {
-            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);
-            goto end;
+        if (version == SERVERINFOV1) {
+            /* 4 byte header: 2 bytes type, 2 bytes len */
+            if (extension_length < 4
+                    || (extension[2] << 8) + extension[3]
+                       != extension_length - 4) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);
+                goto end;
+            }
+            /*
+             * File does not have a context value so we must take account of
+             * this later.
+             */
+            contextoff = 4;
+        } else {
+            /* 8 byte header: 4 bytes context, 2 bytes type, 2 bytes len */
+            if (extension_length < 8
+                    || (extension[6] << 8) + extension[7]
+                       != extension_length - 8) {
+                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);
+                goto end;
+            }
         }
         /* Append the decoded extension to the serverinfo buffer */
-        tmp = OPENSSL_realloc(serverinfo, serverinfo_length + extension_length);
+        tmp = OPENSSL_realloc(serverinfo, serverinfo_length + extension_length
+                                          + contextoff);
         if (tmp == NULL) {
             SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_MALLOC_FAILURE);
             goto end;
         }
         serverinfo = tmp;
-        memcpy(serverinfo + serverinfo_length, extension, extension_length);
-        serverinfo_length += extension_length;
+        if (contextoff > 0) {
+            unsigned int synthcontext = SSL_EXT_CLIENT_HELLO
+                                        | SSL_EXT_TLS1_2_SERVER_HELLO;
+            unsigned char *sinfo = serverinfo + serverinfo_length;
+
+            /* We know this only uses the last 2 bytes */
+            sinfo[0] = 0;
+            sinfo[1] = 0;
+            sinfo[2] = (synthcontext >> 8) & 0xff;
+            sinfo[3] = synthcontext & 0xff;
+        }
+        memcpy(serverinfo + serverinfo_length + contextoff,
+               extension, extension_length);
+        serverinfo_length += extension_length + contextoff;
 
         OPENSSL_free(name);
         name = NULL;
@@ -942,7 +1005,8 @@ int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)
         extension = NULL;
     }
 
-    ret = SSL_CTX_use_serverinfo(ctx, serverinfo, serverinfo_length);
+    ret = SSL_CTX_use_serverinfo_ex(ctx, version, serverinfo,
+                                    serverinfo_length);
  end:
     /* SSL_CTX_use_serverinfo makes a local copy of the serverinfo. */
     OPENSSL_free(name);
index a17ebbc..b4acb5d 100644 (file)
@@ -449,3 +449,4 @@ SSL_get_record_padding_callback_arg     449 1_1_1   EXIST::FUNCTION:
 SSL_set_block_padding                   450    1_1_1   EXIST::FUNCTION:
 SSL_set_record_padding_callback_arg     451    1_1_1   EXIST::FUNCTION:
 SSL_CTX_set_record_padding_callback_arg 452    1_1_1   EXIST::FUNCTION:
+SSL_CTX_use_serverinfo_ex               453    1_1_1   EXIST::FUNCTION: