Add SSL_early_get1_extensions_present()
authorBenjamin Kaduk <bkaduk@akamai.com>
Thu, 16 Mar 2017 22:17:16 +0000 (17:17 -0500)
committerMatt Caswell <matt@openssl.org>
Mon, 12 Jun 2017 08:31:47 +0000 (09:31 +0100)
It is an API to be used from the early callback that indicates what
extensions were present in the ClientHello, and in what order.
This can be used to eliminate unneeded calls to SSL_early_get0_ext()
(which itself scales linearly in the number of extensions supported
by the library).

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2976)

doc/man3/SSL_CTX_set_early_cb.pod
include/openssl/ssl.h
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/statem/extensions.c
util/libssl.num

index 771e4ca0a70a30460d9f21d8b6e52ecf0afc7bae..c2b4650a0636fae657dd4a50e14cfd11e1dca9d5 100644 (file)
@@ -2,7 +2,7 @@
 
 =head1 NAME
 
-SSL_CTX_set_early_cb, SSL_early_cb_fn, SSL_early_isv2, SSL_early_get0_legacy_version, SSL_early_get0_random, SSL_early_get0_session_id, SSL_early_get0_ciphers, SSL_early_get0_compression_methods, SSL_early_get0_ext - callback functions for early server-side ClientHello processing
+SSL_CTX_set_early_cb, SSL_early_cb_fn, SSL_early_isv2, SSL_early_get0_legacy_version, SSL_early_get0_random, SSL_early_get0_session_id, SSL_early_get0_ciphers, SSL_early_get0_compression_methods, SSL_early_get1_extensions_present, SSL_early_get0_ext - callback functions for early server-side ClientHello processing
 
 =head1 SYNOPSIS
 
@@ -14,6 +14,7 @@ SSL_CTX_set_early_cb, SSL_early_cb_fn, SSL_early_isv2, SSL_early_get0_legacy_ver
  size_t SSL_early_get0_session_id(SSL *s, const unsigned char **out);
  size_t SSL_early_get0_ciphers(SSL *s, const unsigned char **out);
  size_t SSL_early_get0_compression_methods(SSL *s, const unsigned char **out);
+ int SSL_early_get1_extensions_present(SSL *s, int **out, size_t *outlen);
  int SSL_early_get0_ext(SSL *s, int type, const unsigned char **out,
                         size_t *outlen);
 
@@ -53,6 +54,14 @@ from the ClientHello on a per-extension basis.  For the provided wire
 protocol extension type value, the extension value and length are returned
 in the output parameters (if present).
 
+SSL_early_get1_extensions_present() can be used prior to SSL_early_get0_ext(),
+to determine which extensions are present in the ClientHello before querying
+for them.  The B<out> and B<outlen> parameters are both required, and on
+success the caller must release the storage allocated for B<*out> using
+OPENSSL_free().  The contents of B<*out> is an array of integers holding the
+numerical value of the TLS extension types in the order they appear in the
+ClientHello.  B<*outlen> contains the number of elements in the array.
+
 =head1 NOTES
 
 The early callback provides a vast window of possibilities for application
@@ -88,6 +97,8 @@ assumed to be valid.
 SSL_early_get0_ext() returns 1 if the extension of type 'type' is present, and
 0 otherwise.
 
+SSL_early_get1_extensions_present() returns 1 on success and 0 on failure.
+
 =head1 SEE ALSO
 
 L<ssl(7)>, L<SSL_CTX_set_tlsext_servername_callback(3)>,
@@ -97,8 +108,8 @@ L<SSL_bytes_to_cipher_list>
 
 The SSL early callback, SSL_early_isv2(), SSL_early_get0_random(),
 SSL_early_get0_session_id(), SSL_early_get0_ciphers(),
-SSL_early_get0_compression_methods(), and SSL_early_get0_ext() were
-added in OpenSSL 1.1.1.
+SSL_early_get0_compression_methods(), SSL_early_get0_ext(), and
+SSL_early_get1_extensions_present() were added in OpenSSL 1.1.1.
 
 =head1 COPYRIGHT
 
index 0eb41c9574b36d6587eb29e4de183f5d97cd257d..2b8344956bc5ae28cbf157ce9c2092dda13e5ee0 100644 (file)
@@ -1682,6 +1682,7 @@ size_t SSL_early_get0_random(SSL *s, const unsigned char **out);
 size_t SSL_early_get0_session_id(SSL *s, const unsigned char **out);
 size_t SSL_early_get0_ciphers(SSL *s, const unsigned char **out);
 size_t SSL_early_get0_compression_methods(SSL *s, const unsigned char **out);
+int SSL_early_get1_extensions_present(SSL *s, int **out, size_t *outlen);
 int SSL_early_get0_ext(SSL *s, unsigned int type, const unsigned char **out,
                        size_t *outlen);
 
index e90c4b8732f711c327b3cbccf248d80e986ab013..068df4200dba7b2b1fe1ab6a5814ccf5ecbce659 100644 (file)
@@ -4598,6 +4598,38 @@ size_t SSL_early_get0_compression_methods(SSL *s, const unsigned char **out)
     return s->clienthello->compressions_len;
 }
 
+int SSL_early_get1_extensions_present(SSL *s, int **out, size_t *outlen)
+{
+    RAW_EXTENSION *ext;
+    int *present;
+    size_t num = 0, i;
+
+    if (s->clienthello == NULL || out == NULL || outlen == NULL)
+        return 0;
+    for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) {
+        ext = s->clienthello->pre_proc_exts + i;
+        if (ext->present)
+            num++;
+    }
+    present = OPENSSL_malloc(sizeof(*present) * num);
+    if (present == NULL)
+        return 0;
+    for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) {
+        ext = s->clienthello->pre_proc_exts + i;
+        if (ext->present) {
+            if (ext->received_order >= num)
+                goto err;
+            present[ext->received_order] = ext->type;
+        }
+    }
+    *out = present;
+    *outlen = num;
+    return 1;
+ err:
+    OPENSSL_free(present);
+    return 0;
+}
+
 int SSL_early_get0_ext(SSL *s, unsigned int type, const unsigned char **out,
                        size_t *outlen)
 {
index fe6119b2ff4cdf214c3003215895070b38747197..85944ecfe70d1a5917c3c250b22933e8a7f4b420 100644 (file)
@@ -668,6 +668,8 @@ typedef struct raw_extension_st {
     int parsed;
     /* The type of this extension, i.e. a TLSEXT_TYPE_* value */
     unsigned int type;
+    /* Track what order extensions are received in (0-based). */
+    size_t received_order;
 } RAW_EXTENSION;
 
 typedef struct {
index b4d85d958c5f1cb430a970c14631e01dc8d4c8a6..d40c34cd1c0b67f362235fa4353596b8e9b97720 100644 (file)
@@ -462,6 +462,7 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
         return 0;
     }
 
+    i = 0;
     while (PACKET_remaining(&extensions) > 0) {
         unsigned int type, idx;
         PACKET extension;
@@ -518,6 +519,7 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
             thisex->data = extension;
             thisex->present = 1;
             thisex->type = type;
+            thisex->received_order = i++;
         }
     }
 
index b4acb5db3574286bff4e85ca49bfe45005a2d816..4cf8227b73e9cd7b52a99b5ccdeffda949d7d8e1 100644 (file)
@@ -450,3 +450,4 @@ 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:
+SSL_early_get1_extensions_present       454    1_1_1   EXIST::FUNCTION: