[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Wed May 17 14:32:38 UTC 2017


The branch master has been updated
       via  355a0d10a9a736202d3dbc41ce2218acb46a30ca (commit)
       via  56c2a6d78354b395dfd0c535debbe063d71b30ab (commit)
       via  b186a592833ea4efd8e18d053955abde179e1b3d (commit)
      from  7a94f5b0f7c878b1056a08f659ce23aa97bfa3ad (commit)


- Log -----------------------------------------------------------------
commit 355a0d10a9a736202d3dbc41ce2218acb46a30ca
Author: Matt Caswell <matt at openssl.org>
Date:   Wed May 17 10:31:46 2017 +0100

    Add a new unsolicited extension error code and add enum tag
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3418)

commit 56c2a6d78354b395dfd0c535debbe063d71b30ab
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 9 16:42:01 2017 +0100

    Add tests for unsolicited extensions
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3418)

commit b186a592833ea4efd8e18d053955abde179e1b3d
Author: Matt Caswell <matt at openssl.org>
Date:   Tue May 9 13:44:25 2017 +0100

    Fail if we receive a response to an extension that we didn't request
    
    We already did this on an ad-hoc per extension basis (for some extensions).
    This centralises it and makes sure we do it for all extensions.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3418)

-----------------------------------------------------------------------

Summary of changes:
 include/openssl/ssl.h               |   1 +
 ssl/ssl_err.c                       |   1 +
 ssl/ssl_locl.h                      |  64 ++++----
 ssl/statem/extensions.c             |  74 ++++++---
 ssl/statem/extensions_clnt.c        | 295 +++++++++++++++++++-----------------
 ssl/statem/extensions_srvr.c        | 201 ++++++++++++------------
 ssl/statem/statem_lib.c             |   3 +
 ssl/statem/statem_locl.h            | 168 +++++++++++---------
 test/recipes/70-test_sslextension.t |  70 ++++++++-
 9 files changed, 520 insertions(+), 357 deletions(-)

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 5e32845..20ec1e5 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2829,6 +2829,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_UNKNOWN_SSL_VERSION                        254
 # define SSL_R_UNKNOWN_STATE                              255
 # define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED       338
+# define SSL_R_UNSOLICITED_EXTENSION                      217
 # define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM          257
 # define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE                 315
 # define SSL_R_UNSUPPORTED_PROTOCOL                       258
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 62d7d76..f7de9f6 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -843,6 +843,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_UNKNOWN_STATE), "unknown state"},
     {ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),
      "unsafe legacy renegotiation disabled"},
