New extension callback features.
authorDr. Stephen Henson <steve@openssl.org>
Sat, 16 Aug 2014 17:16:26 +0000 (18:16 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 28 Aug 2014 16:06:53 +0000 (17:06 +0100)
Support separate parse and add callback arguments.
Add new callback so an application can free extension data.
Change return value for send functions so < 0 is an error 0
omits extension and > 0 includes it. This is more consistent
with the behaviour of other functions in OpenSSL.

Modify parse_cb handling so <= 0 is an error.

Make SSL_CTX_set_custom_cli_ext and SSL_CTX_set_custom_cli_ext argument
order consistent.

NOTE: these changes WILL break existing code.

Remove (now inaccurate) in line documentation.
Reviewed-by: Emilia Käsper <emilia@openssl.org>
apps/s_client.c
ssl/ssl.h
ssl/ssl_locl.h
ssl/ssl_rsa.c
ssl/ssltest.c
ssl/t1_ext.c
ssl/t1_lib.c

index 6a37774..e4007c2 100644 (file)
@@ -1363,7 +1363,7 @@ bad:
                                {
                                SSL_CTX_set_custom_cli_ext(ctx,
                                                           serverinfo_types[i],
                                {
                                SSL_CTX_set_custom_cli_ext(ctx,
                                                           serverinfo_types[i],
-                                                          NULL, 
+                                                          NULL, NULL, NULL,
                                                           serverinfo_cli_cb,
                                                           NULL);
                                }
                                                           serverinfo_cli_cb,
                                                           NULL);
                                }
index 8c59ed3..2a0d928 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -389,36 +389,23 @@ typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, i
 typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
 
 #ifndef OPENSSL_NO_TLSEXT
 typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
 
 #ifndef OPENSSL_NO_TLSEXT
-/* Callbacks and structures for handling custom TLS Extensions: 
- *   cli_ext_add_cb   - sends data for ClientHello TLS Extension
- *   cli_ext_parse_cb - receives data from ServerHello TLS Extension
- *   srv_ext_parse_cb - receives data from ClientHello TLS Extension
- *   srv_ext_add_cb   - sends data for ServerHello TLS Extension
- *
- *   All these functions return nonzero on success.  Zero will terminate
- *   the handshake (and return a specific TLS Fatal alert, if the function
- *   declaration has an "al" parameter).  -1 for the "sending" functions
- *   will cause the TLS Extension to be omitted.
- * 
- *   "ext_type" is a TLS "ExtensionType" from 0-65535.
- *   "in" is a pointer to TLS "extension_data" being provided to the cb.
- *   "out" is used by the callback to return a pointer to "extension data"
- *     which OpenSSL will later copy into the TLS handshake.  The contents
- *     of this buffer should not be changed until the handshake is complete.
- *   "inlen" and "outlen" are TLS Extension lengths from 0-65535.
- *   "al" is a TLS "AlertDescription" from 0-255 which WILL be sent as a 
- *     fatal TLS alert, if the callback returns zero.
- */
+
+/* Typedefs for handling custom extensions */
 
 typedef int (*custom_ext_add_cb)(SSL *s, unsigned int ext_type,
                                          const unsigned char **out,
                                          size_t *outlen, int *al,
 
 typedef int (*custom_ext_add_cb)(SSL *s, unsigned int ext_type,
                                          const unsigned char **out,
                                          size_t *outlen, int *al,
-                                          void *arg);
+                                          void *add_arg);
+
+typedef void (*custom_ext_free_cb)(SSL *s, unsigned int ext_type,
+                                          const unsigned char *out,
+                                          void *add_arg);
 
 typedef int (*custom_ext_parse_cb)(SSL *s, unsigned int ext_type,
                                           const unsigned char *in,
                                           size_t inlen, int *al,
 
 typedef int (*custom_ext_parse_cb)(SSL *s, unsigned int ext_type,
                                           const unsigned char *in,
                                           size_t inlen, int *al,
-                                          void *arg);
+                                          void *parse_arg);
+
 
 #endif
 
 
 #endif
 
@@ -1264,30 +1251,19 @@ const char *SSL_get_psk_identity(const SSL *s);
 #endif
 
 #ifndef OPENSSL_NO_TLSEXT
 #endif
 
 #ifndef OPENSSL_NO_TLSEXT
-/* Register callbacks to handle custom TLS Extensions as client or server.
- * 
- * Returns nonzero on success.  You cannot register twice for the same 
- * extension number, and registering for an extension number already 
- * handled by OpenSSL will fail.
- *
- * NULL can be registered for any callback function.  For the client
- * functions, a NULL custom_ext_add_cb sends an empty ClientHello
- * Extension, and a NULL custom_ext_parse_cb ignores the ServerHello
- * response (if any).
- *
- * For the server functions, a NULL custom_ext_parse means the
- * ClientHello extension's data will be ignored, but the extension will still
- * be noted and custom_ext_add_cb will still be invoked.  A NULL
- * custom_srv_ext_second_cb doesn't send a ServerHello extension.
- */
+/* Register callbacks to handle custom TLS Extensions for client or server. */
+
 int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned int ext_type,
 int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned int ext_type,
-                              custom_ext_add_cb add_cb, 
-                              custom_ext_parse_cb parse_cb, void *arg);
+                              custom_ext_add_cb add_cb,
+                              custom_ext_free_cb free_cb,
+                               void *add_arg,
+                              custom_ext_parse_cb parse_cb, void *parse_arg);
 
 int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned int ext_type,
 
 int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned int ext_type,
