xref: /freebsd/crypto/openssl/ssl/statem/extensions_cust.c (revision b2bf0c7e5f4037d63458def91a026592468afd2f)
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