+    {ERR_REASON(SSL_R_UNSOLICITED_EXTENSION), "unsolicited extension"},
     {ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),
      "unsupported compression algorithm"},
     {ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 0644c7f..f113854 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -686,6 +686,38 @@ typedef struct {
     RAW_EXTENSION *pre_proc_exts;
 } CLIENTHELLO_MSG;
 
+/*
+ * Extension index values NOTE: Any updates to these defines should be mirrored
+ * with equivalent updates to ext_defs in extensions.c
+ */
+typedef enum tlsext_index_en {
+    TLSEXT_IDX_renegotiate,
+    TLSEXT_IDX_server_name,
+    TLSEXT_IDX_srp,
+    TLSEXT_IDX_ec_point_formats,
+    TLSEXT_IDX_supported_groups,
+    TLSEXT_IDX_session_ticket,
+    TLSEXT_IDX_signature_algorithms,
+    TLSEXT_IDX_status_request,
+    TLSEXT_IDX_next_proto_neg,
+    TLSEXT_IDX_application_layer_protocol_negotiation,
+    TLSEXT_IDX_use_srtp,
+    TLSEXT_IDX_encrypt_then_mac,
+    TLSEXT_IDX_signed_certificate_timestamp,
+    TLSEXT_IDX_extended_master_secret,
+    TLSEXT_IDX_supported_versions,
+    TLSEXT_IDX_psk_kex_modes,
+    TLSEXT_IDX_key_share,
+    TLSEXT_IDX_cookie,
+    TLSEXT_IDX_cryptopro_bug,
+    TLSEXT_IDX_early_data,
+    TLSEXT_IDX_certificate_authorities,
+    TLSEXT_IDX_padding,
+    TLSEXT_IDX_psk,
+    /* Dummy index - must always be the last entry */
+    TLSEXT_IDX_num_builtins
+} TLSEXT_INDEX;
+
 DEFINE_LHASH_OF(SSL_SESSION);
 /* Needed in ssl_cert.c */
 DEFINE_LHASH_OF(X509_NAME);
@@ -1153,6 +1185,8 @@ struct ssl_st {
     size_t max_pipelines;
 
     struct {
+        /* Built-in extension flags */
+        uint8_t extflags[TLSEXT_IDX_num_builtins];
         /* TLS extension debug callback */
         void (*debug_cb)(SSL *s, int client_server, int type,
                          const unsigned char *data, int len, void *arg);
@@ -1814,36 +1848,6 @@ typedef enum downgrade_en {
 } DOWNGRADE;
 
 /*
- * Extension index values NOTE: Any updates to these defines should be mirrored
- * with equivalent updates to ext_defs in extensions.c
- */
-typedef enum tlsext_index_en {
-    TLSEXT_IDX_renegotiate,
-    TLSEXT_IDX_server_name,
-    TLSEXT_IDX_srp,
-    TLSEXT_IDX_ec_point_formats,
-    TLSEXT_IDX_supported_groups,
-    TLSEXT_IDX_session_ticket,
-    TLSEXT_IDX_signature_algorithms,
-    TLSEXT_IDX_status_request,
-    TLSEXT_IDX_next_proto_neg,
-    TLSEXT_IDX_application_layer_protocol_negotiation,
-    TLSEXT_IDX_use_srtp,
-    TLSEXT_IDX_encrypt_then_mac,
-    TLSEXT_IDX_signed_certificate_timestamp,
-    TLSEXT_IDX_extended_master_secret,
-    TLSEXT_IDX_supported_versions,
-    TLSEXT_IDX_psk_kex_modes,
-    TLSEXT_IDX_key_share,
-    TLSEXT_IDX_cookie,
-    TLSEXT_IDX_cryptopro_bug,
-    TLSEXT_IDX_early_data,
-    TLSEXT_IDX_certificate_authorities,
-    TLSEXT_IDX_padding,
-    TLSEXT_IDX_psk
-} TLSEXT_INDEX;
-
-/*
  * Dummy status type for the status_type extension. Indicates no status type
  * set
  */
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index 578ca13..fd76337 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -31,9 +31,11 @@ static int init_alpn(SSL *s, unsigned int context);
 static int final_alpn(SSL *s, unsigned int context, int sent, int *al);
 static int init_sig_algs(SSL *s, unsigned int context);
 static int init_certificate_authorities(SSL *s, unsigned int context);
-static int tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
-                                                 unsigned int context, X509 *x,
-                                                 size_t chainidx, int *al);
+static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+                                                        unsigned int context,
+                                                        X509 *x,
+                                                        size_t chainidx,
+                                                        int *al);
 static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
                                              unsigned int context, X509 *x,
                                              size_t chainidx, int *al);
@@ -74,11 +76,11 @@ typedef struct extensions_definition_st {
     int (*parse_stoc)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
                       size_t chainidx, int *al);
     /* Construct extension sent from server to client */
-    int (*construct_stoc)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                          size_t chainidx, int *al);
+    EXT_RETURN (*construct_stoc)(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al);
     /* Construct extension sent from client to server */
-    int (*construct_ctos)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                          size_t chainidx, int *al);
+    EXT_RETURN (*construct_ctos)(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al);
     /*
      * Finalise extension after parsing. Always called where an extensions was
      * initialised even if the extension was not present. |sent| is set to 1 if
@@ -461,7 +463,7 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
     }
 
     while (PACKET_remaining(&extensions) > 0) {
-        unsigned int type;
+        unsigned int type, idx;
         PACKET extension;
         RAW_EXTENSION *thisex;
 
@@ -485,6 +487,33 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
             *al = SSL_AD_ILLEGAL_PARAMETER;
             goto err;
         }
+        idx = thisex - raw_extensions;
+        /*-
+         * Check that we requested this extension (if appropriate). Requests can
+         * be sent in the ClientHello and CertificateRequest. Unsolicited
+         * extensions can be sent in the NewSessionTicket. We only do this for
+         * the built-in extensions. Custom extensions have a different but
+         * similar check elsewhere.
+         * Special cases:
+         * - The HRR cookie extension is unsolicited
+         * - The renegotiate extension is unsolicited (the client signals
+         *   support via an SCSV)
+         * - The signed_certificate_timestamp extension can be provided by a
+         * custom extension or by the built-in version. We let the extension
+         * itself handle unsolicited response checks.
+         */
+        if (idx < OSSL_NELEM(ext_defs)
+                && (context & (SSL_EXT_CLIENT_HELLO
+                               | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+                               | SSL_EXT_TLS1_3_NEW_SESSION_TICKET)) == 0
+                && type != TLSEXT_TYPE_cookie
+                && type != TLSEXT_TYPE_renegotiate
+                && type != TLSEXT_TYPE_signed_certificate_timestamp
+                && (s->ext.extflags[idx] & SSL_EXT_FLAG_SENT) == 0) {
+            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_UNSOLICITED_EXTENSION);
+            *al = SSL_AD_UNSUPPORTED_EXTENSION;
+            goto err;
+        }
         if (thisex != NULL) {
             thisex->data = extension;
             thisex->present = 1;
@@ -699,8 +728,9 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
     }
 
     for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