-                              custom_ext_parse_cb parse_cb, 
-                              custom_ext_add_cb add_cb, void *arg);
-
+                              custom_ext_add_cb add_cb,
+                              custom_ext_free_cb free_cb,
+                               void *add_arg,
+                              custom_ext_parse_cb parse_cb, void *parse_arg);
 #endif
 
 #define SSL_NOTHING    1
 #endif
 
 #define SSL_NOTHING    1
index d76269d..3f87da7 100644 (file)
@@ -539,8 +539,10 @@ typedef struct {
         */
        unsigned short ext_flags;
        custom_ext_add_cb add_cb; 
         */
        unsigned short ext_flags;
        custom_ext_add_cb add_cb; 
+       custom_ext_free_cb free_cb; 
+       void *add_arg;
        custom_ext_parse_cb parse_cb; 
        custom_ext_parse_cb parse_cb; 
-       void *arg;
+       void *parse_arg;
 } custom_ext_method;
 
 /* ext_flags values */
 } custom_ext_method;
 
 /* ext_flags values */
index d4f0e28..6e3d44c 100644 (file)
@@ -921,8 +921,10 @@ static int serverinfo_process_buffer(const unsigned char *serverinfo,
                /* Register callbacks for extensions */
                ext_type = (serverinfo[0] << 8) + serverinfo[1];
                if (ctx && !SSL_CTX_set_custom_srv_ext(ctx, ext_type, 
                /* Register callbacks for extensions */
                ext_type = (serverinfo[0] << 8) + serverinfo[1];
                if (ctx && !SSL_CTX_set_custom_srv_ext(ctx, ext_type, 
-                                                      serverinfo_srv_parse_cb,
-                                                      serverinfo_srv_add_cb, NULL))
+                                                      serverinfo_srv_add_cb,
+                                                      NULL, NULL,
+                                                      serverinfo_srv_parse_cb, 
+                                                      NULL))
                        return 0;
 
                serverinfo += 2;
                        return 0;
 
                serverinfo += 2;
index 5837abb..09400a1 100644 (file)
@@ -558,7 +558,7 @@ static int custom_ext_0_cli_add_cb(SSL *s, unsigned int ext_type,
        {
        if (ext_type != CUSTOM_EXT_TYPE_0)
                custom_ext_error = 1;
        {
        if (ext_type != CUSTOM_EXT_TYPE_0)
                custom_ext_error = 1;
-       return -1;  /* Don't send an extension */
+       return 0;  /* Don't send an extension */
        }
 
 static int custom_ext_0_cli_parse_cb(SSL *s, unsigned int ext_type,
        }
 
 static int custom_ext_0_cli_parse_cb(SSL *s, unsigned int ext_type,
@@ -650,7 +650,7 @@ static int custom_ext_0_srv_add_cb(SSL *s, unsigned int ext_type,
                                      const unsigned char **out,
                                      size_t *outlen, int *al, void *arg)
        {
                                      const unsigned char **out,
                                      size_t *outlen, int *al, void *arg)
        {
-        return -1; /* Don't send an extension */
+        return 0; /* Don't send an extension */
        }
 
 static int custom_ext_1_srv_parse_cb(SSL *s, unsigned int ext_type,
        }
 
 static int custom_ext_1_srv_parse_cb(SSL *s, unsigned int ext_type,
@@ -672,7 +672,7 @@ static int custom_ext_1_srv_add_cb(SSL *s, unsigned int ext_type,
                                      const unsigned char **out,
                                      size_t *outlen, int *al, void *arg)
        {
                                      const unsigned char **out,
                                      size_t *outlen, int *al, void *arg)
        {
-       return -1; /* Don't send an extension */
+       return 0; /* Don't send an extension */
        }
 
 static int custom_ext_2_srv_parse_cb(SSL *s, unsigned int ext_type,
        }
 
 static int custom_ext_2_srv_parse_cb(SSL *s, unsigned int ext_type,
@@ -1584,10 +1584,12 @@ bad:
 #endif
 
        if (serverinfo_sct)
 #endif
 
        if (serverinfo_sct)
-               SSL_CTX_set_custom_cli_ext(c_ctx, SCT_EXT_TYPE, NULL, 
+               SSL_CTX_set_custom_cli_ext(c_ctx, SCT_EXT_TYPE,
+                                          NULL, NULL, NULL,
                                           serverinfo_cli_cb, NULL);
        if (serverinfo_tack)
                                           serverinfo_cli_cb, NULL);
        if (serverinfo_tack)
-               SSL_CTX_set_custom_cli_ext(c_ctx, TACK_EXT_TYPE, NULL,
+               SSL_CTX_set_custom_cli_ext(c_ctx, TACK_EXT_TYPE,
+                                          NULL, NULL, NULL,
                                           serverinfo_cli_cb, NULL);
 
        if (serverinfo_file)
                                           serverinfo_cli_cb, NULL);
 
        if (serverinfo_file)
@@ -1600,31 +1602,31 @@ bad:
        if (custom_ext)
                {
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_0, 
        if (custom_ext)
                {
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_0, 
-                                          custom_ext_0_cli_add_cb, 
+                                          custom_ext_0_cli_add_cb, NULL, NULL,
                                           custom_ext_0_cli_parse_cb, NULL);
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_1, 
                                           custom_ext_0_cli_parse_cb, NULL);
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_1, 
-                                          custom_ext_1_cli_add_cb, 
+                                          custom_ext_1_cli_add_cb, NULL, NULL,
                                           custom_ext_1_cli_parse_cb, NULL);
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_2, 
                                           custom_ext_1_cli_parse_cb, NULL);
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_2, 
-                                          custom_ext_2_cli_add_cb, 
+                                          custom_ext_2_cli_add_cb, NULL, NULL,
                                           custom_ext_2_cli_parse_cb, NULL);
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_3, 
                                           custom_ext_2_cli_parse_cb, NULL);
                SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_3, 
-                                          custom_ext_3_cli_add_cb, 
+                                          custom_ext_3_cli_add_cb, NULL, NULL,
                                           custom_ext_3_cli_parse_cb, NULL);
 
 
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_0, 
                                           custom_ext_3_cli_parse_cb, NULL);
 
 
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_0, 
-                                          custom_ext_0_srv_parse_cb, 
-                                          custom_ext_0_srv_add_cb, NULL);
+                                          custom_ext_0_srv_add_cb, NULL, NULL,
+                                          custom_ext_0_srv_parse_cb, NULL);
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_1, 
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_1, 
-                                          custom_ext_1_srv_parse_cb, 
-                                          custom_ext_1_srv_add_cb, NULL);
+                                          custom_ext_1_srv_add_cb, NULL, NULL,
+                                          custom_ext_1_srv_parse_cb, NULL);
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_2, 
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_2, 
-                                          custom_ext_2_srv_parse_cb, 
-                                          custom_ext_2_srv_add_cb, NULL);
+                                          custom_ext_2_srv_add_cb, NULL, NULL,
+                                          custom_ext_2_srv_parse_cb, NULL);
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_3, 
                SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_3, 
