1e71b7053SJung-uk Kim /* 2*b2bf0c7eSJung-uk Kim * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved. 3e71b7053SJung-uk Kim * 4e71b7053SJung-uk Kim * Licensed under the OpenSSL license (the "License"). You may not use 5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy 6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at 7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html 8e71b7053SJung-uk Kim */ 9e71b7053SJung-uk Kim 10e71b7053SJung-uk Kim /* Custom extension utility functions */ 11e71b7053SJung-uk Kim 12e71b7053SJung-uk Kim #include <openssl/ct.h> 1317f01e99SJung-uk Kim #include "../ssl_local.h" 14e71b7053SJung-uk Kim #include "internal/cryptlib.h" 1517f01e99SJung-uk Kim #include "statem_local.h" 16e71b7053SJung-uk Kim 17e71b7053SJung-uk Kim typedef struct { 18e71b7053SJung-uk Kim void *add_arg; 19e71b7053SJung-uk Kim custom_ext_add_cb add_cb; 20e71b7053SJung-uk Kim custom_ext_free_cb free_cb; 21e71b7053SJung-uk Kim } custom_ext_add_cb_wrap; 22e71b7053SJung-uk Kim 23e71b7053SJung-uk Kim typedef struct { 24e71b7053SJung-uk Kim void *parse_arg; 25e71b7053SJung-uk Kim custom_ext_parse_cb parse_cb; 26e71b7053SJung-uk Kim } custom_ext_parse_cb_wrap; 27e71b7053SJung-uk Kim 28e71b7053SJung-uk Kim /* 29e71b7053SJung-uk Kim * Provide thin wrapper callbacks which convert new style arguments to old style 30e71b7053SJung-uk Kim */ 31e71b7053SJung-uk Kim static int custom_ext_add_old_cb_wrap(SSL *s, unsigned int ext_type, 32e71b7053SJung-uk Kim unsigned int context, 33e71b7053SJung-uk Kim const unsigned char **out, 34e71b7053SJung-uk Kim size_t *outlen, X509 *x, size_t chainidx, 35e71b7053SJung-uk Kim int *al, void *add_arg) 36e71b7053SJung-uk Kim { 37e71b7053SJung-uk Kim custom_ext_add_cb_wrap *add_cb_wrap = (custom_ext_add_cb_wrap *)add_arg; 38e71b7053SJung-uk Kim 39e71b7053SJung-uk Kim if (add_cb_wrap->add_cb == NULL) 40e71b7053SJung-uk Kim return 1; 41e71b7053SJung-uk Kim 42e71b7053SJung-uk Kim return add_cb_wrap->add_cb(s, ext_type, out, outlen, al, 43e71b7053SJung-uk Kim add_cb_wrap->add_arg); 44e71b7053SJung-uk Kim } 45e71b7053SJung-uk Kim 46e71b7053SJung-uk Kim static void custom_ext_free_old_cb_wrap(SSL *s, unsigned int ext_type, 47e71b7053SJung-uk Kim unsigned int context, 48e71b7053SJung-uk Kim const unsigned char *out, void *add_arg) 49e71b7053SJung-uk Kim { 50e71b7053SJung-uk Kim custom_ext_add_cb_wrap *add_cb_wrap = (custom_ext_add_cb_wrap *)add_arg; 51e71b7053SJung-uk Kim 52e71b7053SJung-uk Kim if (add_cb_wrap->free_cb == NULL) 53e71b7053SJung-uk Kim return; 54e71b7053SJung-uk Kim 55e71b7053SJung-uk Kim add_cb_wrap->free_cb(s, ext_type, out, add_cb_wrap->add_arg); 56e71b7053SJung-uk Kim } 57e71b7053SJung-uk Kim 58e71b7053SJung-uk Kim static int custom_ext_parse_old_cb_wrap(SSL *s, unsigned int ext_type, 59e71b7053SJung-uk Kim unsigned int context, 60e71b7053SJung-uk Kim const unsigned char *in, 61e71b7053SJung-uk Kim size_t inlen, X509 *x, size_t chainidx, 62e71b7053SJung-uk Kim int *al, void *parse_arg) 63e71b7053SJung-uk Kim { 64e71b7053SJung-uk Kim custom_ext_parse_cb_wrap *parse_cb_wrap = 65e71b7053SJung-uk Kim (custom_ext_parse_cb_wrap *)parse_arg; 66e71b7053SJung-uk Kim 67e71b7053SJung-uk Kim if (parse_cb_wrap->parse_cb == NULL) 68e71b7053SJung-uk Kim return 1; 69e71b7053SJung-uk Kim 70e71b7053SJung-uk Kim return parse_cb_wrap->parse_cb(s, ext_type, in, inlen, al, 71e71b7053SJung-uk Kim parse_cb_wrap->parse_arg); 72e71b7053SJung-uk Kim } 73e71b7053SJung-uk Kim 74e71b7053SJung-uk Kim /* 75e71b7053SJung-uk Kim * Find a custom extension from the list. The |role| param is there to 76e71b7053SJung-uk Kim * support the legacy API where custom extensions for client and server could 77e71b7053SJung-uk Kim * be set independently on the same SSL_CTX. It is set to ENDPOINT_SERVER if we 78e71b7053SJung-uk Kim * are trying to find a method relevant to the server, ENDPOINT_CLIENT for the 79e71b7053SJung-uk Kim * client, or ENDPOINT_BOTH for either 80e71b7053SJung-uk Kim */ 81e71b7053SJung-uk Kim custom_ext_method *custom_ext_find(const custom_ext_methods *exts, 82e71b7053SJung-uk Kim ENDPOINT role, unsigned int ext_type, 83e71b7053SJung-uk Kim size_t *idx) 84e71b7053SJung-uk Kim { 85e71b7053SJung-uk Kim size_t i; 86e71b7053SJung-uk Kim custom_ext_method *meth = exts->meths; 87e71b7053SJung-uk Kim 88e71b7053SJung-uk Kim for (i = 0; i < exts->meths_count; i++, meth++) { 89e71b7053SJung-uk Kim if (ext_type == meth->ext_type 90e71b7053SJung-uk Kim && (role == ENDPOINT_BOTH || role == meth->role 91e71b7053SJung-uk Kim || meth->role == ENDPOINT_BOTH)) { 92e71b7053SJung-uk Kim if (idx != NULL) 93e71b7053SJung-uk Kim *idx = i; 94e71b7053SJung-uk Kim return meth; 95e71b7053SJung-uk Kim } 96e71b7053SJung-uk Kim } 97e71b7053SJung-uk Kim return NULL; 98e71b7053SJung-uk Kim } 99e71b7053SJung-uk Kim 100e71b7053SJung-uk Kim /* 101e71b7053SJung-uk Kim * Initialise custom extensions flags to indicate neither sent nor received. 102e71b7053SJung-uk Kim */ 103e71b7053SJung-uk Kim void custom_ext_init(custom_ext_methods *exts) 104e71b7053SJung-uk Kim { 105e71b7053SJung-uk Kim size_t i; 106e71b7053SJung-uk Kim custom_ext_method *meth = exts->meths; 107e71b7053SJung-uk Kim 108e71b7053SJung-uk Kim for (i = 0; i < exts->meths_count; i++, meth++) 109e71b7053SJung-uk Kim meth->ext_flags = 0; 110e71b7053SJung-uk Kim } 111e71b7053SJung-uk Kim 112e71b7053SJung-uk Kim /* Pass received custom extension data to the application for parsing. */ 113e71b7053SJung-uk Kim int custom_ext_parse(SSL *s, unsigned int context, unsigned int ext_type, 114e71b7053SJung-uk Kim const unsigned char *ext_data, size_t ext_size, X509 *x, 115e71b7053SJung-uk Kim size_t chainidx) 116e71b7053SJung-uk Kim { 117e71b7053SJung-uk Kim int al; 118e71b7053SJung-uk Kim custom_ext_methods *exts = &s->cert->custext; 119e71b7053SJung-uk Kim custom_ext_method *meth; 120e71b7053SJung-uk Kim ENDPOINT role = ENDPOINT_BOTH; 121e71b7053SJung-uk Kim 122e71b7053SJung-uk Kim if ((context & (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO)) != 0) 123e71b7053SJung-uk Kim role = s->server ? ENDPOINT_SERVER : ENDPOINT_CLIENT; 124e71b7053SJung-uk Kim 125e71b7053SJung-uk Kim meth = custom_ext_find(exts, role, ext_type, NULL); 126e71b7053SJung-uk Kim /* If not found return success */ 127e71b7053SJung-uk Kim if (!meth) 128e71b7053SJung-uk Kim return 1; 129e71b7053SJung-uk Kim 130e71b7053SJung-uk Kim /* Check if extension is defined for our protocol. If not, skip */ 131e71b7053SJung-uk Kim if (!extension_is_relevant(s, meth->context, context)) 132e71b7053SJung-uk Kim return 1; 133e71b7053SJung-uk Kim 134e71b7053SJung-uk Kim if ((context & (SSL_EXT_TLS1_2_SERVER_HELLO 135e71b7053SJung-uk Kim | SSL_EXT_TLS1_3_SERVER_HELLO 136e71b7053SJung-uk Kim | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS)) != 0) { 137e71b7053SJung-uk Kim /* 138e71b7053SJung-uk Kim * If it's ServerHello or EncryptedExtensions we can't have any 139e71b7053SJung-uk Kim * extensions not sent in ClientHello. 140e71b7053SJung-uk Kim */ 141e71b7053SJung-uk Kim if ((meth->ext_flags & SSL_EXT_FLAG_SENT) == 0) { 142e71b7053SJung-uk Kim SSLfatal(s, TLS1_AD_UNSUPPORTED_EXTENSION, SSL_F_CUSTOM_EXT_PARSE, 143e71b7053SJung-uk Kim SSL_R_BAD_EXTENSION); 144e71b7053SJung-uk Kim return 0; 145e71b7053SJung-uk Kim } 146e71b7053SJung-uk Kim } 147e71b7053SJung-uk Kim 148e71b7053SJung-uk Kim /* 149*b2bf0c7eSJung-uk Kim * Extensions received in the ClientHello or CertificateRequest are marked 150*b2bf0c7eSJung-uk Kim * with the SSL_EXT_FLAG_RECEIVED. This is so we know to add the equivalent 151*b2bf0c7eSJung-uk Kim * extensions in the response messages 152e71b7053SJung-uk Kim */ 153*b2bf0c7eSJung-uk Kim if ((context & (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST)) 154*b2bf0c7eSJung-uk Kim != 0) 155e71b7053SJung-uk Kim meth->ext_flags |= SSL_EXT_FLAG_RECEIVED; 156e71b7053SJung-uk Kim 157e71b7053SJung-uk Kim /* If no parse function set return success */ 158e71b7053SJung-uk Kim if (!meth->parse_cb) 159e71b7053SJung-uk Kim return 1; 160e71b7053SJung-uk Kim 161e71b7053SJung-uk Kim if (meth->parse_cb(s, ext_type, context, ext_data, ext_size, x, chainidx, 162e71b7053SJung-uk Kim &al, meth->parse_arg) <= 0) { 163e71b7053SJung-uk Kim SSLfatal(s, al, SSL_F_CUSTOM_EXT_PARSE, SSL_R_BAD_EXTENSION); 164e71b7053SJung-uk Kim return 0; 165e71b7053SJung-uk Kim } 166e71b7053SJung-uk Kim 167e71b7053SJung-uk Kim return 1; 168e71b7053SJung-uk Kim } 169e71b7053SJung-uk Kim 170e71b7053SJung-uk Kim /* 171e71b7053SJung-uk Kim * Request custom extension data from the application and add to the return 172e71b7053SJung-uk Kim * buffer. 173e71b7053SJung-uk Kim */ 174e71b7053SJung-uk Kim int custom_ext_add(SSL *s, int context, WPACKET *pkt, X509 *x, size_t chainidx, 175e71b7053SJung-uk Kim int maxversion) 176e71b7053SJung-uk Kim { 177e71b7053SJung-uk Kim custom_ext_methods *exts = &s->cert->custext; 178e71b7053SJung-uk Kim custom_ext_method *meth; 179e71b7053SJung-uk Kim size_t i; 180e71b7053SJung-uk Kim int al; 181e71b7053SJung-uk Kim 182e71b7053SJung-uk Kim for (i = 0; i < exts->meths_count; i++) { 183e71b7053SJung-uk Kim const unsigned char *out = NULL; 184e71b7053SJung-uk Kim size_t outlen = 0; 185e71b7053SJung-uk Kim 186e71b7053SJung-uk Kim meth = exts->meths + i; 187e71b7053SJung-uk Kim 188e71b7053SJung-uk Kim if (!should_add_extension(s, meth->context, context, maxversion)) 189e71b7053SJung-uk Kim continue; 190e71b7053SJung-uk Kim 191e71b7053SJung-uk Kim if ((context & (SSL_EXT_TLS1_2_SERVER_HELLO 192e71b7053SJung-uk Kim | SSL_EXT_TLS1_3_SERVER_HELLO 193e71b7053SJung-uk Kim | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS 194e71b7053SJung-uk Kim | SSL_EXT_TLS1_3_CERTIFICATE 195e71b7053SJung-uk Kim | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST)) != 0) { 196*b2bf0c7eSJung-uk Kim /* Only send extensions present in ClientHello/CertificateRequest */ 197e71b7053SJung-uk Kim if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED)) 198e71b7053SJung-uk Kim continue; 199e71b7053SJung-uk Kim } 200e71b7053SJung-uk Kim /* 201e71b7053SJung-uk Kim * We skip it if the callback is absent - except for a ClientHello where 202e71b7053SJung-uk Kim * we add an empty extension. 203e71b7053SJung-uk Kim */ 204e71b7053SJung-uk Kim if ((context & SSL_EXT_CLIENT_HELLO) == 0 && meth->add_cb == NULL) 205e71b7053SJung-uk Kim continue; 206e71b7053SJung-uk Kim 207e71b7053SJung-uk Kim if (meth->add_cb != NULL) { 208e71b7053SJung-uk Kim int cb_retval = meth->add_cb(s, meth->ext_type, context, &out, 209e71b7053SJung-uk Kim &outlen, x, chainidx, &al, 210e71b7053SJung-uk Kim meth->add_arg); 211e71b7053SJung-uk Kim 212e71b7053SJung-uk Kim if (cb_retval < 0) { 213e71b7053SJung-uk Kim SSLfatal(s, al, SSL_F_CUSTOM_EXT_ADD, SSL_R_CALLBACK_FAILED); 214e71b7053SJung-uk Kim return 0; /* error */ 215e71b7053SJung-uk Kim } 216e71b7053SJung-uk Kim if (cb_retval == 0) 217e71b7053SJung-uk Kim continue; /* skip this extension */ 218e71b7053SJung-uk Kim } 219e71b7053SJung-uk Kim 220e71b7053SJung-uk Kim if (!WPACKET_put_bytes_u16(pkt, meth->ext_type) 221e71b7053SJung-uk Kim || !WPACKET_start_sub_packet_u16(pkt) 222e71b7053SJung-uk Kim || (outlen > 0 && !WPACKET_memcpy(pkt, out, outlen)) 223e71b7053SJung-uk Kim || !WPACKET_close(pkt)) { 224e71b7053SJung-uk Kim SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CUSTOM_EXT_ADD, 225e71b7053SJung-uk Kim ERR_R_INTERNAL_ERROR); 226e71b7053SJung-uk Kim return 0; 227e71b7053SJung-uk Kim } 228e71b7053SJung-uk Kim if ((context & SSL_EXT_CLIENT_HELLO) != 0) { 229e71b7053SJung-uk Kim /* 230e71b7053SJung-uk Kim * We can't send duplicates: code logic should prevent this. 231e71b7053SJung-uk Kim */ 232e71b7053SJung-uk Kim if (!ossl_assert((meth->ext_flags & SSL_EXT_FLAG_SENT) == 0)) { 233e71b7053SJung-uk Kim SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CUSTOM_EXT_ADD, 234e71b7053SJung-uk Kim ERR_R_INTERNAL_ERROR); 235e71b7053SJung-uk Kim return 0; 236e71b7053SJung-uk Kim } 237e71b7053SJung-uk Kim /* 238e71b7053SJung-uk Kim * Indicate extension has been sent: this is both a sanity check to 239e71b7053SJung-uk Kim * ensure we don't send duplicate extensions and indicates that it 240e71b7053SJung-uk Kim * is not an error if the extension is present in ServerHello. 241e71b7053SJung-uk Kim */ 242e71b7053SJung-uk Kim meth->ext_flags |= SSL_EXT_FLAG_SENT; 243e71b7053SJung-uk Kim } 244e71b7053SJung-uk Kim if (meth->free_cb != NULL) 245e71b7053SJung-uk Kim meth->free_cb(s, meth->ext_type, context, out, meth->add_arg); 246e71b7053SJung-uk Kim } 247e71b7053SJung-uk Kim return 1; 248e71b7053SJung-uk Kim } 249e71b7053SJung-uk Kim 250e71b7053SJung-uk Kim /* Copy the flags from src to dst for any extensions that exist in both */ 251e71b7053SJung-uk Kim int custom_exts_copy_flags(custom_ext_methods *dst, 252e71b7053SJung-uk Kim const custom_ext_methods *src) 253e71b7053SJung-uk Kim { 254e71b7053SJung-uk Kim size_t i; 255e71b7053SJung-uk Kim custom_ext_method *methsrc = src->meths; 256e71b7053SJung-uk Kim 257e71b7053SJung-uk Kim for (i = 0; i < src->meths_count; i++, methsrc++) { 258e71b7053SJung-uk Kim custom_ext_method *methdst = custom_ext_find(dst, methsrc->role, 259e71b7053SJung-uk Kim methsrc->ext_type, NULL); 260e71b7053SJung-uk Kim 261e71b7053SJung-uk Kim if (methdst == NULL) 262e71b7053SJung-uk Kim continue; 263e71b7053SJung-uk Kim 264e71b7053SJung-uk Kim methdst->ext_flags = methsrc->ext_flags; 265e71b7053SJung-uk Kim } 266e71b7053SJung-uk Kim 267e71b7053SJung-uk Kim return 1; 268e71b7053SJung-uk Kim } 269e71b7053SJung-uk Kim 270e71b7053SJung-uk Kim /* Copy table of custom extensions */ 271e71b7053SJung-uk Kim int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src) 272e71b7053SJung-uk Kim { 273e71b7053SJung-uk Kim size_t i; 274e71b7053SJung-uk Kim int err = 0; 275e71b7053SJung-uk Kim 276e71b7053SJung-uk Kim if (src->meths_count > 0) { 277e71b7053SJung-uk Kim dst->meths = 278e71b7053SJung-uk Kim OPENSSL_memdup(src->meths, 279e71b7053SJung-uk Kim sizeof(*src->meths) * src->meths_count); 280e71b7053SJung-uk Kim if (dst->meths == NULL) 281e71b7053SJung-uk Kim return 0; 282e71b7053SJung-uk Kim dst->meths_count = src->meths_count; 283e71b7053SJung-uk Kim 284e71b7053SJung-uk Kim for (i = 0; i < src->meths_count; i++) { 285e71b7053SJung-uk Kim custom_ext_method *methsrc = src->meths + i; 286e71b7053SJung-uk Kim custom_ext_method *methdst = dst->meths + i; 287e71b7053SJung-uk Kim 288e71b7053SJung-uk Kim if (methsrc->add_cb != custom_ext_add_old_cb_wrap) 289e71b7053SJung-uk Kim continue; 290e71b7053SJung-uk Kim 291e71b7053SJung-uk Kim /* 292e71b7053SJung-uk Kim * We have found an old style API wrapper. We need to copy the 293e71b7053SJung-uk Kim * arguments too. 294e71b7053SJung-uk Kim */ 295e71b7053SJung-uk Kim 296e71b7053SJung-uk Kim if (err) { 297e71b7053SJung-uk Kim methdst->add_arg = NULL; 298e71b7053SJung-uk Kim methdst->parse_arg = NULL; 299e71b7053SJung-uk Kim continue; 300e71b7053SJung-uk Kim } 301e71b7053SJung-uk Kim 302e71b7053SJung-uk Kim methdst->add_arg = OPENSSL_memdup(methsrc->add_arg, 303e71b7053SJung-uk Kim sizeof(custom_ext_add_cb_wrap)); 304e71b7053SJung-uk Kim methdst->parse_arg = OPENSSL_memdup(methsrc->parse_arg, 305e71b7053SJung-uk Kim sizeof(custom_ext_parse_cb_wrap)); 306e71b7053SJung-uk Kim 307e71b7053SJung-uk Kim if (methdst->add_arg == NULL || methdst->parse_arg == NULL) 308e71b7053SJung-uk Kim err = 1; 309e71b7053SJung-uk Kim } 310e71b7053SJung-uk Kim } 311e71b7053SJung-uk Kim 312e71b7053SJung-uk Kim if (err) { 313e71b7053SJung-uk Kim custom_exts_free(dst); 314e71b7053SJung-uk Kim return 0; 315e71b7053SJung-uk Kim } 316e71b7053SJung-uk Kim 317e71b7053SJung-uk Kim return 1; 318e71b7053SJung-uk Kim } 319e71b7053SJung-uk Kim 320e71b7053SJung-uk Kim void custom_exts_free(custom_ext_methods *exts) 321e71b7053SJung-uk Kim { 322e71b7053SJung-uk Kim size_t i; 323e71b7053SJung-uk Kim custom_ext_method *meth; 324e71b7053SJung-uk Kim 325e71b7053SJung-uk Kim for (i = 0, meth = exts->meths; i < exts->meths_count; i++, meth++) { 326e71b7053SJung-uk Kim if (meth->add_cb != custom_ext_add_old_cb_wrap) 327e71b7053SJung-uk Kim continue; 328e71b7053SJung-uk Kim 329e71b7053SJung-uk Kim /* Old style API wrapper. Need to free the arguments too */ 330e71b7053SJung-uk Kim OPENSSL_free(meth->add_arg); 331e71b7053SJung-uk Kim OPENSSL_free(meth->parse_arg); 332e71b7053SJung-uk Kim } 333e71b7053SJung-uk Kim OPENSSL_free(exts->meths); 334e71b7053SJung-uk Kim } 335e71b7053SJung-uk Kim 336e71b7053SJung-uk Kim /* Return true if a client custom extension exists, false otherwise */ 337e71b7053SJung-uk Kim int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx, unsigned int ext_type) 338e71b7053SJung-uk Kim { 339e71b7053SJung-uk Kim return custom_ext_find(&ctx->cert->custext, ENDPOINT_CLIENT, ext_type, 340e71b7053SJung-uk Kim NULL) != NULL; 341e71b7053SJung-uk Kim } 342e71b7053SJung-uk Kim 343e71b7053SJung-uk Kim static int add_custom_ext_intern(SSL_CTX *ctx, ENDPOINT role, 344e71b7053SJung-uk Kim unsigned int ext_type, 345e71b7053SJung-uk Kim unsigned int context, 346e71b7053SJung-uk Kim SSL_custom_ext_add_cb_ex add_cb, 347e71b7053SJung-uk Kim SSL_custom_ext_free_cb_ex free_cb, 348e71b7053SJung-uk Kim void *add_arg, 349e71b7053SJung-uk Kim SSL_custom_ext_parse_cb_ex parse_cb, 350e71b7053SJung-uk Kim void *parse_arg) 351e71b7053SJung-uk Kim { 352e71b7053SJung-uk Kim custom_ext_methods *exts = &ctx->cert->custext; 353e71b7053SJung-uk Kim custom_ext_method *meth, *tmp; 354e71b7053SJung-uk Kim 355e71b7053SJung-uk Kim /* 356e71b7053SJung-uk Kim * Check application error: if add_cb is not set free_cb will never be 357e71b7053SJung-uk Kim * called. 358e71b7053SJung-uk Kim */ 359e71b7053SJung-uk Kim if (add_cb == NULL && free_cb != NULL) 360e71b7053SJung-uk Kim return 0; 361e71b7053SJung-uk Kim 362e71b7053SJung-uk Kim #ifndef OPENSSL_NO_CT 363e71b7053SJung-uk Kim /* 364e71b7053SJung-uk Kim * We don't want applications registering callbacks for SCT extensions 365e71b7053SJung-uk Kim * whilst simultaneously using the built-in SCT validation features, as 366e71b7053SJung-uk Kim * these two things may not play well together. 367e71b7053SJung-uk Kim */ 368e71b7053SJung-uk Kim if (ext_type == TLSEXT_TYPE_signed_certificate_timestamp 369e71b7053SJung-uk Kim && (context & SSL_EXT_CLIENT_HELLO) != 0 370e71b7053SJung-uk Kim && SSL_CTX_ct_is_enabled(ctx)) 371e71b7053SJung-uk Kim return 0; 372e71b7053SJung-uk Kim #endif 373e71b7053SJung-uk Kim 374e71b7053SJung-uk Kim /* 375e71b7053SJung-uk Kim * Don't add if extension supported internally, but make exception 376e71b7053SJung-uk Kim * for extension types that previously were not supported, but now are. 377e71b7053SJung-uk Kim */ 378e71b7053SJung-uk Kim if (SSL_extension_supported(ext_type) 379e71b7053SJung-uk Kim && ext_type != TLSEXT_TYPE_signed_certificate_timestamp) 380e71b7053SJung-uk Kim return 0; 381e71b7053SJung-uk Kim 382e71b7053SJung-uk Kim /* Extension type must fit in 16 bits */ 383e71b7053SJung-uk Kim if (ext_type > 0xffff) 384e71b7053SJung-uk Kim return 0; 385e71b7053SJung-uk Kim /* Search for duplicate */ 386e71b7053SJung-uk Kim if (custom_ext_find(exts, role, ext_type, NULL)) 387e71b7053SJung-uk Kim return 0; 388e71b7053SJung-uk Kim tmp = OPENSSL_realloc(exts->meths, 389e71b7053SJung-uk Kim (exts->meths_count + 1) * sizeof(custom_ext_method)); 390e71b7053SJung-uk Kim if (tmp == NULL) 391e71b7053SJung-uk Kim return 0; 392e71b7053SJung-uk Kim 393e71b7053SJung-uk Kim exts->meths = tmp; 394e71b7053SJung-uk Kim meth = exts->meths + exts->meths_count; 395e71b7053SJung-uk Kim memset(meth, 0, sizeof(*meth)); 396e71b7053SJung-uk Kim meth->role = role; 397e71b7053SJung-uk Kim meth->context = context; 398e71b7053SJung-uk Kim meth->parse_cb = parse_cb; 399e71b7053SJung-uk Kim meth->add_cb = add_cb; 400e71b7053SJung-uk Kim meth->free_cb = free_cb; 401e71b7053SJung-uk Kim meth->ext_type = ext_type; 402e71b7053SJung-uk Kim meth->add_arg = add_arg; 403e71b7053SJung-uk Kim meth->parse_arg = parse_arg; 404e71b7053SJung-uk Kim exts->meths_count++; 405e71b7053SJung-uk Kim return 1; 406e71b7053SJung-uk Kim } 407e71b7053SJung-uk Kim 408e71b7053SJung-uk Kim static int add_old_custom_ext(SSL_CTX *ctx, ENDPOINT role, 409e71b7053SJung-uk Kim unsigned int ext_type, 410e71b7053SJung-uk Kim unsigned int context, 411e71b7053SJung-uk Kim custom_ext_add_cb add_cb, 412e71b7053SJung-uk Kim custom_ext_free_cb free_cb, 413e71b7053SJung-uk Kim void *add_arg, 414e71b7053SJung-uk Kim custom_ext_parse_cb parse_cb, void *parse_arg) 415e71b7053SJung-uk Kim { 416e71b7053SJung-uk Kim custom_ext_add_cb_wrap *add_cb_wrap 417e71b7053SJung-uk Kim = OPENSSL_malloc(sizeof(*add_cb_wrap)); 418e71b7053SJung-uk Kim custom_ext_parse_cb_wrap *parse_cb_wrap 419e71b7053SJung-uk Kim = OPENSSL_malloc(sizeof(*parse_cb_wrap)); 420e71b7053SJung-uk Kim int ret; 421e71b7053SJung-uk Kim 422e71b7053SJung-uk Kim if (add_cb_wrap == NULL || parse_cb_wrap == NULL) { 423e71b7053SJung-uk Kim OPENSSL_free(add_cb_wrap); 424e71b7053SJung-uk Kim OPENSSL_free(parse_cb_wrap); 425e71b7053SJung-uk Kim return 0; 426e71b7053SJung-uk Kim } 427e71b7053SJung-uk Kim 428e71b7053SJung-uk Kim add_cb_wrap->add_arg = add_arg; 429e71b7053SJung-uk Kim add_cb_wrap->add_cb = add_cb; 430e71b7053SJung-uk Kim add_cb_wrap->free_cb = free_cb; 431e71b7053SJung-uk Kim parse_cb_wrap->parse_arg = parse_arg; 432e71b7053SJung-uk Kim parse_cb_wrap->parse_cb = parse_cb; 433e71b7053SJung-uk Kim 434e71b7053SJung-uk Kim ret = add_custom_ext_intern(ctx, role, ext_type, 435e71b7053SJung-uk Kim context, 436e71b7053SJung-uk Kim custom_ext_add_old_cb_wrap, 437e71b7053SJung-uk Kim custom_ext_free_old_cb_wrap, 438e71b7053SJung-uk Kim add_cb_wrap, 439e71b7053SJung-uk Kim custom_ext_parse_old_cb_wrap, 440e71b7053SJung-uk Kim parse_cb_wrap); 441e71b7053SJung-uk Kim 442e71b7053SJung-uk Kim if (!ret) { 443e71b7053SJung-uk Kim OPENSSL_free(add_cb_wrap); 444e71b7053SJung-uk Kim OPENSSL_free(parse_cb_wrap); 445e71b7053SJung-uk Kim } 446e71b7053SJung-uk Kim 447e71b7053SJung-uk Kim return ret; 448e71b7053SJung-uk Kim } 449e71b7053SJung-uk Kim 450e71b7053SJung-uk Kim /* Application level functions to add the old custom extension callbacks */ 451e71b7053SJung-uk Kim int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type, 452e71b7053SJung-uk Kim custom_ext_add_cb add_cb, 453e71b7053SJung-uk Kim custom_ext_free_cb free_cb, 454e71b7053SJung-uk Kim void *add_arg, 455e71b7053SJung-uk Kim custom_ext_parse_cb parse_cb, void *parse_arg) 456e71b7053SJung-uk Kim { 457e71b7053SJung-uk Kim return add_old_custom_ext(ctx, ENDPOINT_CLIENT, ext_type, 458e71b7053SJung-uk Kim SSL_EXT_TLS1_2_AND_BELOW_ONLY 459e71b7053SJung-uk Kim | SSL_EXT_CLIENT_HELLO 460e71b7053SJung-uk Kim | SSL_EXT_TLS1_2_SERVER_HELLO 461e71b7053SJung-uk Kim | SSL_EXT_IGNORE_ON_RESUMPTION, 462e71b7053SJung-uk Kim add_cb, free_cb, add_arg, parse_cb, parse_arg); 463e71b7053SJung-uk Kim } 464e71b7053SJung-uk Kim 465e71b7053SJung-uk Kim int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type, 466e71b7053SJung-uk Kim custom_ext_add_cb add_cb, 467e71b7053SJung-uk Kim custom_ext_free_cb free_cb, 468e71b7053SJung-uk Kim void *add_arg, 469e71b7053SJung-uk Kim custom_ext_parse_cb parse_cb, void *parse_arg) 470e71b7053SJung-uk Kim { 471e71b7053SJung-uk Kim return add_old_custom_ext(ctx, ENDPOINT_SERVER, ext_type, 472e71b7053SJung-uk Kim SSL_EXT_TLS1_2_AND_BELOW_ONLY 473e71b7053SJung-uk Kim | SSL_EXT_CLIENT_HELLO 474e71b7053SJung-uk Kim | SSL_EXT_TLS1_2_SERVER_HELLO 475e71b7053SJung-uk Kim | SSL_EXT_IGNORE_ON_RESUMPTION, 476e71b7053SJung-uk Kim add_cb, free_cb, add_arg, parse_cb, parse_arg); 477e71b7053SJung-uk Kim } 478e71b7053SJung-uk Kim 479e71b7053SJung-uk Kim int SSL_CTX_add_custom_ext(SSL_CTX *ctx, unsigned int ext_type, 480e71b7053SJung-uk Kim unsigned int context, 481e71b7053SJung-uk Kim SSL_custom_ext_add_cb_ex add_cb, 482e71b7053SJung-uk Kim SSL_custom_ext_free_cb_ex free_cb, 483e71b7053SJung-uk Kim void *add_arg, 484e71b7053SJung-uk Kim SSL_custom_ext_parse_cb_ex parse_cb, void *parse_arg) 485e71b7053SJung-uk Kim { 486e71b7053SJung-uk Kim return add_custom_ext_intern(ctx, ENDPOINT_BOTH, ext_type, context, add_cb, 487e71b7053SJung-uk Kim free_cb, add_arg, parse_cb, parse_arg); 488e71b7053SJung-uk Kim } 489e71b7053SJung-uk Kim 490e71b7053SJung-uk Kim int SSL_extension_supported(unsigned int ext_type) 491e71b7053SJung-uk Kim { 492e71b7053SJung-uk Kim switch (ext_type) { 493e71b7053SJung-uk Kim /* Internally supported extensions. */ 494e71b7053SJung-uk Kim case TLSEXT_TYPE_application_layer_protocol_negotiation: 495e71b7053SJung-uk Kim #ifndef OPENSSL_NO_EC 496e71b7053SJung-uk Kim case TLSEXT_TYPE_ec_point_formats: 497e71b7053SJung-uk Kim case TLSEXT_TYPE_supported_groups: 498e71b7053SJung-uk Kim case TLSEXT_TYPE_key_share: 499e71b7053SJung-uk Kim #endif 500e71b7053SJung-uk Kim #ifndef OPENSSL_NO_NEXTPROTONEG 501e71b7053SJung-uk Kim case TLSEXT_TYPE_next_proto_neg: 502e71b7053SJung-uk Kim #endif 503e71b7053SJung-uk Kim case TLSEXT_TYPE_padding: 504e71b7053SJung-uk Kim case TLSEXT_TYPE_renegotiate: 505e71b7053SJung-uk Kim case TLSEXT_TYPE_max_fragment_length: 506e71b7053SJung-uk Kim case TLSEXT_TYPE_server_name: 507e71b7053SJung-uk Kim case TLSEXT_TYPE_session_ticket: 508e71b7053SJung-uk Kim case TLSEXT_TYPE_signature_algorithms: 509e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SRP 510e71b7053SJung-uk Kim case TLSEXT_TYPE_srp: 511e71b7053SJung-uk Kim #endif 512e71b7053SJung-uk Kim #ifndef OPENSSL_NO_OCSP 513e71b7053SJung-uk Kim case TLSEXT_TYPE_status_request: 514e71b7053SJung-uk Kim #endif 515e71b7053SJung-uk Kim #ifndef OPENSSL_NO_CT 516e71b7053SJung-uk Kim case TLSEXT_TYPE_signed_certificate_timestamp: 517e71b7053SJung-uk Kim #endif 518e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SRTP 519e71b7053SJung-uk Kim case TLSEXT_TYPE_use_srtp: 520e71b7053SJung-uk Kim #endif 521e71b7053SJung-uk Kim case TLSEXT_TYPE_encrypt_then_mac: 522e71b7053SJung-uk Kim case TLSEXT_TYPE_supported_versions: 523e71b7053SJung-uk Kim case TLSEXT_TYPE_extended_master_secret: 524e71b7053SJung-uk Kim case TLSEXT_TYPE_psk_kex_modes: 525e71b7053SJung-uk Kim case TLSEXT_TYPE_cookie: 526e71b7053SJung-uk Kim case TLSEXT_TYPE_early_data: 527e71b7053SJung-uk Kim case TLSEXT_TYPE_certificate_authorities: 528e71b7053SJung-uk Kim case TLSEXT_TYPE_psk: 529e71b7053SJung-uk Kim case TLSEXT_TYPE_post_handshake_auth: 530e71b7053SJung-uk Kim return 1; 531e71b7053SJung-uk Kim default: 532e71b7053SJung-uk Kim return 0; 533e71b7053SJung-uk Kim } 534e71b7053SJung-uk Kim } 535