-        int (*construct)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                         size_t chainidx, int *al);
+        EXT_RETURN (*construct)(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx, int *al);
+        EXT_RETURN ret;
 
         /* Skip if not relevant for our context */
         if (!should_add_extension(s, thisexd->context, context, max_version))
@@ -712,8 +742,14 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
         if (construct == NULL)
             continue;
 
-        if (!construct(s, pkt, context, x, chainidx, &tmpal))
+        ret = construct(s, pkt, context, x, chainidx, &tmpal);
+        if (ret == EXT_RETURN_FAIL)
             goto err;
+        if (ret == EXT_RETURN_SENT
+                && (context & (SSL_EXT_CLIENT_HELLO
+                               | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+                               | SSL_EXT_TLS1_3_NEW_SESSION_TICKET)) != 0)
+            s->ext.extflags[i] |= SSL_EXT_FLAG_SENT;
     }
 
     if (!WPACKET_close(pkt)) {
@@ -997,14 +1033,16 @@ static int init_certificate_authorities(SSL *s, unsigned int context)
     return 1;
 }
 
-static int tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
-                                                 unsigned int context, X509 *x,
-                                                 size_t chainidx, int *al)
+static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+                                                        unsigned int context,
+                                                        X509 *x,
+                                                        size_t chainidx,
+                                                        int *al)
 {
     const STACK_OF(X509_NAME) *ca_sk = SSL_get0_CA_list(s);
 
     if (ca_sk == NULL || sk_X509_NAME_num(ca_sk) == 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_certificate_authorities)
         || !WPACKET_start_sub_packet_u16(pkt)
@@ -1012,10 +1050,10 @@ static int tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
         || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_AUTHORITIES,
                ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 2d7bcd3..f2626a3 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -12,12 +12,13 @@
 #include "../ssl_locl.h"
 #include "statem_locl.h"
 
-int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
-                                   X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx, int *al)
 {
     /* Add RI if renegotiating */
     if (!s->renegotiate)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
             || !WPACKET_start_sub_packet_u16(pkt)
@@ -25,17 +26,18 @@ int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
                                s->s3->previous_client_finished_len)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, unsigned int context,
-                                   X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_server_name(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx, int *al)
 {
     if (s->ext.hostname == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /* Add TLS extension servername to the Client Hello message */
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
@@ -49,19 +51,19 @@ int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_close(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #ifndef OPENSSL_NO_SRP
-int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     /* Add SRP username if there is one */
     if (s->srp_ctx.login == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_srp)
                /* Sub-packet for SRP extension */
@@ -74,10 +76,10 @@ int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
             || !WPACKET_close(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SRP, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
@@ -108,14 +110,15 @@ static int use_ecc(SSL *s)
     return 0;
 }
 
-int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
-                                     X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al)
 {
     const unsigned char *pformats;
     size_t num_formats;
 
     if (!use_ecc(s))
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /* Add TLS extension ECPointFormats to the ClientHello message */
     tls1_get_formatlist(s, &pformats, &num_formats);
@@ -126,21 +129,21 @@ int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_sub_memcpy_u8(pkt, pformats, num_formats)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
-                                        unsigned int context, X509 *x,
-                                        size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx, int *al)
 {
     const unsigned char *pcurves = NULL, *pcurvestmp;
     size_t num_curves = 0, i;
 
     if (!use_ecc(s))
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /*
      * Add TLS extension supported_groups to the ClientHello message
@@ -149,7 +152,7 @@ int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
     if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
                ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
     pcurvestmp = pcurves;
 
@@ -159,7 +162,7 @@ int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
             || !WPACKET_start_sub_packet_u16(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
                ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
     /* Copy curve ID if supported */
     for (i = 0; i < num_curves; i++, pcurvestmp += 2) {
@@ -168,28 +171,28 @@ int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
                 || !WPACKET_put_bytes_u8(pkt, pcurvestmp[1])) {
                     SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
                            ERR_R_INTERNAL_ERROR);
-                    return 0;
+                    return EXT_RETURN_FAIL;
                 }
         }
     }
     if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
                ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