-                                          custom_ext_3_srv_parse_cb, 
-                                          custom_ext_3_srv_add_cb, NULL);
+                                          custom_ext_3_srv_add_cb, NULL, NULL,
+                                          custom_ext_3_srv_parse_cb, NULL);
                }
 
        if (alpn_server)
                }
 
        if (alpn_server)
index 8b6c170..115e434 100644 (file)
@@ -120,7 +120,7 @@ int custom_ext_parse(SSL *s, int server,
        if (!meth->parse_cb)
                return 1;
 
        if (!meth->parse_cb)
                return 1;
 
-       return meth->parse_cb(s, ext_type, ext_data, ext_size, al, meth->arg);
+       return meth->parse_cb(s, ext_type, ext_data, ext_size, al, meth->parse_arg);
        }
 
 /* request custom extension data from the application and add to the
        }
 
 /* request custom extension data from the application and add to the
@@ -159,10 +159,10 @@ int custom_ext_add(SSL *s, int server,
                        int cb_retval = 0;
                        cb_retval = meth->add_cb(s, meth->ext_type,
                                                        &out, &outlen, al,
                        int cb_retval = 0;
                        cb_retval = meth->add_cb(s, meth->ext_type,
                                                        &out, &outlen, al,
-                                                       meth->arg);
-                       if (cb_retval == 0)
+                                                       meth->add_arg);
+                       if (cb_retval < 0)
                                return 0; /* error */
                                return 0; /* error */
