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