-int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al)
 {
     size_t ticklen;
 
     if (!tls_use_ticket(s))
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!s->new_session && s->session != NULL
             && s->session->ext.tick != NULL
@@ -202,7 +205,7 @@ int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
         if (s->session->ext.tick == NULL) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET,
                    ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
         memcpy(s->session->ext.tick,
                s->ext.session_ticket->data, ticklen);
@@ -213,25 +216,26 @@ int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
 
     if (ticklen == 0 && s->ext.session_ticket != NULL &&
             s->ext.session_ticket->data == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
             || !WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick, ticklen)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, unsigned int context,
-                                X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx, int *al)
 {
     size_t salglen;
     const uint16_t *salg;
 
     if (!SSL_CLIENT_USE_SIGALGS(s))
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     salglen = tls12_get_psigalgs(s, 1, &salg);
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signature_algorithms)
@@ -243,25 +247,25 @@ int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_close(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SIG_ALGS, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al)
 {
     int i;
 
     /* This extension isn't defined for client Certificates */
     if (x != NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (s->ext.status_type != TLSEXT_STATUSTYPE_ocsp)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
                /* Sub-packet for status request extension */
@@ -270,7 +274,7 @@ int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
                /* Sub-packet for the ids */
             || !WPACKET_start_sub_packet_u16(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
     for (i = 0; i < sk_OCSP_RESPID_num(s->ext.ocsp.ids); i++) {
         unsigned char *idbytes;
@@ -283,13 +287,13 @@ int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
                 || i2d_OCSP_RESPID(id, &idbytes) != idlen) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
                    ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
     }
     if (!WPACKET_close(pkt)
             || !WPACKET_start_sub_packet_u16(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
     if (s->ext.ocsp.exts) {
         unsigned char *extbytes;
@@ -298,31 +302,31 @@ int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
         if (extlen < 0) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
                    ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
         if (!WPACKET_allocate_bytes(pkt, extlen, &extbytes)
                 || i2d_X509_EXTENSIONS(s->ext.ocsp.exts, &extbytes)
                    != extlen) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST,
                    ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
        }
     }
     if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (s->ctx->ext.npn_select_cb == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /*
      * The client advertises an empty extension to indicate its support
@@ -331,20 +335,20 @@ int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_NPN, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
-int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                            size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al)
 {
     s->s3->alpn_sent = 0;
 
     if (s->ext.alpn == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt,
                 TLSEXT_TYPE_application_layer_protocol_negotiation)
@@ -353,23 +357,24 @@ int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
             || !WPACKET_sub_memcpy_u16(pkt, s->ext.alpn, s->ext.alpn_len)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ALPN, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
     s->s3->alpn_sent = 1;
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
-                                X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx, int *al)
 {
     STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = SSL_get_srtp_profiles(s);
     int i, end;
 
     if (clnt == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
                /* Sub-packet for SRTP extension */
@@ -377,7 +382,7 @@ int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
                /* Sub-packet for the protection profile list */
             || !WPACKET_start_sub_packet_u16(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     end = sk_SRTP_PROTECTION_PROFILE_num(clnt);
@@ -387,7 +392,7 @@ int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
 
         if (prof == NULL || !WPACKET_put_bytes_u16(pkt, prof->id)) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP, ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
     }
     if (!WPACKET_close(pkt)
@@ -395,64 +400,64 @@ int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_put_bytes_u8(pkt, 0)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
-int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ETM, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #ifndef OPENSSL_NO_CT
-int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (s->ct_validation_callback == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /* Not defined for client Certificates */
     if (x != NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_signed_certificate_timestamp)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SCT, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
-int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EMS, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
-                                          unsigned int context, X509 *x,
-                                          size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
+                                                 unsigned int context, X509 *x,
+                                                 size_t chainidx, int *al)
 {
     int currv, min_version, max_version, reason;
 
@@ -461,13 +466,13 @@ int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
             || !WPACKET_start_sub_packet_u8(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
                ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     reason = ssl_get_min_max_version(s, &min_version, &max_version);
     if (reason != 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, reason);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     /*
@@ -481,29 +486,30 @@ int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
             if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)) {
                 SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
                        ERR_R_INTERNAL_ERROR);
-                return 0;
+                return EXT_RETURN_FAIL;
             }
         } else if (!WPACKET_put_bytes_u16(pkt, currv)) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
                    ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
     }
     if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS,
                ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 /*
  * Construct a psk_kex_modes extension. We only have two modes we know about
  * at this stage, so we send both.
  */
-int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, unsigned int context,
-                                     X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     /*
@@ -518,13 +524,13 @@ int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_close(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_KE | TLSEXT_KEX_MODE_FLAG_KE_DHE;
 #endif
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #ifndef OPENSSL_NO_TLS1_3
@@ -538,7 +544,7 @@ static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
         assert(s->hello_retry_request);
         if (!s->hello_retry_request) {
             SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
         /*
          * Could happen if we got an HRR that wasn't requesting a new key_share
@@ -548,7 +554,7 @@ static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
         key_share_key = ssl_generate_pkey_curve(curve_id);
         if (key_share_key == NULL) {
             SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EVP_LIB);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
     }
 
@@ -576,17 +582,18 @@ static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
     s->s3->group_id = curve_id;
     OPENSSL_free(encoded_point);
 
-    return 1;
+    return EXT_RETURN_SENT;
  err:
     if (s->s3->tmp.pkey == NULL)
         EVP_PKEY_free(key_share_key);
     OPENSSL_free(encoded_point);
-    return 0;
+    return EXT_RETURN_FAIL;
 }
 #endif
 
-int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
-                                 X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     size_t i, num_curves = 0;
@@ -600,12 +607,12 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
                /* KeyShare list sub-packet */
             || !WPACKET_start_sub_packet_u16(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     /*
@@ -627,29 +634,29 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
 
     if (curve_id == 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     if (!add_key_share(s, pkt, curve_id))
-        return 0;
+        return EXT_RETURN_FAIL;
 
     if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 #endif
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
-                              X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al)
 {
-    int ret = 0;
+    EXT_RETURN ret = EXT_RETURN_FAIL;
 
     /* Should only be set if we've had an HRR */
     if (s->ext.tls13_cookie_len == 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_cookie)
                /* Extension data sub-packet */
@@ -661,7 +668,7 @@ int tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
         goto end;
     }
 
-    ret = 1;
+    ret = EXT_RETURN_SENT;
  end:
     OPENSSL_free(s->ext.tls13_cookie);
     s->ext.tls13_cookie = NULL;
@@ -670,13 +677,14 @@ int tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
     return ret;
 }
 
-int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context,
-                                  X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx, int *al)
 {
     if (s->early_data_state != SSL_EARLY_DATA_CONNECTING
             || s->session->ext.max_early_data == 0) {
         s->max_early_data = 0;
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
     s->max_early_data = s->session->ext.max_early_data;
 
@@ -684,7 +692,7 @@ int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_start_sub_packet_u16(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     /*
@@ -693,7 +701,7 @@ int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context,
      */
     s->ext.early_data = SSL_EARLY_DATA_REJECTED;
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #define F5_WORKAROUND_MIN_MSG_LEN   0xff
@@ -713,14 +721,15 @@ int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context,
  */
 #define PSK_PRE_BINDER_OVERHEAD (2 + 2 + 2 + 2 + 4 + 2 + 1)
 
-int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, unsigned int context,
-                               X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
+                                      size_t chainidx, int *al)
 {
     unsigned char *padbytes;
     size_t hlen;
 
     if ((s->options & SSL_OP_TLSEXT_PADDING) == 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /*
      * Add padding to workaround bugs in F5 terminators. See RFC7685.
@@ -730,7 +739,7 @@ int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, unsigned int context,
      */
     if (!WPACKET_get_total_written(pkt, &hlen)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PADDING, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     /*
@@ -773,21 +782,21 @@ int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, unsigned int context,
         memset(padbytes, 0, hlen);
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 /*
  * Construct the pre_shared_key extension
  */
-int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     uint32_t now, agesec, agems;
     size_t hashsize, binderoffset, msglen;
     unsigned char *binder = NULL, *msgstart = NULL;
     const EVP_MD *md;
-    int ret = 0;
+    EXT_RETURN ret = EXT_RETURN_FAIL;
 
     s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY;
 
@@ -803,7 +812,7 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
      */
     if (s->session->ssl_version != TLS1_3_VERSION
             || s->session->ext.ticklen == 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (s->session->cipher == NULL) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
@@ -813,7 +822,7 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
     md = ssl_md(s->session->cipher->algorithm2);
     if (md == NULL) {
         /* Don't recognize this cipher so we can't use the session. Ignore it */
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
 
     if (s->hello_retry_request && md != ssl_handshake_md(s)) {
@@ -821,7 +830,7 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
          * Selected ciphersuite hash does not match the hash for the session so
          * we can't use it.
          */
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
 
     /*
@@ -836,7 +845,7 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
 
     if (s->session->ext.tick_lifetime_hint < agesec) {
         /* Ticket is too old. Ignore it. */
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
 
     /*
@@ -850,7 +859,7 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
          * Overflow. Shouldn't happen unless this is a *really* old session. If
          * so we just ignore it.
          */
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
 
     /*
@@ -894,7 +903,7 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
 
     s->session->ext.tick_identity = 0;
 
-    ret = 1;
+    ret = EXT_RETURN_SENT;
  err:
     return ret;
 #else
@@ -1100,6 +1109,20 @@ int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             }
         }
     } else {
+        ENDPOINT role = (context & SSL_EXT_TLS1_2_SERVER_HELLO) != 0
+                        ? ENDPOINT_CLIENT : ENDPOINT_BOTH;
+
+        /*
+         * If we didn't ask for it then there must be a custom extension,
+         * otherwise this is unsolicited.
+         */
+        if (custom_ext_find(&s->cert->custext, role,
+                            TLSEXT_TYPE_signed_certificate_timestamp,
+                            NULL) == NULL) {
+            *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+            return 0;
+        }
+
         if (custom_ext_parse(s, context,
                              TLSEXT_TYPE_signed_certificate_timestamp,
                              PACKET_data(pkt), PACKET_remaining(pkt),
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index f85477c..9cde695 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -810,11 +810,12 @@ err:
 /*
  * Add the server's renegotiation binding
  */
-int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
-                                   X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx, int *al)
 {
     if (!s->s3->send_connection_binding)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
             || !WPACKET_start_sub_packet_u16(pkt)
@@ -826,31 +827,33 @@ int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_close(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context,
-                                   X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx, int *al)
 {
     if (s->hit || s->servername_done != 1
             || s->session->ext.hostname == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #ifndef OPENSSL_NO_EC
-int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
-                                     X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al)
 {
     unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
     unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
@@ -860,7 +863,7 @@ int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
     size_t plistlen;
 
     if (!using_ecc)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     tls1_get_formatlist(s, &plist, &plistlen);
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
@@ -868,29 +871,29 @@ int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_sub_memcpy_u8(pkt, plist, plistlen)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
 #ifndef OPENSSL_NO_EC
-int tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
-                                        unsigned int context, X509 *x,
-                                        size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx, int *al)
 {
     const unsigned char *groups;
     size_t numgroups, i, first = 1;
 
     /* s->s3->group_id is non zero if we accepted a key_share */
     if (s->s3->group_id == 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /* Get our list of supported groups */
     if (!tls1_get_curvelist(s, 0, &groups, &numgroups) || numgroups == 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     /* Copy group ID if supported */
@@ -902,7 +905,7 @@ int tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
                  * so we don't need to add this extension
                  */
                 if (s->s3->group_id == GET_GROUP_ID(groups, 0))
-                    return 1;
+                    return EXT_RETURN_NOT_SENT;
 
                 /* Add extension header */
                 if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
@@ -911,7 +914,7 @@ int tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
                         || !WPACKET_start_sub_packet_u16(pkt)) {
                     SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
                            ERR_R_INTERNAL_ERROR);
-                    return 0;
+                    return EXT_RETURN_FAIL;
                 }
 
                 first = 0;
@@ -919,53 +922,53 @@ int tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
             if (!WPACKET_put_bytes_u16(pkt, GET_GROUP_ID(groups, 0))) {
                     SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS,
                            ERR_R_INTERNAL_ERROR);
-                    return 0;
+                    return EXT_RETURN_FAIL;
                 }
         }
     }
 
     if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_GROUPS, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
-int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al)
 {
     if (!s->ext.ticket_expected || !tls_use_ticket(s)) {
         s->ext.ticket_expected = 0;
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al)
 {
     if (!s->ext.status_expected)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (SSL_IS_TLS13(s) && chainidx != 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
             || !WPACKET_start_sub_packet_u16(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     /*
@@ -976,17 +979,17 @@ int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
     if ((SSL_IS_TLS13(s) && !tls_construct_cert_status_body(s, pkt))
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_STATUS_REQUEST, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al)
 {
     const unsigned char *npa;
     unsigned int npalen;
@@ -995,7 +998,7 @@ int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
 
     s->s3->npn_seen = 0;
     if (!npn_seen || s->ctx->ext.npn_advertised_cb == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     ret = s->ctx->ext.npn_advertised_cb(s, &npa, &npalen,
                                         s->ctx->ext.npn_advertised_cb_arg);
@@ -1004,20 +1007,20 @@ int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
                 || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
             SSLerr(SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG,
                    ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
         s->s3->npn_seen = 1;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
-int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                            size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al)
 {
     if (s->s3->alpn_selected == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt,
                 TLSEXT_TYPE_application_layer_protocol_negotiation)
@@ -1028,18 +1031,19 @@ int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
             || !WPACKET_close(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_ALPN, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
-                                X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx, int *al)
 {
     if (s->srtp_profile == NULL)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
             || !WPACKET_start_sub_packet_u16(pkt)
@@ -1048,18 +1052,18 @@ int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
             || !WPACKET_put_bytes_u8(pkt, 0)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_USE_SRTP, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 #endif
 
-int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (!s->ext.use_etm)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     /*
      * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
@@ -1070,35 +1074,36 @@ int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
         || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
         || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12) {
         s->ext.use_etm = 0;
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_ETM, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if ((s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EMS, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
-                                 X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     unsigned char *encodedPoint;
@@ -1114,32 +1119,32 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
                     || !WPACKET_close(pkt)) {
                 SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
                        ERR_R_INTERNAL_ERROR);
-                return 0;
+                return EXT_RETURN_FAIL;
             }
 
-            return 1;
+            return EXT_RETURN_SENT;
         }
 
         /* Must be resuming. */
         if (!s->hit || !tls13_generate_handshake_secret(s, NULL, 0)) {
             *al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
-        return 1;
+        return EXT_RETURN_NOT_SENT;
     }
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
             || !WPACKET_start_sub_packet_u16(pkt)
             || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     skey = ssl_generate_pkey(ckey);
     if (skey == NULL) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     /* Generate encoding of server key */
@@ -1147,7 +1152,7 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
     if (encoded_pt_len == 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_EC_LIB);
         EVP_PKEY_free(skey);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
     if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
@@ -1155,7 +1160,7 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
         EVP_PKEY_free(skey);
         OPENSSL_free(encodedPoint);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
     OPENSSL_free(encodedPoint);
 
@@ -1163,15 +1168,16 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
     s->s3->tmp.pkey = skey;
     if (ssl_derive(s, skey, ckey, 1) == 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 #endif
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, unsigned int context,
-                                     X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al)
 {
     const unsigned char cryptopro_ext[36] = {
         0xfd, 0xe8,         /* 65000 */
@@ -1185,60 +1191,61 @@ int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, unsigned int context,
     if (((s->s3->tmp.new_cipher->id & 0xFFFF) != 0x80
          && (s->s3->tmp.new_cipher->id & 0xFFFF) != 0x81)
             || (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG) == 0)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context,
-                                  X509 *x, size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx, int *al)
 {
     if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) {
         if (s->max_early_data == 0)
-            return 1;
+            return EXT_RETURN_NOT_SENT;
 
         if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
                 || !WPACKET_start_sub_packet_u16(pkt)
                 || !WPACKET_put_bytes_u32(pkt, s->max_early_data)
                 || !WPACKET_close(pkt)) {
             SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, ERR_R_INTERNAL_ERROR);
-            return 0;
+            return EXT_RETURN_FAIL;
         }
 
-        return 1;
+        return EXT_RETURN_SENT;
     }
 
     if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
             || !WPACKET_start_sub_packet_u16(pkt)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
 
-int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al)
+EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (!s->hit)
-        return 1;
+        return EXT_RETURN_NOT_SENT;
 
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk)
             || !WPACKET_start_sub_packet_u16(pkt)
             || !WPACKET_put_bytes_u16(pkt, s->session->ext.tick_identity)
             || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_STOC_PSK, ERR_R_INTERNAL_ERROR);
-        return 0;
+        return EXT_RETURN_FAIL;
     }
 
-    return 1;
+    return EXT_RETURN_SENT;
 }
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 5c00b0a..4a399ca 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -77,6 +77,9 @@ int tls_setup_handshake(SSL *s)
     if (!ssl3_init_finished_mac(s))
         return 0;
 
+    /* Reset any extension flags */
+    memset(s->ext.extflags, 0, sizeof(s->ext.extflags));
+
     if (s->server) {
         STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(s);
         int i, ver_min, ver_max, ok = 0;
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index 49a5ed5..673822a 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -156,6 +156,12 @@ MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt);
 
 /* Extension processing */
 
+typedef enum ext_return_en {
+    EXT_RETURN_FAIL,
+    EXT_RETURN_SENT,
+    EXT_RETURN_NOT_SENT
+} EXT_RETURN;
+
 __owur int extension_is_relevant(SSL *s, unsigned int extctx,
                                  unsigned int thisctx);
 __owur int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
@@ -223,113 +229,125 @@ int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
 int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
                        size_t chainidx, int *al);
 
-int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
-                                   X509 *x, size_t chainidx, int *al);
-int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context,
-                                   X509 *x, size_t chainidx, int *al);
-int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context,
-                                  X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
+                                          size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx, int *al);
 #ifndef OPENSSL_NO_EC
-int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
-                                     X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al);
 #endif
-int tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
-                                        unsigned int context, X509 *x,
-                                        size_t chainidx, int *al);
-int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al);
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al);
 #endif
-int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                            size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
                                 X509 *x, size_t chainidx, int *al);
 #endif
-int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
-int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
-int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
-                                 X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx, int *al);
 /*
  * Not in public headers as this is not an official extension. Only used when
  * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set.
  */
 #define TLSEXT_TYPE_cryptopro_bug      0xfde8
-int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, unsigned int context,
-                                     X509 *x, size_t chainidx, int *al);
-int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al);
+EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 
 /* Client Extension processing */