-                       if (cb_retval == -1)
+                       if (cb_retval == 0)
                                        continue; /* skip this extension */
                        }
                if (4 > limit - ret || outlen > (size_t)(limit - ret - 4))
                                        continue; /* skip this extension */
                        }
                if (4 > limit - ret || outlen > (size_t)(limit - ret - 4))
@@ -182,6 +182,8 @@ int custom_ext_add(SSL *s, int server,
                 * sent in ServerHello.
                 */
                meth->ext_flags |= SSL_EXT_FLAG_SENT;
                 * sent in ServerHello.
                 */
                meth->ext_flags |= SSL_EXT_FLAG_SENT;
+               if (meth->free_cb)
+                       meth->free_cb(s, meth->ext_type, out, meth->add_arg);
                }
        *pret = ret;
        return 1;
                }
        *pret = ret;
        return 1;
@@ -210,9 +212,10 @@ void custom_exts_free(custom_ext_methods *exts)
 /* Set callbacks for a custom extension */
 static int custom_ext_set(custom_ext_methods *exts,
                        unsigned int ext_type,
 /* Set callbacks for a custom extension */
 static int custom_ext_set(custom_ext_methods *exts,
                        unsigned int ext_type,
-                       custom_ext_parse_cb parse_cb,
                        custom_ext_add_cb add_cb,
                        custom_ext_add_cb add_cb,
-                       void *arg)
+                       custom_ext_free_cb free_cb,
+                       void *add_arg,
+                       custom_ext_parse_cb parse_cb, void *parse_arg)
        {
        custom_ext_method *meth;
        /* See if it is a supported internally */
        {
        custom_ext_method *meth;
        /* See if it is a supported internally */
@@ -258,8 +261,10 @@ static int custom_ext_set(custom_ext_methods *exts,
        memset(meth, 0, sizeof(custom_ext_method));
        meth->parse_cb = parse_cb;
        meth->add_cb = add_cb;
        memset(meth, 0, sizeof(custom_ext_method));
        meth->parse_cb = parse_cb;
        meth->add_cb = add_cb;
+       meth->free_cb = free_cb;
        meth->ext_type = ext_type;
        meth->ext_type = ext_type;
-       meth->arg = arg;
+       meth->add_arg = add_arg;
+       meth->parse_arg = parse_arg;
        exts->meths_count++;
        return 1;
        }
        exts->meths_count++;
        return 1;
        }
@@ -267,19 +272,25 @@ static int custom_ext_set(custom_ext_methods *exts,
 /* Application level functions to add custom extension callbacks */
 
 int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned int ext_type,
 /* Application level functions to add custom extension callbacks */
 
 int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned int ext_type,
-                              custom_ext_add_cb add_cb, 
-                              custom_ext_parse_cb parse_cb, void *arg)
+                              custom_ext_add_cb add_cb,
+                              custom_ext_free_cb free_cb,
+                               void *add_arg,
+                              custom_ext_parse_cb parse_cb, void *parse_arg)
 
        {
 
        {
-       return custom_ext_set(&ctx->cert->cli_ext, ext_type, parse_cb, add_cb,
-                                                                       arg);
+       return custom_ext_set(&ctx->cert->cli_ext, ext_type,
+                               add_cb, free_cb, add_arg,
+                               parse_cb, parse_arg);
        }
 
 int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned int ext_type,
        }
 
 int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned int ext_type,
