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>
{
SSL_CTX_set_custom_cli_ext(ctx,
serverinfo_types[i],
- NULL,
+ NULL, NULL, NULL,
serverinfo_cli_cb,
NULL);
}
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,
- 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,
- void *arg);
+ void *parse_arg);
+
#endif
#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,
- 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,
- 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
*/
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;
- void *arg;
+ void *parse_arg;
} custom_ext_method;
/* ext_flags values */
/* 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;
{
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,
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,
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,
#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)
- 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)
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_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_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_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_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,
- 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,
- 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,
- 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 (!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
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 */
- if (cb_retval == -1)
+ if (cb_retval == 0)
continue; /* skip this extension */
}
if (4 > limit - ret || outlen > (size_t)(limit - ret - 4))
* 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;
/* 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,
- 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 */
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->arg = arg;
+ meth->add_arg = add_arg;
+ meth->parse_arg = parse_arg;
exts->meths_count++;
return 1;
}
/* 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,
- 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
*/
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
/* 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)