-int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
                                    X509 *x, size_t chainidx, int *al);
-int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, unsigned int context,
                                    X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRP
-int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+EXT_RETURN tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
                            size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_EC
-int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
-                                     X509 *x, size_t chainidx, int *al);
-int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
-                                        unsigned int context, X509 *x,
-                                        size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
+                                               unsigned int context, X509 *x,
+                                               size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context,
-                                  X509 *x, size_t chainidx, int *al);
-int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al);
-int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, unsigned int context,
-                                X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt,
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt,
+                                       unsigned int context, X509 *x,
+                                       size_t chainidx, int *al);
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
-                                      unsigned int context, X509 *x,
-                                      size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
+                                             unsigned int context, X509 *x,
+                                             size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                            size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
-                                X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+                                       X509 *x, size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_CT
-int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
-int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
-                                          unsigned int context, X509 *x,
-                                          size_t chainidx, int *al);
-int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
-                                 X509 *x, size_t chainidx, int *al);
-int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, unsigned int context,
+EXT_RETURN tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
+                                                 unsigned int context, X509 *x,
+                                                 size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_key_share(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
+                                        size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt,
+                                            unsigned int context, X509 *x,
+                                            size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
                                      X509 *x, size_t chainidx, int *al);
-int tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context,
-                              X509 *x, size_t chainidx, int *al);
-int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, unsigned int context,
-                               X509 *x, size_t chainidx, int *al);
-int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
-                           size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_padding(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
+                                      size_t chainidx, int *al);
+EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
                                X509 *x, size_t chainidx, int *al);
 int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