-                              custom_ext_parse_cb parse_cb, 
-                              custom_ext_add_cb add_cb, void *arg)
+                              custom_ext_add_cb add_cb,
+                              custom_ext_free_cb free_cb,
+                               void *add_arg,
+                              custom_ext_parse_cb parse_cb, void *parse_arg)
        {
        {
-       return custom_ext_set(&ctx->cert->srv_ext, ext_type, parse_cb, add_cb,
-                                                                       arg);
+       return custom_ext_set(&ctx->cert->srv_ext, ext_type,
+                               add_cb, free_cb, add_arg,
+                               parse_cb, parse_arg);
        }
 #endif
        }
 #endif
index f94a4c0..f46279d 100644 (file)
@@ -2442,7 +2442,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
                 */
                else if (!s->hit)
                        {
                 */
                else if (!s->hit)
                        {
-                       if (!custom_ext_parse(s, 1, type, data, size, al))
+                       if (custom_ext_parse(s, 1, type, data, size, al) <= 0)
                                return 0;
                        }
 #ifdef TLSEXT_TYPE_encrypt_then_mac
                                return 0;
                        }
 #ifdef TLSEXT_TYPE_encrypt_then_mac
@@ -2777,7 +2777,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
                /* If this extension type was not otherwise handled, but 
                 * matches a custom_cli_ext_record, then send it to the c
                 * callback */
                /* If this extension type was not otherwise handled, but 
                 * matches a custom_cli_ext_record, then send it to the c
                 * callback */
-               else if (!custom_ext_parse(s, 0, type, data, size, al))
+               else if (custom_ext_parse(s, 0, type, data, size, al) <= 0)
                                return 0;
 #ifdef TLSEXT_TYPE_encrypt_then_mac
                else if (type == TLSEXT_TYPE_encrypt_then_mac)
                                return 0;
 #ifdef TLSEXT_TYPE_encrypt_then_mac
                else if (type == TLSEXT_TYPE_encrypt_then_mac)