11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci/* Custom extension utility functions */
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci#include <openssl/ct.h>
131cb0ef41Sopenharmony_ci#include "../ssl_local.h"
141cb0ef41Sopenharmony_ci#include "internal/cryptlib.h"
151cb0ef41Sopenharmony_ci#include "statem_local.h"
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_citypedef struct {
181cb0ef41Sopenharmony_ci    void *add_arg;
191cb0ef41Sopenharmony_ci    custom_ext_add_cb add_cb;
201cb0ef41Sopenharmony_ci    custom_ext_free_cb free_cb;
211cb0ef41Sopenharmony_ci} custom_ext_add_cb_wrap;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_citypedef struct {
241cb0ef41Sopenharmony_ci    void *parse_arg;
251cb0ef41Sopenharmony_ci    custom_ext_parse_cb parse_cb;
261cb0ef41Sopenharmony_ci} custom_ext_parse_cb_wrap;
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci/*
291cb0ef41Sopenharmony_ci * Provide thin wrapper callbacks which convert new style arguments to old style
301cb0ef41Sopenharmony_ci */
311cb0ef41Sopenharmony_cistatic int custom_ext_add_old_cb_wrap(SSL *s, unsigned int ext_type,
321cb0ef41Sopenharmony_ci                                      unsigned int context,
331cb0ef41Sopenharmony_ci                                      const unsigned char **out,
341cb0ef41Sopenharmony_ci                                      size_t *outlen, X509 *x, size_t chainidx,
351cb0ef41Sopenharmony_ci                                      int *al, void *add_arg)
361cb0ef41Sopenharmony_ci{
371cb0ef41Sopenharmony_ci    custom_ext_add_cb_wrap *add_cb_wrap = (custom_ext_add_cb_wrap *)add_arg;
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci    if (add_cb_wrap->add_cb == NULL)
401cb0ef41Sopenharmony_ci        return 1;
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci    return add_cb_wrap->add_cb(s, ext_type, out, outlen, al,
431cb0ef41Sopenharmony_ci                               add_cb_wrap->add_arg);
441cb0ef41Sopenharmony_ci}
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_cistatic void custom_ext_free_old_cb_wrap(SSL *s, unsigned int ext_type,
471cb0ef41Sopenharmony_ci                                        unsigned int context,
481cb0ef41Sopenharmony_ci                                        const unsigned char *out, void *add_arg)
491cb0ef41Sopenharmony_ci{
501cb0ef41Sopenharmony_ci    custom_ext_add_cb_wrap *add_cb_wrap = (custom_ext_add_cb_wrap *)add_arg;
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    if (add_cb_wrap->free_cb == NULL)
531cb0ef41Sopenharmony_ci        return;
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci    add_cb_wrap->free_cb(s, ext_type, out, add_cb_wrap->add_arg);
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_cistatic int custom_ext_parse_old_cb_wrap(SSL *s, unsigned int ext_type,
591cb0ef41Sopenharmony_ci                                        unsigned int context,
601cb0ef41Sopenharmony_ci                                        const unsigned char *in,
611cb0ef41Sopenharmony_ci                                        size_t inlen, X509 *x, size_t chainidx,
621cb0ef41Sopenharmony_ci                                        int *al, void *parse_arg)
631cb0ef41Sopenharmony_ci{
641cb0ef41Sopenharmony_ci    custom_ext_parse_cb_wrap *parse_cb_wrap =
651cb0ef41Sopenharmony_ci        (custom_ext_parse_cb_wrap *)parse_arg;
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    if (parse_cb_wrap->parse_cb == NULL)
681cb0ef41Sopenharmony_ci        return 1;
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci    return parse_cb_wrap->parse_cb(s, ext_type, in, inlen, al,
711cb0ef41Sopenharmony_ci                                   parse_cb_wrap->parse_arg);
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci/*
751cb0ef41Sopenharmony_ci * Find a custom extension from the list. The |role| param is there to
761cb0ef41Sopenharmony_ci * support the legacy API where custom extensions for client and server could
771cb0ef41Sopenharmony_ci * be set independently on the same SSL_CTX. It is set to ENDPOINT_SERVER if we
781cb0ef41Sopenharmony_ci * are trying to find a method relevant to the server, ENDPOINT_CLIENT for the
791cb0ef41Sopenharmony_ci * client, or ENDPOINT_BOTH for either
801cb0ef41Sopenharmony_ci */
811cb0ef41Sopenharmony_cicustom_ext_method *custom_ext_find(const custom_ext_methods *exts,
821cb0ef41Sopenharmony_ci                                   ENDPOINT role, unsigned int ext_type,
831cb0ef41Sopenharmony_ci                                   size_t *idx)
841cb0ef41Sopenharmony_ci{
851cb0ef41Sopenharmony_ci    size_t i;
861cb0ef41Sopenharmony_ci    custom_ext_method *meth = exts->meths;
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci    for (i = 0; i < exts->meths_count; i++, meth++) {
891cb0ef41Sopenharmony_ci        if (ext_type == meth->ext_type
901cb0ef41Sopenharmony_ci                && (role == ENDPOINT_BOTH || role == meth->role
911cb0ef41Sopenharmony_ci                    || meth->role == ENDPOINT_BOTH)) {
921cb0ef41Sopenharmony_ci            if (idx != NULL)
931cb0ef41Sopenharmony_ci                *idx = i;
941cb0ef41Sopenharmony_ci            return meth;
951cb0ef41Sopenharmony_ci        }
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci    return NULL;
981cb0ef41Sopenharmony_ci}
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci/*
1011cb0ef41Sopenharmony_ci * Initialise custom extensions flags to indicate neither sent nor received.
1021cb0ef41Sopenharmony_ci */
1031cb0ef41Sopenharmony_civoid custom_ext_init(custom_ext_methods *exts)
1041cb0ef41Sopenharmony_ci{
1051cb0ef41Sopenharmony_ci    size_t i;
1061cb0ef41Sopenharmony_ci    custom_ext_method *meth = exts->meths;
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci    for (i = 0; i < exts->meths_count; i++, meth++)
1091cb0ef41Sopenharmony_ci        meth->ext_flags = 0;
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci/* Pass received custom extension data to the application for parsing. */
1131cb0ef41Sopenharmony_ciint custom_ext_parse(SSL *s, unsigned int context, unsigned int ext_type,
1141cb0ef41Sopenharmony_ci                     const unsigned char *ext_data, size_t ext_size, X509 *x,
1151cb0ef41Sopenharmony_ci                     size_t chainidx)
1161cb0ef41Sopenharmony_ci{
1171cb0ef41Sopenharmony_ci    int al;
1181cb0ef41Sopenharmony_ci    custom_ext_methods *exts = &s->cert->custext;
1191cb0ef41Sopenharmony_ci    custom_ext_method *meth;
1201cb0ef41Sopenharmony_ci    ENDPOINT role = ENDPOINT_BOTH;
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci    if ((context & (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO)) != 0)
1231cb0ef41Sopenharmony_ci        role = s->server ? ENDPOINT_SERVER : ENDPOINT_CLIENT;
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci    meth = custom_ext_find(exts, role, ext_type, NULL);
1261cb0ef41Sopenharmony_ci    /* If not found return success */
1271cb0ef41Sopenharmony_ci    if (!meth)
1281cb0ef41Sopenharmony_ci        return 1;
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci    /* Check if extension is defined for our protocol. If not, skip */
1311cb0ef41Sopenharmony_ci    if (!extension_is_relevant(s, meth->context, context))
1321cb0ef41Sopenharmony_ci        return 1;
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    if ((context & (SSL_EXT_TLS1_2_SERVER_HELLO
1351cb0ef41Sopenharmony_ci                    | SSL_EXT_TLS1_3_SERVER_HELLO
1361cb0ef41Sopenharmony_ci                    | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS)) != 0) {
1371cb0ef41Sopenharmony_ci        /*
1381cb0ef41Sopenharmony_ci         * If it's ServerHello or EncryptedExtensions we can't have any
1391cb0ef41Sopenharmony_ci         * extensions not sent in ClientHello.
1401cb0ef41Sopenharmony_ci         */
1411cb0ef41Sopenharmony_ci        if ((meth->ext_flags & SSL_EXT_FLAG_SENT) == 0) {
1421cb0ef41Sopenharmony_ci            SSLfatal(s, TLS1_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION);
1431cb0ef41Sopenharmony_ci            return 0;
1441cb0ef41Sopenharmony_ci        }
1451cb0ef41Sopenharmony_ci    }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci    /*
1481cb0ef41Sopenharmony_ci     * Extensions received in the ClientHello or CertificateRequest are marked
1491cb0ef41Sopenharmony_ci     * with the SSL_EXT_FLAG_RECEIVED. This is so we know to add the equivalent
1501cb0ef41Sopenharmony_ci     * extensions in the response messages
1511cb0ef41Sopenharmony_ci     */
1521cb0ef41Sopenharmony_ci    if ((context & (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST))
1531cb0ef41Sopenharmony_ci            != 0)
1541cb0ef41Sopenharmony_ci        meth->ext_flags |= SSL_EXT_FLAG_RECEIVED;
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci    /* If no parse function set return success */
1571cb0ef41Sopenharmony_ci    if (!meth->parse_cb)
1581cb0ef41Sopenharmony_ci        return 1;
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci    if (meth->parse_cb(s, ext_type, context, ext_data, ext_size, x, chainidx,
1611cb0ef41Sopenharmony_ci                       &al, meth->parse_arg) <= 0) {
1621cb0ef41Sopenharmony_ci        SSLfatal(s, al, SSL_R_BAD_EXTENSION);
1631cb0ef41Sopenharmony_ci        return 0;
1641cb0ef41Sopenharmony_ci    }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci    return 1;
1671cb0ef41Sopenharmony_ci}
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci/*
1701cb0ef41Sopenharmony_ci * Request custom extension data from the application and add to the return
1711cb0ef41Sopenharmony_ci * buffer.
1721cb0ef41Sopenharmony_ci */
1731cb0ef41Sopenharmony_ciint custom_ext_add(SSL *s, int context, WPACKET *pkt, X509 *x, size_t chainidx,
1741cb0ef41Sopenharmony_ci                   int maxversion)
1751cb0ef41Sopenharmony_ci{
1761cb0ef41Sopenharmony_ci    custom_ext_methods *exts = &s->cert->custext;
1771cb0ef41Sopenharmony_ci    custom_ext_method *meth;
1781cb0ef41Sopenharmony_ci    size_t i;
1791cb0ef41Sopenharmony_ci    int al;
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci    for (i = 0; i < exts->meths_count; i++) {
1821cb0ef41Sopenharmony_ci        const unsigned char *out = NULL;
1831cb0ef41Sopenharmony_ci        size_t outlen = 0;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci        meth = exts->meths + i;
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci        if (!should_add_extension(s, meth->context, context, maxversion))
1881cb0ef41Sopenharmony_ci            continue;
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci        if ((context & (SSL_EXT_TLS1_2_SERVER_HELLO
1911cb0ef41Sopenharmony_ci                        | SSL_EXT_TLS1_3_SERVER_HELLO
1921cb0ef41Sopenharmony_ci                        | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
1931cb0ef41Sopenharmony_ci                        | SSL_EXT_TLS1_3_CERTIFICATE
1941cb0ef41Sopenharmony_ci                        | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST)) != 0) {
1951cb0ef41Sopenharmony_ci            /* Only send extensions present in ClientHello/CertificateRequest */
1961cb0ef41Sopenharmony_ci            if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED))
1971cb0ef41Sopenharmony_ci                continue;
1981cb0ef41Sopenharmony_ci        }
1991cb0ef41Sopenharmony_ci        /*
2001cb0ef41Sopenharmony_ci         * We skip it if the callback is absent - except for a ClientHello where
2011cb0ef41Sopenharmony_ci         * we add an empty extension.
2021cb0ef41Sopenharmony_ci         */
2031cb0ef41Sopenharmony_ci        if ((context & SSL_EXT_CLIENT_HELLO) == 0 && meth->add_cb == NULL)
2041cb0ef41Sopenharmony_ci            continue;
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci        if (meth->add_cb != NULL) {
2071cb0ef41Sopenharmony_ci            int cb_retval = meth->add_cb(s, meth->ext_type, context, &out,
2081cb0ef41Sopenharmony_ci                                         &outlen, x, chainidx, &al,
2091cb0ef41Sopenharmony_ci                                         meth->add_arg);
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci            if (cb_retval < 0) {
2121cb0ef41Sopenharmony_ci                SSLfatal(s, al, SSL_R_CALLBACK_FAILED);
2131cb0ef41Sopenharmony_ci                return 0;       /* error */
2141cb0ef41Sopenharmony_ci            }
2151cb0ef41Sopenharmony_ci            if (cb_retval == 0)
2161cb0ef41Sopenharmony_ci                continue;       /* skip this extension */
2171cb0ef41Sopenharmony_ci        }
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci        if (!WPACKET_put_bytes_u16(pkt, meth->ext_type)
2201cb0ef41Sopenharmony_ci                || !WPACKET_start_sub_packet_u16(pkt)
2211cb0ef41Sopenharmony_ci                || (outlen > 0 && !WPACKET_memcpy(pkt, out, outlen))
2221cb0ef41Sopenharmony_ci                || !WPACKET_close(pkt)) {
2231cb0ef41Sopenharmony_ci            if (meth->free_cb != NULL)
2241cb0ef41Sopenharmony_ci                meth->free_cb(s, meth->ext_type, context, out, meth->add_arg);
2251cb0ef41Sopenharmony_ci            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
2261cb0ef41Sopenharmony_ci            return 0;
2271cb0ef41Sopenharmony_ci        }
2281cb0ef41Sopenharmony_ci        if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
2291cb0ef41Sopenharmony_ci            /*
2301cb0ef41Sopenharmony_ci             * We can't send duplicates: code logic should prevent this.
2311cb0ef41Sopenharmony_ci             */
2321cb0ef41Sopenharmony_ci            if (!ossl_assert((meth->ext_flags & SSL_EXT_FLAG_SENT) == 0)) {
2331cb0ef41Sopenharmony_ci                if (meth->free_cb != NULL)
2341cb0ef41Sopenharmony_ci                    meth->free_cb(s, meth->ext_type, context, out,
2351cb0ef41Sopenharmony_ci                                  meth->add_arg);
2361cb0ef41Sopenharmony_ci                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
2371cb0ef41Sopenharmony_ci                return 0;
2381cb0ef41Sopenharmony_ci            }
2391cb0ef41Sopenharmony_ci            /*
2401cb0ef41Sopenharmony_ci             * Indicate extension has been sent: this is both a sanity check to
2411cb0ef41Sopenharmony_ci             * ensure we don't send duplicate extensions and indicates that it
2421cb0ef41Sopenharmony_ci             * is not an error if the extension is present in ServerHello.
2431cb0ef41Sopenharmony_ci             */
2441cb0ef41Sopenharmony_ci            meth->ext_flags |= SSL_EXT_FLAG_SENT;
2451cb0ef41Sopenharmony_ci        }
2461cb0ef41Sopenharmony_ci        if (meth->free_cb != NULL)
2471cb0ef41Sopenharmony_ci            meth->free_cb(s, meth->ext_type, context, out, meth->add_arg);
2481cb0ef41Sopenharmony_ci    }
2491cb0ef41Sopenharmony_ci    return 1;
2501cb0ef41Sopenharmony_ci}
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci/* Copy the flags from src to dst for any extensions that exist in both */
2531cb0ef41Sopenharmony_ciint custom_exts_copy_flags(custom_ext_methods *dst,
2541cb0ef41Sopenharmony_ci                           const custom_ext_methods *src)
2551cb0ef41Sopenharmony_ci{
2561cb0ef41Sopenharmony_ci    size_t i;
2571cb0ef41Sopenharmony_ci    custom_ext_method *methsrc = src->meths;
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci    for (i = 0; i < src->meths_count; i++, methsrc++) {
2601cb0ef41Sopenharmony_ci        custom_ext_method *methdst = custom_ext_find(dst, methsrc->role,
2611cb0ef41Sopenharmony_ci                                                     methsrc->ext_type, NULL);
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci        if (methdst == NULL)
2641cb0ef41Sopenharmony_ci            continue;
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci        methdst->ext_flags = methsrc->ext_flags;
2671cb0ef41Sopenharmony_ci    }
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci    return 1;
2701cb0ef41Sopenharmony_ci}
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci/* Copy table of custom extensions */
2731cb0ef41Sopenharmony_ciint custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
2741cb0ef41Sopenharmony_ci{
2751cb0ef41Sopenharmony_ci    size_t i;
2761cb0ef41Sopenharmony_ci    int err = 0;
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci    if (src->meths_count > 0) {
2791cb0ef41Sopenharmony_ci        dst->meths =
2801cb0ef41Sopenharmony_ci            OPENSSL_memdup(src->meths,
2811cb0ef41Sopenharmony_ci                           sizeof(*src->meths) * src->meths_count);
2821cb0ef41Sopenharmony_ci        if (dst->meths == NULL)
2831cb0ef41Sopenharmony_ci            return 0;
2841cb0ef41Sopenharmony_ci        dst->meths_count = src->meths_count;
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci        for (i = 0; i < src->meths_count; i++) {
2871cb0ef41Sopenharmony_ci            custom_ext_method *methsrc = src->meths + i;
2881cb0ef41Sopenharmony_ci            custom_ext_method *methdst = dst->meths + i;
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci            if (methsrc->add_cb != custom_ext_add_old_cb_wrap)
2911cb0ef41Sopenharmony_ci                continue;
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci            /*
2941cb0ef41Sopenharmony_ci             * We have found an old style API wrapper. We need to copy the
2951cb0ef41Sopenharmony_ci             * arguments too.
2961cb0ef41Sopenharmony_ci             */
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci            if (err) {
2991cb0ef41Sopenharmony_ci                methdst->add_arg = NULL;
3001cb0ef41Sopenharmony_ci                methdst->parse_arg = NULL;
3011cb0ef41Sopenharmony_ci                continue;
3021cb0ef41Sopenharmony_ci            }
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci            methdst->add_arg = OPENSSL_memdup(methsrc->add_arg,
3051cb0ef41Sopenharmony_ci                                              sizeof(custom_ext_add_cb_wrap));
3061cb0ef41Sopenharmony_ci            methdst->parse_arg = OPENSSL_memdup(methsrc->parse_arg,
3071cb0ef41Sopenharmony_ci                                            sizeof(custom_ext_parse_cb_wrap));
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ci            if (methdst->add_arg == NULL || methdst->parse_arg == NULL)
3101cb0ef41Sopenharmony_ci                err = 1;
3111cb0ef41Sopenharmony_ci        }
3121cb0ef41Sopenharmony_ci    }
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci    if (err) {
3151cb0ef41Sopenharmony_ci        custom_exts_free(dst);
3161cb0ef41Sopenharmony_ci        return 0;
3171cb0ef41Sopenharmony_ci    }
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci    return 1;
3201cb0ef41Sopenharmony_ci}
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_civoid custom_exts_free(custom_ext_methods *exts)
3231cb0ef41Sopenharmony_ci{
3241cb0ef41Sopenharmony_ci    size_t i;
3251cb0ef41Sopenharmony_ci    custom_ext_method *meth;
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci    for (i = 0, meth = exts->meths; i < exts->meths_count; i++, meth++) {
3281cb0ef41Sopenharmony_ci        if (meth->add_cb != custom_ext_add_old_cb_wrap)
3291cb0ef41Sopenharmony_ci            continue;
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci        /* Old style API wrapper. Need to free the arguments too */
3321cb0ef41Sopenharmony_ci        OPENSSL_free(meth->add_arg);
3331cb0ef41Sopenharmony_ci        OPENSSL_free(meth->parse_arg);
3341cb0ef41Sopenharmony_ci    }
3351cb0ef41Sopenharmony_ci    OPENSSL_free(exts->meths);
3361cb0ef41Sopenharmony_ci    exts->meths = NULL;
3371cb0ef41Sopenharmony_ci    exts->meths_count = 0;
3381cb0ef41Sopenharmony_ci}
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci/* Return true if a client custom extension exists, false otherwise */
3411cb0ef41Sopenharmony_ciint SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx, unsigned int ext_type)
3421cb0ef41Sopenharmony_ci{
3431cb0ef41Sopenharmony_ci    return custom_ext_find(&ctx->cert->custext, ENDPOINT_CLIENT, ext_type,
3441cb0ef41Sopenharmony_ci                           NULL) != NULL;
3451cb0ef41Sopenharmony_ci}
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_cistatic int add_custom_ext_intern(SSL_CTX *ctx, ENDPOINT role,
3481cb0ef41Sopenharmony_ci                                 unsigned int ext_type,
3491cb0ef41Sopenharmony_ci                                 unsigned int context,
3501cb0ef41Sopenharmony_ci                                 SSL_custom_ext_add_cb_ex add_cb,
3511cb0ef41Sopenharmony_ci                                 SSL_custom_ext_free_cb_ex free_cb,
3521cb0ef41Sopenharmony_ci                                 void *add_arg,
3531cb0ef41Sopenharmony_ci                                 SSL_custom_ext_parse_cb_ex parse_cb,
3541cb0ef41Sopenharmony_ci                                 void *parse_arg)
3551cb0ef41Sopenharmony_ci{
3561cb0ef41Sopenharmony_ci    custom_ext_methods *exts = &ctx->cert->custext;
3571cb0ef41Sopenharmony_ci    custom_ext_method *meth, *tmp;
3581cb0ef41Sopenharmony_ci
3591cb0ef41Sopenharmony_ci    /*
3601cb0ef41Sopenharmony_ci     * Check application error: if add_cb is not set free_cb will never be
3611cb0ef41Sopenharmony_ci     * called.
3621cb0ef41Sopenharmony_ci     */
3631cb0ef41Sopenharmony_ci    if (add_cb == NULL && free_cb != NULL)
3641cb0ef41Sopenharmony_ci        return 0;
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_ci#ifndef OPENSSL_NO_CT
3671cb0ef41Sopenharmony_ci    /*
3681cb0ef41Sopenharmony_ci     * We don't want applications registering callbacks for SCT extensions
3691cb0ef41Sopenharmony_ci     * whilst simultaneously using the built-in SCT validation features, as
3701cb0ef41Sopenharmony_ci     * these two things may not play well together.
3711cb0ef41Sopenharmony_ci     */
3721cb0ef41Sopenharmony_ci    if (ext_type == TLSEXT_TYPE_signed_certificate_timestamp
3731cb0ef41Sopenharmony_ci            && (context & SSL_EXT_CLIENT_HELLO) != 0
3741cb0ef41Sopenharmony_ci            && SSL_CTX_ct_is_enabled(ctx))
3751cb0ef41Sopenharmony_ci        return 0;
3761cb0ef41Sopenharmony_ci#endif
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci    /*
3791cb0ef41Sopenharmony_ci     * Don't add if extension supported internally, but make exception
3801cb0ef41Sopenharmony_ci     * for extension types that previously were not supported, but now are.
3811cb0ef41Sopenharmony_ci     */
3821cb0ef41Sopenharmony_ci    if (SSL_extension_supported(ext_type)
3831cb0ef41Sopenharmony_ci            && ext_type != TLSEXT_TYPE_signed_certificate_timestamp)
3841cb0ef41Sopenharmony_ci        return 0;
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci    /* Extension type must fit in 16 bits */
3871cb0ef41Sopenharmony_ci    if (ext_type > 0xffff)
3881cb0ef41Sopenharmony_ci        return 0;
3891cb0ef41Sopenharmony_ci    /* Search for duplicate */
3901cb0ef41Sopenharmony_ci    if (custom_ext_find(exts, role, ext_type, NULL))
3911cb0ef41Sopenharmony_ci        return 0;
3921cb0ef41Sopenharmony_ci    tmp = OPENSSL_realloc(exts->meths,
3931cb0ef41Sopenharmony_ci                          (exts->meths_count + 1) * sizeof(custom_ext_method));
3941cb0ef41Sopenharmony_ci    if (tmp == NULL)
3951cb0ef41Sopenharmony_ci        return 0;
3961cb0ef41Sopenharmony_ci
3971cb0ef41Sopenharmony_ci    exts->meths = tmp;
3981cb0ef41Sopenharmony_ci    meth = exts->meths + exts->meths_count;
3991cb0ef41Sopenharmony_ci    memset(meth, 0, sizeof(*meth));
4001cb0ef41Sopenharmony_ci    meth->role = role;
4011cb0ef41Sopenharmony_ci    meth->context = context;
4021cb0ef41Sopenharmony_ci    meth->parse_cb = parse_cb;
4031cb0ef41Sopenharmony_ci    meth->add_cb = add_cb;
4041cb0ef41Sopenharmony_ci    meth->free_cb = free_cb;
4051cb0ef41Sopenharmony_ci    meth->ext_type = ext_type;
4061cb0ef41Sopenharmony_ci    meth->add_arg = add_arg;
4071cb0ef41Sopenharmony_ci    meth->parse_arg = parse_arg;
4081cb0ef41Sopenharmony_ci    exts->meths_count++;
4091cb0ef41Sopenharmony_ci    return 1;
4101cb0ef41Sopenharmony_ci}
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_cistatic int add_old_custom_ext(SSL_CTX *ctx, ENDPOINT role,
4131cb0ef41Sopenharmony_ci                              unsigned int ext_type,
4141cb0ef41Sopenharmony_ci                              unsigned int context,
4151cb0ef41Sopenharmony_ci                              custom_ext_add_cb add_cb,
4161cb0ef41Sopenharmony_ci                              custom_ext_free_cb free_cb,
4171cb0ef41Sopenharmony_ci                              void *add_arg,
4181cb0ef41Sopenharmony_ci                              custom_ext_parse_cb parse_cb, void *parse_arg)
4191cb0ef41Sopenharmony_ci{
4201cb0ef41Sopenharmony_ci    custom_ext_add_cb_wrap *add_cb_wrap
4211cb0ef41Sopenharmony_ci        = OPENSSL_malloc(sizeof(*add_cb_wrap));
4221cb0ef41Sopenharmony_ci    custom_ext_parse_cb_wrap *parse_cb_wrap
4231cb0ef41Sopenharmony_ci        = OPENSSL_malloc(sizeof(*parse_cb_wrap));
4241cb0ef41Sopenharmony_ci    int ret;
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci    if (add_cb_wrap == NULL || parse_cb_wrap == NULL) {
4271cb0ef41Sopenharmony_ci        OPENSSL_free(add_cb_wrap);
4281cb0ef41Sopenharmony_ci        OPENSSL_free(parse_cb_wrap);
4291cb0ef41Sopenharmony_ci        return 0;
4301cb0ef41Sopenharmony_ci    }
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci    add_cb_wrap->add_arg = add_arg;
4331cb0ef41Sopenharmony_ci    add_cb_wrap->add_cb = add_cb;
4341cb0ef41Sopenharmony_ci    add_cb_wrap->free_cb = free_cb;
4351cb0ef41Sopenharmony_ci    parse_cb_wrap->parse_arg = parse_arg;
4361cb0ef41Sopenharmony_ci    parse_cb_wrap->parse_cb = parse_cb;
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci    ret = add_custom_ext_intern(ctx, role, ext_type,
4391cb0ef41Sopenharmony_ci                                context,
4401cb0ef41Sopenharmony_ci                                custom_ext_add_old_cb_wrap,
4411cb0ef41Sopenharmony_ci                                custom_ext_free_old_cb_wrap,
4421cb0ef41Sopenharmony_ci                                add_cb_wrap,
4431cb0ef41Sopenharmony_ci                                custom_ext_parse_old_cb_wrap,
4441cb0ef41Sopenharmony_ci                                parse_cb_wrap);
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci    if (!ret) {
4471cb0ef41Sopenharmony_ci        OPENSSL_free(add_cb_wrap);
4481cb0ef41Sopenharmony_ci        OPENSSL_free(parse_cb_wrap);
4491cb0ef41Sopenharmony_ci    }
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci    return ret;
4521cb0ef41Sopenharmony_ci}
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci/* Application level functions to add the old custom extension callbacks */
4551cb0ef41Sopenharmony_ciint SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
4561cb0ef41Sopenharmony_ci                                  custom_ext_add_cb add_cb,
4571cb0ef41Sopenharmony_ci                                  custom_ext_free_cb free_cb,
4581cb0ef41Sopenharmony_ci                                  void *add_arg,
4591cb0ef41Sopenharmony_ci                                  custom_ext_parse_cb parse_cb, void *parse_arg)
4601cb0ef41Sopenharmony_ci{
4611cb0ef41Sopenharmony_ci    return add_old_custom_ext(ctx, ENDPOINT_CLIENT, ext_type,
4621cb0ef41Sopenharmony_ci                              SSL_EXT_TLS1_2_AND_BELOW_ONLY
4631cb0ef41Sopenharmony_ci                              | SSL_EXT_CLIENT_HELLO
4641cb0ef41Sopenharmony_ci                              | SSL_EXT_TLS1_2_SERVER_HELLO
4651cb0ef41Sopenharmony_ci                              | SSL_EXT_IGNORE_ON_RESUMPTION,
4661cb0ef41Sopenharmony_ci                              add_cb, free_cb, add_arg, parse_cb, parse_arg);
4671cb0ef41Sopenharmony_ci}
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ciint SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
4701cb0ef41Sopenharmony_ci                                  custom_ext_add_cb add_cb,
4711cb0ef41Sopenharmony_ci                                  custom_ext_free_cb free_cb,
4721cb0ef41Sopenharmony_ci                                  void *add_arg,
4731cb0ef41Sopenharmony_ci                                  custom_ext_parse_cb parse_cb, void *parse_arg)
4741cb0ef41Sopenharmony_ci{
4751cb0ef41Sopenharmony_ci    return add_old_custom_ext(ctx, ENDPOINT_SERVER, ext_type,
4761cb0ef41Sopenharmony_ci                              SSL_EXT_TLS1_2_AND_BELOW_ONLY
4771cb0ef41Sopenharmony_ci                              | SSL_EXT_CLIENT_HELLO
4781cb0ef41Sopenharmony_ci                              | SSL_EXT_TLS1_2_SERVER_HELLO
4791cb0ef41Sopenharmony_ci                              | SSL_EXT_IGNORE_ON_RESUMPTION,
4801cb0ef41Sopenharmony_ci                              add_cb, free_cb, add_arg, parse_cb, parse_arg);
4811cb0ef41Sopenharmony_ci}
4821cb0ef41Sopenharmony_ci
4831cb0ef41Sopenharmony_ciint SSL_CTX_add_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
4841cb0ef41Sopenharmony_ci                           unsigned int context,
4851cb0ef41Sopenharmony_ci                           SSL_custom_ext_add_cb_ex add_cb,
4861cb0ef41Sopenharmony_ci                           SSL_custom_ext_free_cb_ex free_cb,
4871cb0ef41Sopenharmony_ci                           void *add_arg,
4881cb0ef41Sopenharmony_ci                           SSL_custom_ext_parse_cb_ex parse_cb, void *parse_arg)
4891cb0ef41Sopenharmony_ci{
4901cb0ef41Sopenharmony_ci    return add_custom_ext_intern(ctx, ENDPOINT_BOTH, ext_type, context, add_cb,
4911cb0ef41Sopenharmony_ci                                 free_cb, add_arg, parse_cb, parse_arg);
4921cb0ef41Sopenharmony_ci}
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_ciint SSL_extension_supported(unsigned int ext_type)
4951cb0ef41Sopenharmony_ci{
4961cb0ef41Sopenharmony_ci    switch (ext_type) {
4971cb0ef41Sopenharmony_ci        /* Internally supported extensions. */
4981cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_application_layer_protocol_negotiation:
4991cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_ec_point_formats:
5001cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_supported_groups:
5011cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_key_share:
5021cb0ef41Sopenharmony_ci#ifndef OPENSSL_NO_NEXTPROTONEG
5031cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_next_proto_neg:
5041cb0ef41Sopenharmony_ci#endif
5051cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_padding:
5061cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_renegotiate:
5071cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_max_fragment_length:
5081cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_server_name:
5091cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_session_ticket:
5101cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_signature_algorithms:
5111cb0ef41Sopenharmony_ci#ifndef OPENSSL_NO_SRP
5121cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_srp:
5131cb0ef41Sopenharmony_ci#endif
5141cb0ef41Sopenharmony_ci#ifndef OPENSSL_NO_OCSP
5151cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_status_request:
5161cb0ef41Sopenharmony_ci#endif
5171cb0ef41Sopenharmony_ci#ifndef OPENSSL_NO_CT
5181cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_signed_certificate_timestamp:
5191cb0ef41Sopenharmony_ci#endif
5201cb0ef41Sopenharmony_ci#ifndef OPENSSL_NO_SRTP
5211cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_use_srtp:
5221cb0ef41Sopenharmony_ci#endif
5231cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_encrypt_then_mac:
5241cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_supported_versions:
5251cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_extended_master_secret:
5261cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_psk_kex_modes:
5271cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_cookie:
5281cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_early_data:
5291cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_certificate_authorities:
5301cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_psk:
5311cb0ef41Sopenharmony_ci    case TLSEXT_TYPE_post_handshake_auth:
5321cb0ef41Sopenharmony_ci        return 1;
5331cb0ef41Sopenharmony_ci    default:
5341cb0ef41Sopenharmony_ci        return 0;
5351cb0ef41Sopenharmony_ci    }
5361cb0ef41Sopenharmony_ci}
537