1e71b7053SJung-uk Kim /*
2b2bf0c7eSJung-uk Kim  * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (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  */
custom_ext_add_old_cb_wrap(SSL * s,unsigned int ext_type,unsigned int context,const unsigned char ** out,size_t * outlen,X509 * x,size_t chainidx,int * al,void * add_arg)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 
custom_ext_free_old_cb_wrap(SSL * s,unsigned int ext_type,unsigned int context,const unsigned char * out,void * add_arg)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 
custom_ext_parse_old_cb_wrap(SSL * s,unsigned int ext_type,unsigned int context,const unsigned char * in,size_t inlen,X509 * x,size_t chainidx,int * al,void * parse_arg)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  */
custom_ext_find(const custom_ext_methods * exts,ENDPOINT role,unsigned int ext_type,size_t * idx)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  */
custom_ext_init(custom_ext_methods * exts)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. */
custom_ext_parse(SSL * s,unsigned int context,unsigned int ext_type,const unsigned char * ext_data,size_t ext_size,X509 * x,size_t chainidx)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) {
142b077aed3SPierre Pronchery             SSLfatal(s, TLS1_AD_UNSUPPORTED_EXTENSION, SSL_R_BAD_EXTENSION);
143e71b7053SJung-uk Kim             return 0;
144e71b7053SJung-uk Kim         }
145e71b7053SJung-uk Kim     }
146e71b7053SJung-uk Kim 
147e71b7053SJung-uk Kim     /*
148b2bf0c7eSJung-uk Kim      * Extensions received in the ClientHello or CertificateRequest are marked
149b2bf0c7eSJung-uk Kim      * with the SSL_EXT_FLAG_RECEIVED. This is so we know to add the equivalent
150b2bf0c7eSJung-uk Kim      * extensions in the response messages
151e71b7053SJung-uk Kim      */
152b2bf0c7eSJung-uk Kim     if ((context & (SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST))
153b2bf0c7eSJung-uk Kim             != 0)
154e71b7053SJung-uk Kim         meth->ext_flags |= SSL_EXT_FLAG_RECEIVED;
155e71b7053SJung-uk Kim 
156e71b7053SJung-uk Kim     /* If no parse function set return success */
157e71b7053SJung-uk Kim     if (!meth->parse_cb)
158e71b7053SJung-uk Kim         return 1;
159e71b7053SJung-uk Kim 
160e71b7053SJung-uk Kim     if (meth->parse_cb(s, ext_type, context, ext_data, ext_size, x, chainidx,
161e71b7053SJung-uk Kim                        &al, meth->parse_arg) <= 0) {
162b077aed3SPierre Pronchery         SSLfatal(s, al, SSL_R_BAD_EXTENSION);
163e71b7053SJung-uk Kim         return 0;
164e71b7053SJung-uk Kim     }
165e71b7053SJung-uk Kim 
166e71b7053SJung-uk Kim     return 1;
167e71b7053SJung-uk Kim }
168e71b7053SJung-uk Kim 
169e71b7053SJung-uk Kim /*
170e71b7053SJung-uk Kim  * Request custom extension data from the application and add to the return
171e71b7053SJung-uk Kim  * buffer.
172e71b7053SJung-uk Kim  */
custom_ext_add(SSL * s,int context,WPACKET * pkt,X509 * x,size_t chainidx,int maxversion)173e71b7053SJung-uk Kim int custom_ext_add(SSL *s, int context, WPACKET *pkt, X509 *x, size_t chainidx,
174e71b7053SJung-uk Kim                    int maxversion)
175e71b7053SJung-uk Kim {
176e71b7053SJung-uk Kim     custom_ext_methods *exts = &s->cert->custext;
177e71b7053SJung-uk Kim     custom_ext_method *meth;
178e71b7053SJung-uk Kim     size_t i;
179e71b7053SJung-uk Kim     int al;
180e71b7053SJung-uk Kim 
181e71b7053SJung-uk Kim     for (i = 0; i < exts->meths_count; i++) {
182e71b7053SJung-uk Kim         const unsigned char *out = NULL;
183e71b7053SJung-uk Kim         size_t outlen = 0;
184e71b7053SJung-uk Kim 
185e71b7053SJung-uk Kim         meth = exts->meths + i;
186e71b7053SJung-uk Kim 
187e71b7053SJung-uk Kim         if (!should_add_extension(s, meth->context, context, maxversion))
188e71b7053SJung-uk Kim             continue;
189e71b7053SJung-uk Kim 
190e71b7053SJung-uk Kim         if ((context & (SSL_EXT_TLS1_2_SERVER_HELLO
191e71b7053SJung-uk Kim                         | SSL_EXT_TLS1_3_SERVER_HELLO
192e71b7053SJung-uk Kim                         | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
193e71b7053SJung-uk Kim                         | SSL_EXT_TLS1_3_CERTIFICATE
194e71b7053SJung-uk Kim                         | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST)) != 0) {
195b2bf0c7eSJung-uk Kim             /* Only send extensions present in ClientHello/CertificateRequest */
196e71b7053SJung-uk Kim             if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED))
197e71b7053SJung-uk Kim                 continue;
198e71b7053SJung-uk Kim         }
199e71b7053SJung-uk Kim         /*
200e71b7053SJung-uk Kim          * We skip it if the callback is absent - except for a ClientHello where
201e71b7053SJung-uk Kim          * we add an empty extension.
202e71b7053SJung-uk Kim          */
203e71b7053SJung-uk Kim         if ((context & SSL_EXT_CLIENT_HELLO) == 0 && meth->add_cb == NULL)
204e71b7053SJung-uk Kim             continue;
205e71b7053SJung-uk Kim 
206e71b7053SJung-uk Kim         if (meth->add_cb != NULL) {
207e71b7053SJung-uk Kim             int cb_retval = meth->add_cb(s, meth->ext_type, context, &out,
208e71b7053SJung-uk Kim                                          &outlen, x, chainidx, &al,
209e71b7053SJung-uk Kim                                          meth->add_arg);
210e71b7053SJung-uk Kim 
211e71b7053SJung-uk Kim             if (cb_retval < 0) {
212b077aed3SPierre Pronchery                 SSLfatal(s, al, SSL_R_CALLBACK_FAILED);
213e71b7053SJung-uk Kim                 return 0;       /* error */
214e71b7053SJung-uk Kim             }
215e71b7053SJung-uk Kim             if (cb_retval == 0)
216e71b7053SJung-uk Kim                 continue;       /* skip this extension */
217e71b7053SJung-uk Kim         }
218e71b7053SJung-uk Kim 
219e71b7053SJung-uk Kim         if (!WPACKET_put_bytes_u16(pkt, meth->ext_type)
220e71b7053SJung-uk Kim                 || !WPACKET_start_sub_packet_u16(pkt)
221e71b7053SJung-uk Kim                 || (outlen > 0 && !WPACKET_memcpy(pkt, out, outlen))
222e71b7053SJung-uk Kim                 || !WPACKET_close(pkt)) {
223e0c4386eSCy Schubert             if (meth->free_cb != NULL)
224e0c4386eSCy Schubert                 meth->free_cb(s, meth->ext_type, context, out, meth->add_arg);
225b077aed3SPierre Pronchery             SSLfatal(s, SSL_AD_INTERNAL_ERROR, 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)) {
233e0c4386eSCy Schubert                 if (meth->free_cb != NULL)
234e0c4386eSCy Schubert                     meth->free_cb(s, meth->ext_type, context, out,
235e0c4386eSCy Schubert                                   meth->add_arg);
236b077aed3SPierre Pronchery                 SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
237e71b7053SJung-uk Kim                 return 0;
238e71b7053SJung-uk Kim             }
239e71b7053SJung-uk Kim             /*
240e71b7053SJung-uk Kim              * Indicate extension has been sent: this is both a sanity check to
241e71b7053SJung-uk Kim              * ensure we don't send duplicate extensions and indicates that it
242e71b7053SJung-uk Kim              * is not an error if the extension is present in ServerHello.
243e71b7053SJung-uk Kim              */
244e71b7053SJung-uk Kim             meth->ext_flags |= SSL_EXT_FLAG_SENT;
245e71b7053SJung-uk Kim         }
246e71b7053SJung-uk Kim         if (meth->free_cb != NULL)
247e71b7053SJung-uk Kim             meth->free_cb(s, meth->ext_type, context, out, meth->add_arg);
248e71b7053SJung-uk Kim     }
249e71b7053SJung-uk Kim     return 1;
250e71b7053SJung-uk Kim }
251e71b7053SJung-uk Kim 
252e71b7053SJung-uk Kim /* Copy the flags from src to dst for any extensions that exist in both */
custom_exts_copy_flags(custom_ext_methods * dst,const custom_ext_methods * src)253e71b7053SJung-uk Kim int custom_exts_copy_flags(custom_ext_methods *dst,
254e71b7053SJung-uk Kim                            const custom_ext_methods *src)
255e71b7053SJung-uk Kim {
256e71b7053SJung-uk Kim     size_t i;
257e71b7053SJung-uk Kim     custom_ext_method *methsrc = src->meths;
258e71b7053SJung-uk Kim 
259e71b7053SJung-uk Kim     for (i = 0; i < src->meths_count; i++, methsrc++) {
260e71b7053SJung-uk Kim         custom_ext_method *methdst = custom_ext_find(dst, methsrc->role,
261e71b7053SJung-uk Kim                                                      methsrc->ext_type, NULL);
262e71b7053SJung-uk Kim 
263e71b7053SJung-uk Kim         if (methdst == NULL)
264e71b7053SJung-uk Kim             continue;
265e71b7053SJung-uk Kim 
266e71b7053SJung-uk Kim         methdst->ext_flags = methsrc->ext_flags;
267e71b7053SJung-uk Kim     }
268e71b7053SJung-uk Kim 
269e71b7053SJung-uk Kim     return 1;
270e71b7053SJung-uk Kim }
271e71b7053SJung-uk Kim 
272e71b7053SJung-uk Kim /* Copy table of custom extensions */
custom_exts_copy(custom_ext_methods * dst,const custom_ext_methods * src)273e71b7053SJung-uk Kim int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
274e71b7053SJung-uk Kim {
275e71b7053SJung-uk Kim     size_t i;
276e71b7053SJung-uk Kim     int err = 0;
277e71b7053SJung-uk Kim 
278e71b7053SJung-uk Kim     if (src->meths_count > 0) {
279e71b7053SJung-uk Kim         dst->meths =
280e71b7053SJung-uk Kim             OPENSSL_memdup(src->meths,
281e71b7053SJung-uk Kim                            sizeof(*src->meths) * src->meths_count);
282e71b7053SJung-uk Kim         if (dst->meths == NULL)
283e71b7053SJung-uk Kim             return 0;
284e71b7053SJung-uk Kim         dst->meths_count = src->meths_count;
285e71b7053SJung-uk Kim 
286e71b7053SJung-uk Kim         for (i = 0; i < src->meths_count; i++) {
287e71b7053SJung-uk Kim             custom_ext_method *methsrc = src->meths + i;
288e71b7053SJung-uk Kim             custom_ext_method *methdst = dst->meths + i;
289e71b7053SJung-uk Kim 
290e71b7053SJung-uk Kim             if (methsrc->add_cb != custom_ext_add_old_cb_wrap)
291e71b7053SJung-uk Kim                 continue;
292e71b7053SJung-uk Kim 
293e71b7053SJung-uk Kim             /*
294e71b7053SJung-uk Kim              * We have found an old style API wrapper. We need to copy the
295e71b7053SJung-uk Kim              * arguments too.
296e71b7053SJung-uk Kim              */
297e71b7053SJung-uk Kim 
298e71b7053SJung-uk Kim             if (err) {
299e71b7053SJung-uk Kim                 methdst->add_arg = NULL;
300e71b7053SJung-uk Kim                 methdst->parse_arg = NULL;
301e71b7053SJung-uk Kim                 continue;
302e71b7053SJung-uk Kim             }
303e71b7053SJung-uk Kim 
304e71b7053SJung-uk Kim             methdst->add_arg = OPENSSL_memdup(methsrc->add_arg,
305e71b7053SJung-uk Kim                                               sizeof(custom_ext_add_cb_wrap));
306e71b7053SJung-uk Kim             methdst->parse_arg = OPENSSL_memdup(methsrc->parse_arg,
307e71b7053SJung-uk Kim                                             sizeof(custom_ext_parse_cb_wrap));
308e71b7053SJung-uk Kim 
309e71b7053SJung-uk Kim             if (methdst->add_arg == NULL || methdst->parse_arg == NULL)
310e71b7053SJung-uk Kim                 err = 1;
311e71b7053SJung-uk Kim         }
312e71b7053SJung-uk Kim     }
313e71b7053SJung-uk Kim 
314e71b7053SJung-uk Kim     if (err) {
315e71b7053SJung-uk Kim         custom_exts_free(dst);
316e71b7053SJung-uk Kim         return 0;
317e71b7053SJung-uk Kim     }
318e71b7053SJung-uk Kim 
319e71b7053SJung-uk Kim     return 1;
320e71b7053SJung-uk Kim }
321e71b7053SJung-uk Kim 
custom_exts_free(custom_ext_methods * exts)322e71b7053SJung-uk Kim void custom_exts_free(custom_ext_methods *exts)
323e71b7053SJung-uk Kim {
324e71b7053SJung-uk Kim     size_t i;
325e71b7053SJung-uk Kim     custom_ext_method *meth;
326e71b7053SJung-uk Kim 
327e71b7053SJung-uk Kim     for (i = 0, meth = exts->meths; i < exts->meths_count; i++, meth++) {
328e71b7053SJung-uk Kim         if (meth->add_cb != custom_ext_add_old_cb_wrap)
329e71b7053SJung-uk Kim             continue;
330e71b7053SJung-uk Kim 
331e71b7053SJung-uk Kim         /* Old style API wrapper. Need to free the arguments too */
332e71b7053SJung-uk Kim         OPENSSL_free(meth->add_arg);
333e71b7053SJung-uk Kim         OPENSSL_free(meth->parse_arg);
334e71b7053SJung-uk Kim     }
335e71b7053SJung-uk Kim     OPENSSL_free(exts->meths);
336e0c4386eSCy Schubert     exts->meths = NULL;
337e0c4386eSCy Schubert     exts->meths_count = 0;
338e71b7053SJung-uk Kim }
339e71b7053SJung-uk Kim 
340e71b7053SJung-uk Kim /* Return true if a client custom extension exists, false otherwise */
SSL_CTX_has_client_custom_ext(const SSL_CTX * ctx,unsigned int ext_type)341e71b7053SJung-uk Kim int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx, unsigned int ext_type)
342e71b7053SJung-uk Kim {
343e71b7053SJung-uk Kim     return custom_ext_find(&ctx->cert->custext, ENDPOINT_CLIENT, ext_type,
344e71b7053SJung-uk Kim                            NULL) != NULL;
345e71b7053SJung-uk Kim }
346e71b7053SJung-uk Kim 
add_custom_ext_intern(SSL_CTX * ctx,ENDPOINT role,unsigned int ext_type,unsigned int context,SSL_custom_ext_add_cb_ex add_cb,SSL_custom_ext_free_cb_ex free_cb,void * add_arg,SSL_custom_ext_parse_cb_ex parse_cb,void * parse_arg)347e71b7053SJung-uk Kim static int add_custom_ext_intern(SSL_CTX *ctx, ENDPOINT role,
348e71b7053SJung-uk Kim                                  unsigned int ext_type,
349e71b7053SJung-uk Kim                                  unsigned int context,
350e71b7053SJung-uk Kim                                  SSL_custom_ext_add_cb_ex add_cb,
351e71b7053SJung-uk Kim                                  SSL_custom_ext_free_cb_ex free_cb,
352e71b7053SJung-uk Kim                                  void *add_arg,
353e71b7053SJung-uk Kim                                  SSL_custom_ext_parse_cb_ex parse_cb,
354e71b7053SJung-uk Kim                                  void *parse_arg)
355e71b7053SJung-uk Kim {
356e71b7053SJung-uk Kim     custom_ext_methods *exts = &ctx->cert->custext;
357e71b7053SJung-uk Kim     custom_ext_method *meth, *tmp;
358e71b7053SJung-uk Kim 
359e71b7053SJung-uk Kim     /*
360e71b7053SJung-uk Kim      * Check application error: if add_cb is not set free_cb will never be
361e71b7053SJung-uk Kim      * called.
362e71b7053SJung-uk Kim      */
363e71b7053SJung-uk Kim     if (add_cb == NULL && free_cb != NULL)
364e71b7053SJung-uk Kim         return 0;
365e71b7053SJung-uk Kim 
366e71b7053SJung-uk Kim #ifndef OPENSSL_NO_CT
367e71b7053SJung-uk Kim     /*
368e71b7053SJung-uk Kim      * We don't want applications registering callbacks for SCT extensions
369e71b7053SJung-uk Kim      * whilst simultaneously using the built-in SCT validation features, as
370e71b7053SJung-uk Kim      * these two things may not play well together.
371e71b7053SJung-uk Kim      */
372e71b7053SJung-uk Kim     if (ext_type == TLSEXT_TYPE_signed_certificate_timestamp
373e71b7053SJung-uk Kim             && (context & SSL_EXT_CLIENT_HELLO) != 0
374e71b7053SJung-uk Kim             && SSL_CTX_ct_is_enabled(ctx))
375e71b7053SJung-uk Kim         return 0;
376e71b7053SJung-uk Kim #endif
377e71b7053SJung-uk Kim 
378e71b7053SJung-uk Kim     /*
379e71b7053SJung-uk Kim      * Don't add if extension supported internally, but make exception
380e71b7053SJung-uk Kim      * for extension types that previously were not supported, but now are.
381e71b7053SJung-uk Kim      */
382e71b7053SJung-uk Kim     if (SSL_extension_supported(ext_type)
383e71b7053SJung-uk Kim             && ext_type != TLSEXT_TYPE_signed_certificate_timestamp)
384e71b7053SJung-uk Kim         return 0;
385e71b7053SJung-uk Kim 
386e71b7053SJung-uk Kim     /* Extension type must fit in 16 bits */
387e71b7053SJung-uk Kim     if (ext_type > 0xffff)
388e71b7053SJung-uk Kim         return 0;
389e71b7053SJung-uk Kim     /* Search for duplicate */
390e71b7053SJung-uk Kim     if (custom_ext_find(exts, role, ext_type, NULL))
391e71b7053SJung-uk Kim         return 0;
392e71b7053SJung-uk Kim     tmp = OPENSSL_realloc(exts->meths,
393e71b7053SJung-uk Kim                           (exts->meths_count + 1) * sizeof(custom_ext_method));
394e71b7053SJung-uk Kim     if (tmp == NULL)
395e71b7053SJung-uk Kim         return 0;
396e71b7053SJung-uk Kim 
397e71b7053SJung-uk Kim     exts->meths = tmp;
398e71b7053SJung-uk Kim     meth = exts->meths + exts->meths_count;
399e71b7053SJung-uk Kim     memset(meth, 0, sizeof(*meth));
400e71b7053SJung-uk Kim     meth->role = role;
401e71b7053SJung-uk Kim     meth->context = context;
402e71b7053SJung-uk Kim     meth->parse_cb = parse_cb;
403e71b7053SJung-uk Kim     meth->add_cb = add_cb;
404e71b7053SJung-uk Kim     meth->free_cb = free_cb;
405e71b7053SJung-uk Kim     meth->ext_type = ext_type;
406e71b7053SJung-uk Kim     meth->add_arg = add_arg;
407e71b7053SJung-uk Kim     meth->parse_arg = parse_arg;
408e71b7053SJung-uk Kim     exts->meths_count++;
409e71b7053SJung-uk Kim     return 1;
410e71b7053SJung-uk Kim }
411e71b7053SJung-uk Kim 
add_old_custom_ext(SSL_CTX * ctx,ENDPOINT role,unsigned int ext_type,unsigned int context,custom_ext_add_cb add_cb,custom_ext_free_cb free_cb,void * add_arg,custom_ext_parse_cb parse_cb,void * parse_arg)412e71b7053SJung-uk Kim static int add_old_custom_ext(SSL_CTX *ctx, ENDPOINT role,
413e71b7053SJung-uk Kim                               unsigned int ext_type,
414e71b7053SJung-uk Kim                               unsigned int context,
415e71b7053SJung-uk Kim                               custom_ext_add_cb add_cb,
416e71b7053SJung-uk Kim                               custom_ext_free_cb free_cb,
417e71b7053SJung-uk Kim                               void *add_arg,
418e71b7053SJung-uk Kim                               custom_ext_parse_cb parse_cb, void *parse_arg)
419e71b7053SJung-uk Kim {
420e71b7053SJung-uk Kim     custom_ext_add_cb_wrap *add_cb_wrap
421e71b7053SJung-uk Kim         = OPENSSL_malloc(sizeof(*add_cb_wrap));
422e71b7053SJung-uk Kim     custom_ext_parse_cb_wrap *parse_cb_wrap
423e71b7053SJung-uk Kim         = OPENSSL_malloc(sizeof(*parse_cb_wrap));
424e71b7053SJung-uk Kim     int ret;
425e71b7053SJung-uk Kim 
426e71b7053SJung-uk Kim     if (add_cb_wrap == NULL || parse_cb_wrap == NULL) {
427e71b7053SJung-uk Kim         OPENSSL_free(add_cb_wrap);
428e71b7053SJung-uk Kim         OPENSSL_free(parse_cb_wrap);
429e71b7053SJung-uk Kim         return 0;
430e71b7053SJung-uk Kim     }
431e71b7053SJung-uk Kim 
432e71b7053SJung-uk Kim     add_cb_wrap->add_arg = add_arg;
433e71b7053SJung-uk Kim     add_cb_wrap->add_cb = add_cb;
434e71b7053SJung-uk Kim     add_cb_wrap->free_cb = free_cb;
435e71b7053SJung-uk Kim     parse_cb_wrap->parse_arg = parse_arg;
436e71b7053SJung-uk Kim     parse_cb_wrap->parse_cb = parse_cb;
437e71b7053SJung-uk Kim 
438e71b7053SJung-uk Kim     ret = add_custom_ext_intern(ctx, role, ext_type,
439e71b7053SJung-uk Kim                                 context,
440e71b7053SJung-uk Kim                                 custom_ext_add_old_cb_wrap,
441e71b7053SJung-uk Kim                                 custom_ext_free_old_cb_wrap,
442e71b7053SJung-uk Kim                                 add_cb_wrap,
443e71b7053SJung-uk Kim                                 custom_ext_parse_old_cb_wrap,
444e71b7053SJung-uk Kim                                 parse_cb_wrap);
445e71b7053SJung-uk Kim 
446e71b7053SJung-uk Kim     if (!ret) {
447e71b7053SJung-uk Kim         OPENSSL_free(add_cb_wrap);
448e71b7053SJung-uk Kim         OPENSSL_free(parse_cb_wrap);
449e71b7053SJung-uk Kim     }
450e71b7053SJung-uk Kim 
451e71b7053SJung-uk Kim     return ret;
452e71b7053SJung-uk Kim }
453e71b7053SJung-uk Kim 
454e71b7053SJung-uk Kim /* Application level functions to add the old custom extension callbacks */
SSL_CTX_add_client_custom_ext(SSL_CTX * ctx,unsigned int ext_type,custom_ext_add_cb add_cb,custom_ext_free_cb free_cb,void * add_arg,custom_ext_parse_cb parse_cb,void * parse_arg)455e71b7053SJung-uk Kim int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
456e71b7053SJung-uk Kim                                   custom_ext_add_cb add_cb,
457e71b7053SJung-uk Kim                                   custom_ext_free_cb free_cb,
458e71b7053SJung-uk Kim                                   void *add_arg,
459e71b7053SJung-uk Kim                                   custom_ext_parse_cb parse_cb, void *parse_arg)
460e71b7053SJung-uk Kim {
461e71b7053SJung-uk Kim     return add_old_custom_ext(ctx, ENDPOINT_CLIENT, ext_type,
462e71b7053SJung-uk Kim                               SSL_EXT_TLS1_2_AND_BELOW_ONLY
463e71b7053SJung-uk Kim                               | SSL_EXT_CLIENT_HELLO
464e71b7053SJung-uk Kim                               | SSL_EXT_TLS1_2_SERVER_HELLO
465e71b7053SJung-uk Kim                               | SSL_EXT_IGNORE_ON_RESUMPTION,
466e71b7053SJung-uk Kim                               add_cb, free_cb, add_arg, parse_cb, parse_arg);
467e71b7053SJung-uk Kim }
468e71b7053SJung-uk Kim 
SSL_CTX_add_server_custom_ext(SSL_CTX * ctx,unsigned int ext_type,custom_ext_add_cb add_cb,custom_ext_free_cb free_cb,void * add_arg,custom_ext_parse_cb parse_cb,void * parse_arg)469e71b7053SJung-uk Kim int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
470e71b7053SJung-uk Kim                                   custom_ext_add_cb add_cb,
471e71b7053SJung-uk Kim                                   custom_ext_free_cb free_cb,
472e71b7053SJung-uk Kim                                   void *add_arg,
473e71b7053SJung-uk Kim                                   custom_ext_parse_cb parse_cb, void *parse_arg)
474e71b7053SJung-uk Kim {
475e71b7053SJung-uk Kim     return add_old_custom_ext(ctx, ENDPOINT_SERVER, ext_type,
476e71b7053SJung-uk Kim                               SSL_EXT_TLS1_2_AND_BELOW_ONLY
477e71b7053SJung-uk Kim                               | SSL_EXT_CLIENT_HELLO
478e71b7053SJung-uk Kim                               | SSL_EXT_TLS1_2_SERVER_HELLO
479e71b7053SJung-uk Kim                               | SSL_EXT_IGNORE_ON_RESUMPTION,
480e71b7053SJung-uk Kim                               add_cb, free_cb, add_arg, parse_cb, parse_arg);
481e71b7053SJung-uk Kim }
482e71b7053SJung-uk Kim 
SSL_CTX_add_custom_ext(SSL_CTX * ctx,unsigned int ext_type,unsigned int context,SSL_custom_ext_add_cb_ex add_cb,SSL_custom_ext_free_cb_ex free_cb,void * add_arg,SSL_custom_ext_parse_cb_ex parse_cb,void * parse_arg)483e71b7053SJung-uk Kim int SSL_CTX_add_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
484e71b7053SJung-uk Kim                            unsigned int context,
485e71b7053SJung-uk Kim                            SSL_custom_ext_add_cb_ex add_cb,
486e71b7053SJung-uk Kim                            SSL_custom_ext_free_cb_ex free_cb,
487e71b7053SJung-uk Kim                            void *add_arg,
488e71b7053SJung-uk Kim                            SSL_custom_ext_parse_cb_ex parse_cb, void *parse_arg)
489e71b7053SJung-uk Kim {
490e71b7053SJung-uk Kim     return add_custom_ext_intern(ctx, ENDPOINT_BOTH, ext_type, context, add_cb,
491e71b7053SJung-uk Kim                                  free_cb, add_arg, parse_cb, parse_arg);
492e71b7053SJung-uk Kim }
493e71b7053SJung-uk Kim 
SSL_extension_supported(unsigned int ext_type)494e71b7053SJung-uk Kim int SSL_extension_supported(unsigned int ext_type)
495e71b7053SJung-uk Kim {
496e71b7053SJung-uk Kim     switch (ext_type) {
497e71b7053SJung-uk Kim         /* Internally supported extensions. */
498e71b7053SJung-uk Kim     case TLSEXT_TYPE_application_layer_protocol_negotiation:
499e71b7053SJung-uk Kim     case TLSEXT_TYPE_ec_point_formats:
500e71b7053SJung-uk Kim     case TLSEXT_TYPE_supported_groups:
501e71b7053SJung-uk Kim     case TLSEXT_TYPE_key_share:
502e71b7053SJung-uk Kim #ifndef OPENSSL_NO_NEXTPROTONEG
503e71b7053SJung-uk Kim     case TLSEXT_TYPE_next_proto_neg:
504e71b7053SJung-uk Kim #endif
505e71b7053SJung-uk Kim     case TLSEXT_TYPE_padding:
506e71b7053SJung-uk Kim     case TLSEXT_TYPE_renegotiate:
507e71b7053SJung-uk Kim     case TLSEXT_TYPE_max_fragment_length:
508e71b7053SJung-uk Kim     case TLSEXT_TYPE_server_name:
509e71b7053SJung-uk Kim     case TLSEXT_TYPE_session_ticket:
510e71b7053SJung-uk Kim     case TLSEXT_TYPE_signature_algorithms:
511e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SRP
512e71b7053SJung-uk Kim     case TLSEXT_TYPE_srp:
513e71b7053SJung-uk Kim #endif
514e71b7053SJung-uk Kim #ifndef OPENSSL_NO_OCSP
515e71b7053SJung-uk Kim     case TLSEXT_TYPE_status_request:
516e71b7053SJung-uk Kim #endif
517e71b7053SJung-uk Kim #ifndef OPENSSL_NO_CT
518e71b7053SJung-uk Kim     case TLSEXT_TYPE_signed_certificate_timestamp:
519e71b7053SJung-uk Kim #endif
520e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SRTP
521e71b7053SJung-uk Kim     case TLSEXT_TYPE_use_srtp:
522e71b7053SJung-uk Kim #endif
523e71b7053SJung-uk Kim     case TLSEXT_TYPE_encrypt_then_mac:
524e71b7053SJung-uk Kim     case TLSEXT_TYPE_supported_versions:
525e71b7053SJung-uk Kim     case TLSEXT_TYPE_extended_master_secret:
526e71b7053SJung-uk Kim     case TLSEXT_TYPE_psk_kex_modes:
527e71b7053SJung-uk Kim     case TLSEXT_TYPE_cookie:
528e71b7053SJung-uk Kim     case TLSEXT_TYPE_early_data:
529e71b7053SJung-uk Kim     case TLSEXT_TYPE_certificate_authorities:
530e71b7053SJung-uk Kim     case TLSEXT_TYPE_psk:
531e71b7053SJung-uk Kim     case TLSEXT_TYPE_post_handshake_auth:
532e71b7053SJung-uk Kim         return 1;
533e71b7053SJung-uk Kim     default:
534e71b7053SJung-uk Kim         return 0;
535e71b7053SJung-uk Kim     }
536e71b7053SJung-uk Kim }
537