diff --git a/test/recipes/70-test_sslextension.t b/test/recipes/70-test_sslextension.t
index 1c0e96e..ce25c78 100644
--- a/test/recipes/70-test_sslextension.t
+++ b/test/recipes/70-test_sslextension.t
@@ -26,6 +26,14 @@ plan skip_all => "$test_name needs the sock feature enabled"
 plan skip_all => "$test_name needs TLS enabled"
     if alldisabled(available_protocols("tls"));
 
+use constant {
+    UNSOLICITED_SERVER_NAME => 0,
+    UNSOLICITED_SERVER_NAME_TLS13 => 1,
+    UNSOLICITED_SCT => 2
+};
+
+my $testtype;
+
 $ENV{OPENSSL_ia32cap} = '~0x200000200000000';
 my $proxy = TLSProxy::Proxy->new(
     \&extension_filter,
@@ -36,7 +44,7 @@ my $proxy = TLSProxy::Proxy->new(
 
 # Test 1: Sending a zero length extension block should pass
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 3;
+plan tests => 6;
 ok(TLSProxy::Message->success, "Zero extension length test");
 
 sub extension_filter
@@ -119,3 +127,63 @@ $proxy->clear();
 $proxy->filter(\&inject_duplicate_extension_serverhello);
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Duplicate ServerHello extension");
+
+sub inject_unsolicited_extension
+{
+    my $proxy = shift;
+    my $message;
+
+    # We're only interested in the initial ServerHello/EncryptedExtensions
+    if ($proxy->flight != 1) {
+        return;
+    }
+
+    if ($testtype == UNSOLICITED_SERVER_NAME_TLS13) {
+        $message = ${$proxy->message_list}[2];
+        die "Expecting EE message ".($message->mt).", ".${$proxy->message_list}[1]->mt.", ".${$proxy->message_list}[3]->mt if $message->mt != TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS;
+    } else {
+        $message = ${$proxy->message_list}[1];
+    }
+
+    my $ext = pack "C2",
+        0x00, 0x00; #Extension length
+
+    my $type;
+    if ($testtype == UNSOLICITED_SERVER_NAME
+            || $testtype == UNSOLICITED_SERVER_NAME_TLS13) {
+        $type = TLSProxy::Message::EXT_SERVER_NAME;
+    } elsif ($testtype == UNSOLICITED_SCT) {
+        $type = TLSProxy::Message::EXT_SCT;
+    }
+    $message->set_extension($type, $ext);
+    $message->repack();
+}
+
+SKIP: {
+    skip "TLS <= 1.2 disabled", 2 if alldisabled(("tls1", "tls1_1", "tls1_2"));
+    #Test 4: Inject an unsolicited extension (<= TLSv1.2)
+    $proxy->clear();
+    $proxy->filter(\&inject_unsolicited_extension);
+    $testtype = UNSOLICITED_SERVER_NAME;
+    $proxy->clientflags("-no_tls1_3 -noservername");
+    $proxy->start();
+    ok(TLSProxy::Message->fail(), "Unsolicited server name extension");
+
+    #Test 5: Same as above for the SCT extension which has special handling
+    $proxy->clear();
+    $testtype = UNSOLICITED_SCT;
+    $proxy->clientflags("-no_tls1_3");
+    $proxy->start();
+    ok(TLSProxy::Message->fail(), "Unsolicited sct extension");
+}
+
+SKIP: {
+    skip "TLS 1.3 disabled", 1 if disabled("tls1_3");
+    #Test 6: Inject an unsolicited extension (TLSv1.3)
+    $proxy->clear();
+    $proxy->filter(\&inject_unsolicited_extension);
+    $testtype = UNSOLICITED_SERVER_NAME_TLS13;
+    $proxy->clientflags("-noservername");
+    $proxy->start();
+    ok(TLSProxy::Message->fail(), "Unsolicited server name extension (TLSv1.3)");
+}


More information about the openssl-commits mailing list