xref: /freebsd/crypto/openssl/ssl/statem/extensions_cust.c (revision 17f01e9963948a18f55eb97173123702c5dae671)
1e71b7053SJung-uk Kim /*
2e71b7053SJung-uk Kim  * Copyright 2014-2018 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>
13*17f01e99SJung-uk Kim #include "../ssl_local.h"
14e71b7053SJung-uk Kim #include "internal/cryptlib.h"
15*17f01e99SJung-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     /*
149e71b7053SJung-uk Kim      * Extensions received in the ClientHello are marked with the
150e71b7053SJung-uk Kim      * SSL_EXT_FLAG_RECEIVED. This is so we know to add the equivalent
151e71b7053SJung-uk Kim      * extensions in the ServerHello/EncryptedExtensions message
152e71b7053SJung-uk Kim      */
153e71b7053SJung-uk Kim     if ((context & SSL_EXT_CLIENT_HELLO) != 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) {
162e71b7053SJung-uk Kim         SSLfatal(s, al, SSL_F_CUSTOM_EXT_PARSE, 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  */
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) {
195e71b7053SJung-uk Kim             /* Only send extensions present in ClientHello. */
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) {
212e71b7053SJung-uk Kim                 SSLfatal(s, al, SSL_F_CUSTOM_EXT_ADD, 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)) {
223e71b7053SJung-uk Kim             SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CUSTOM_EXT_ADD,
224e71b7053SJung-uk Kim                      ERR_R_INTERNAL_ERROR);
225e71b7053SJung-uk Kim             return 0;
226e71b7053SJung-uk Kim         }
227e71b7053SJung-uk Kim         if ((context & SSL_EXT_CLIENT_HELLO) != 0) {
228e71b7053SJung-uk Kim             /*
229e71b7053SJung-uk Kim              * We can't send duplicates: code logic should prevent this.
230e71b7053SJung-uk Kim              */
231e71b7053SJung-uk Kim             if (!ossl_assert((meth->ext_flags & SSL_EXT_FLAG_SENT) == 0)) {
232e71b7053SJung-uk Kim                 SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CUSTOM_EXT_ADD,
233e71b7053SJung-uk Kim                          ERR_R_INTERNAL_ERROR);
234e71b7053SJung-uk Kim                 return 0;
235e71b7053SJung-uk Kim             }
236e71b7053SJung-uk Kim             /*
237e71b7053SJung-uk Kim              * Indicate extension has been sent: this is both a sanity check to
238e71b7053SJung-uk Kim              * ensure we don't send duplicate extensions and indicates that it
239e71b7053SJung-uk Kim              * is not an error if the extension is present in ServerHello.
240e71b7053SJung-uk Kim              */
241e71b7053SJung-uk Kim             meth->ext_flags |= SSL_EXT_FLAG_SENT;
242e71b7053SJung-uk Kim         }
243e71b7053SJung-uk Kim         if (meth->free_cb != NULL)
244e71b7053SJung-uk Kim             meth->free_cb(s, meth->ext_type, context, out, meth->add_arg);
245e71b7053SJung-uk Kim     }
246e71b7053SJung-uk Kim     return 1;
247e71b7053SJung-uk Kim }
248e71b7053SJung-uk Kim 
249e71b7053SJung-uk Kim /* Copy the flags from src to dst for any extensions that exist in both */
250e71b7053SJung-uk Kim int custom_exts_copy_flags(custom_ext_methods *dst,
251e71b7053SJung-uk Kim                            const custom_ext_methods *src)
252e71b7053SJung-uk Kim {
253e71b7053SJung-uk Kim     size_t i;
254e71b7053SJung-uk Kim     custom_ext_method *methsrc = src->meths;
255e71b7053SJung-uk Kim 
256e71b7053SJung-uk Kim     for (i = 0; i < src->meths_count; i++, methsrc++) {
257e71b7053SJung-uk Kim         custom_ext_method *methdst = custom_ext_find(dst, methsrc->role,
258e71b7053SJung-uk Kim                                                      methsrc->ext_type, NULL);
259e71b7053SJung-uk Kim 
260e71b7053SJung-uk Kim         if (methdst == NULL)
261e71b7053SJung-uk Kim             continue;
262e71b7053SJung-uk Kim 
263e71b7053SJung-uk Kim         methdst->ext_flags = methsrc->ext_flags;
264e71b7053SJung-uk Kim     }
265e71b7053SJung-uk Kim 
266e71b7053SJung-uk Kim     return 1;
267e71b7053SJung-uk Kim }
268e71b7053SJung-uk Kim 
269e71b7053SJung-uk Kim /* Copy table of custom extensions */
270e71b7053SJung-uk Kim int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
271e71b7053SJung-uk Kim {
272e71b7053SJung-uk Kim     size_t i;
273e71b7053SJung-uk Kim     int err = 0;
274e71b7053SJung-uk Kim 
275e71b7053SJung-uk Kim     if (src->meths_count > 0) {
276e71b7053SJung-uk Kim         dst->meths =
277e71b7053SJung-uk Kim             OPENSSL_memdup(src->meths,
278e71b7053SJung-uk Kim                            sizeof(*src->meths) * src->meths_count);
279e71b7053SJung-uk Kim         if (dst->meths == NULL)
280e71b7053SJung-uk Kim             return 0;
281e71b7053SJung-uk Kim         dst->meths_count = src->meths_count;
282e71b7053SJung-uk Kim 
283e71b7053SJung-uk Kim         for (i = 0; i < src->meths_count; i++) {
284e71b7053SJung-uk Kim             custom_ext_method *methsrc = src->meths + i;
285e71b7053SJung-uk Kim             custom_ext_method *methdst = dst->meths + i;
286e71b7053SJung-uk Kim 
287e71b7053SJung-uk Kim             if (methsrc->add_cb != custom_ext_add_old_cb_wrap)
288e71b7053SJung-uk Kim                 continue;
289e71b7053SJung-uk Kim 
290e71b7053SJung-uk Kim             /*
291e71b7053SJung-uk Kim              * We have found an old style API wrapper. We need to copy the
292e71b7053SJung-uk Kim              * arguments too.
293e71b7053SJung-uk Kim              */
294e71b7053SJung-uk Kim 
295e71b7053SJung-uk Kim             if (err) {
296e71b7053SJung-uk Kim                 methdst->add_arg = NULL;
297e71b7053SJung-uk Kim                 methdst->parse_arg = NULL;
298e71b7053SJung-uk Kim                 continue;
299e71b7053SJung-uk Kim             }
300e71b7053SJung-uk Kim 
301e71b7053SJung-uk Kim             methdst->add_arg = OPENSSL_memdup(methsrc->add_arg,
302e71b7053SJung-uk Kim                                               sizeof(custom_ext_add_cb_wrap));
303e71b7053SJung-uk Kim             methdst->parse_arg = OPENSSL_memdup(methsrc->parse_arg,
304e71b7053SJung-uk Kim                                             sizeof(custom_ext_parse_cb_wrap));
305e71b7053SJung-uk Kim 
306e71b7053SJung-uk Kim             if (methdst->add_arg == NULL || methdst->parse_arg == NULL)
307e71b7053SJung-uk Kim                 err = 1;
308e71b7053SJung-uk Kim         }
309e71b7053SJung-uk Kim     }
310e71b7053SJung-uk Kim 
311e71b7053SJung-uk Kim     if (err) {
312e71b7053SJung-uk Kim         custom_exts_free(dst);
313e71b7053SJung-uk Kim         return 0;
314e71b7053SJung-uk Kim     }
315e71b7053SJung-uk Kim 
316e71b7053SJung-uk Kim     return 1;
317e71b7053SJung-uk Kim }
318e71b7053SJung-uk Kim 
319e71b7053SJung-uk Kim void custom_exts_free(custom_ext_methods *exts)
320e71b7053SJung-uk Kim {
321e71b7053SJung-uk Kim     size_t i;
322e71b7053SJung-uk Kim     custom_ext_method *meth;
323e71b7053SJung-uk Kim 
324e71b7053SJung-uk Kim     for (i = 0, meth = exts->meths; i < exts->meths_count; i++, meth++) {
325e71b7053SJung-uk Kim         if (meth->add_cb != custom_ext_add_old_cb_wrap)
326e71b7053SJung-uk Kim             continue;
327e71b7053SJung-uk Kim 
328e71b7053SJung-uk Kim         /* Old style API wrapper. Need to free the arguments too */
329e71b7053SJung-uk Kim         OPENSSL_free(meth->add_arg);
330e71b7053SJung-uk Kim         OPENSSL_free(meth->parse_arg);
331e71b7053SJung-uk Kim     }
332e71b7053SJung-uk Kim     OPENSSL_free(exts->meths);
333e71b7053SJung-uk Kim }
334e71b7053SJung-uk Kim 
335e71b7053SJung-uk Kim /* Return true if a client custom extension exists, false otherwise */
336e71b7053SJung-uk Kim int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx, unsigned int ext_type)
337e71b7053SJung-uk Kim {
338e71b7053SJung-uk Kim     return custom_ext_find(&ctx->cert->custext, ENDPOINT_CLIENT, ext_type,
339e71b7053SJung-uk Kim                            NULL) != NULL;
340e71b7053SJung-uk Kim }
341e71b7053SJung-uk Kim 
342e71b7053SJung-uk Kim static int add_custom_ext_intern(SSL_CTX *ctx, ENDPOINT role,
343e71b7053SJung-uk Kim                                  unsigned int ext_type,
344e71b7053SJung-uk Kim                                  unsigned int context,
345e71b7053SJung-uk Kim                                  SSL_custom_ext_add_cb_ex add_cb,
346e71b7053SJung-uk Kim                                  SSL_custom_ext_free_cb_ex free_cb,
347e71b7053SJung-uk Kim                                  void *add_arg,
348e71b7053SJung-uk Kim                                  SSL_custom_ext_parse_cb_ex parse_cb,
349e71b7053SJung-uk Kim                                  void *parse_arg)
350e71b7053SJung-uk Kim {
351e71b7053SJung-uk Kim     custom_ext_methods *exts = &ctx->cert->custext;
352e71b7053SJung-uk Kim     custom_ext_method *meth, *tmp;
353e71b7053SJung-uk Kim 
354e71b7053SJung-uk Kim     /*
355e71b7053SJung-uk Kim      * Check application error: if add_cb is not set free_cb will never be
356e71b7053SJung-uk Kim      * called.
357e71b7053SJung-uk Kim      */
358e71b7053SJung-uk Kim     if (add_cb == NULL && free_cb != NULL)
359e71b7053SJung-uk Kim         return 0;
360e71b7053SJung-uk Kim 
361e71b7053SJung-uk Kim #ifndef OPENSSL_NO_CT
362e71b7053SJung-uk Kim     /*
363e71b7053SJung-uk Kim      * We don't want applications registering callbacks for SCT extensions
364e71b7053SJung-uk Kim      * whilst simultaneously using the built-in SCT validation features, as
365e71b7053SJung-uk Kim      * these two things may not play well together.
366e71b7053SJung-uk Kim      */
367e71b7053SJung-uk Kim     if (ext_type == TLSEXT_TYPE_signed_certificate_timestamp
368e71b7053SJung-uk Kim             && (context & SSL_EXT_CLIENT_HELLO) != 0
369e71b7053SJung-uk Kim             && SSL_CTX_ct_is_enabled(ctx))
370e71b7053SJung-uk Kim         return 0;
371e71b7053SJung-uk Kim #endif
372e71b7053SJung-uk Kim 
373e71b7053SJung-uk Kim     /*
374e71b7053SJung-uk Kim      * Don't add if extension supported internally, but make exception
375e71b7053SJung-uk Kim      * for extension types that previously were not supported, but now are.
376e71b7053SJung-uk Kim      */
377e71b7053SJung-uk Kim     if (SSL_extension_supported(ext_type)
378e71b7053SJung-uk Kim             && ext_type != TLSEXT_TYPE_signed_certificate_timestamp)
379e71b7053SJung-uk Kim         return 0;
380e71b7053SJung-uk Kim 
381e71b7053SJung-uk Kim     /* Extension type must fit in 16 bits */
382e71b7053SJung-uk Kim     if (ext_type > 0xffff)
383e71b7053SJung-uk Kim         return 0;
384e71b7053SJung-uk Kim     /* Search for duplicate */
385e71b7053SJung-uk Kim     if (custom_ext_find(exts, role, ext_type, NULL))
386e71b7053SJung-uk Kim         return 0;
387e71b7053SJung-uk Kim     tmp = OPENSSL_realloc(exts->meths,
388e71b7053SJung-uk Kim                           (exts->meths_count + 1) * sizeof(custom_ext_method));
389e71b7053SJung-uk Kim     if (tmp == NULL)
390e71b7053SJung-uk Kim         return 0;
391e71b7053SJung-uk Kim 
392e71b7053SJung-uk Kim     exts->meths = tmp;
393e71b7053SJung-uk Kim     meth = exts->meths + exts->meths_count;
394e71b7053SJung-uk Kim     memset(meth, 0, sizeof(*meth));
395e71b7053SJung-uk Kim     meth->role = role;
396e71b7053SJung-uk Kim     meth->context = context;
397e71b7053SJung-uk Kim     meth->parse_cb = parse_cb;
398e71b7053SJung-uk Kim     meth->add_cb = add_cb;
399e71b7053SJung-uk Kim     meth->free_cb = free_cb;
400e71b7053SJung-uk Kim     meth->ext_type = ext_type;
401e71b7053SJung-uk Kim     meth->add_arg = add_arg;
402e71b7053SJung-uk Kim     meth->parse_arg = parse_arg;
403e71b7053SJung-uk Kim     exts->meths_count++;
404e71b7053SJung-uk Kim     return 1;
405e71b7053SJung-uk Kim }
406e71b7053SJung-uk Kim 
407e71b7053SJung-uk Kim static int add_old_custom_ext(SSL_CTX *ctx, ENDPOINT role,
408e71b7053SJung-uk Kim                               unsigned int ext_type,
409e71b7053SJung-uk Kim                               unsigned int context,
410e71b7053SJung-uk Kim                               custom_ext_add_cb add_cb,
411e71b7053SJung-uk Kim                               custom_ext_free_cb free_cb,
412e71b7053SJung-uk Kim                               void *add_arg,
413e71b7053SJung-uk Kim                               custom_ext_parse_cb parse_cb, void *parse_arg)
414e71b7053SJung-uk Kim {
415e71b7053SJung-uk Kim     custom_ext_add_cb_wrap *add_cb_wrap
416e71b7053SJung-uk Kim         = OPENSSL_malloc(sizeof(*add_cb_wrap));
417e71b7053SJung-uk Kim     custom_ext_parse_cb_wrap *parse_cb_wrap
418e71b7053SJung-uk Kim         = OPENSSL_malloc(sizeof(*parse_cb_wrap));
419e71b7053SJung-uk Kim     int ret;
420e71b7053SJung-uk Kim 
421e71b7053SJung-uk Kim     if (add_cb_wrap == NULL || parse_cb_wrap == NULL) {
422e71b7053SJung-uk Kim         OPENSSL_free(add_cb_wrap);
423e71b7053SJung-uk Kim         OPENSSL_free(parse_cb_wrap);
424e71b7053SJung-uk Kim         return 0;
425e71b7053SJung-uk Kim     }
426e71b7053SJung-uk Kim 
427e71b7053SJung-uk Kim     add_cb_wrap->add_arg = add_arg;
428e71b7053SJung-uk Kim     add_cb_wrap->add_cb = add_cb;
429e71b7053SJung-uk Kim     add_cb_wrap->free_cb = free_cb;
430e71b7053SJung-uk Kim     parse_cb_wrap->parse_arg = parse_arg;
431e71b7053SJung-uk Kim     parse_cb_wrap->parse_cb = parse_cb;
432e71b7053SJung-uk Kim 
433e71b7053SJung-uk Kim     ret = add_custom_ext_intern(ctx, role, ext_type,
434e71b7053SJung-uk Kim                                 context,
435e71b7053SJung-uk Kim                                 custom_ext_add_old_cb_wrap,
436e71b7053SJung-uk Kim                                 custom_ext_free_old_cb_wrap,
437e71b7053SJung-uk Kim                                 add_cb_wrap,
438e71b7053SJung-uk Kim                                 custom_ext_parse_old_cb_wrap,
439e71b7053SJung-uk Kim                                 parse_cb_wrap);
440e71b7053SJung-uk Kim 
441e71b7053SJung-uk Kim     if (!ret) {
442e71b7053SJung-uk Kim         OPENSSL_free(add_cb_wrap);
443e71b7053SJung-uk Kim         OPENSSL_free(parse_cb_wrap);
444e71b7053SJung-uk Kim     }
445e71b7053SJung-uk Kim 
446e71b7053SJung-uk Kim     return ret;
447e71b7053SJung-uk Kim }
448e71b7053SJung-uk Kim 
449e71b7053SJung-uk Kim /* Application level functions to add the old custom extension callbacks */
450e71b7053SJung-uk Kim int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
451e71b7053SJung-uk Kim                                   custom_ext_add_cb add_cb,
452e71b7053SJung-uk Kim                                   custom_ext_free_cb free_cb,
453e71b7053SJung-uk Kim                                   void *add_arg,
454e71b7053SJung-uk Kim                                   custom_ext_parse_cb parse_cb, void *parse_arg)
455e71b7053SJung-uk Kim {
456e71b7053SJung-uk Kim     return add_old_custom_ext(ctx, ENDPOINT_CLIENT, ext_type,
457e71b7053SJung-uk Kim                               SSL_EXT_TLS1_2_AND_BELOW_ONLY
458e71b7053SJung-uk Kim                               | SSL_EXT_CLIENT_HELLO
459e71b7053SJung-uk Kim                               | SSL_EXT_TLS1_2_SERVER_HELLO
460e71b7053SJung-uk Kim                               | SSL_EXT_IGNORE_ON_RESUMPTION,
461e71b7053SJung-uk Kim                               add_cb, free_cb, add_arg, parse_cb, parse_arg);
462e71b7053SJung-uk Kim }
463e71b7053SJung-uk Kim 
464e71b7053SJung-uk Kim int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
465e71b7053SJung-uk Kim                                   custom_ext_add_cb add_cb,
466e71b7053SJung-uk Kim                                   custom_ext_free_cb free_cb,
467e71b7053SJung-uk Kim                                   void *add_arg,
468e71b7053SJung-uk Kim                                   custom_ext_parse_cb parse_cb, void *parse_arg)
469e71b7053SJung-uk Kim {
470e71b7053SJung-uk Kim     return add_old_custom_ext(ctx, ENDPOINT_SERVER, ext_type,
471e71b7053SJung-uk Kim                               SSL_EXT_TLS1_2_AND_BELOW_ONLY
472e71b7053SJung-uk Kim                               | SSL_EXT_CLIENT_HELLO
473e71b7053SJung-uk Kim                               | SSL_EXT_TLS1_2_SERVER_HELLO
474e71b7053SJung-uk Kim                               | SSL_EXT_IGNORE_ON_RESUMPTION,
475e71b7053SJung-uk Kim                               add_cb, free_cb, add_arg, parse_cb, parse_arg);
476e71b7053SJung-uk Kim }
477e71b7053SJung-uk Kim 
478e71b7053SJung-uk Kim int SSL_CTX_add_custom_ext(SSL_CTX *ctx, unsigned int ext_type,
479e71b7053SJung-uk Kim                            unsigned int context,
480e71b7053SJung-uk Kim                            SSL_custom_ext_add_cb_ex add_cb,
481e71b7053SJung-uk Kim                            SSL_custom_ext_free_cb_ex free_cb,
482e71b7053SJung-uk Kim                            void *add_arg,
483e71b7053SJung-uk Kim                            SSL_custom_ext_parse_cb_ex parse_cb, void *parse_arg)
484e71b7053SJung-uk Kim {
485e71b7053SJung-uk Kim     return add_custom_ext_intern(ctx, ENDPOINT_BOTH, ext_type, context, add_cb,
486e71b7053SJung-uk Kim                                  free_cb, add_arg, parse_cb, parse_arg);
487e71b7053SJung-uk Kim }
488e71b7053SJung-uk Kim 
489e71b7053SJung-uk Kim int SSL_extension_supported(unsigned int ext_type)
490e71b7053SJung-uk Kim {
491e71b7053SJung-uk Kim     switch (ext_type) {
492e71b7053SJung-uk Kim         /* Internally supported extensions. */
493e71b7053SJung-uk Kim     case TLSEXT_TYPE_application_layer_protocol_negotiation:
494e71b7053SJung-uk Kim #ifndef OPENSSL_NO_EC
495e71b7053SJung-uk Kim     case TLSEXT_TYPE_ec_point_formats:
496e71b7053SJung-uk Kim     case TLSEXT_TYPE_supported_groups:
497e71b7053SJung-uk Kim     case TLSEXT_TYPE_key_share:
498e71b7053SJung-uk Kim #endif
499e71b7053SJung-uk Kim #ifndef OPENSSL_NO_NEXTPROTONEG
500e71b7053SJung-uk Kim     case TLSEXT_TYPE_next_proto_neg:
501e71b7053SJung-uk Kim #endif
502e71b7053SJung-uk Kim     case TLSEXT_TYPE_padding:
503e71b7053SJung-uk Kim     case TLSEXT_TYPE_renegotiate:
504e71b7053SJung-uk Kim     case TLSEXT_TYPE_max_fragment_length:
505e71b7053SJung-uk Kim     case TLSEXT_TYPE_server_name:
506e71b7053SJung-uk Kim     case TLSEXT_TYPE_session_ticket:
507e71b7053SJung-uk Kim     case TLSEXT_TYPE_signature_algorithms:
508e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SRP
509e71b7053SJung-uk Kim     case TLSEXT_TYPE_srp:
510e71b7053SJung-uk Kim #endif
511e71b7053SJung-uk Kim #ifndef OPENSSL_NO_OCSP
512e71b7053SJung-uk Kim     case TLSEXT_TYPE_status_request:
513e71b7053SJung-uk Kim #endif
514e71b7053SJung-uk Kim #ifndef OPENSSL_NO_CT
515e71b7053SJung-uk Kim     case TLSEXT_TYPE_signed_certificate_timestamp:
516e71b7053SJung-uk Kim #endif
517e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SRTP
518e71b7053SJung-uk Kim     case TLSEXT_TYPE_use_srtp:
519e71b7053SJung-uk Kim #endif
520e71b7053SJung-uk Kim     case TLSEXT_TYPE_encrypt_then_mac:
521e71b7053SJung-uk Kim     case TLSEXT_TYPE_supported_versions:
522e71b7053SJung-uk Kim     case TLSEXT_TYPE_extended_master_secret:
523e71b7053SJung-uk Kim     case TLSEXT_TYPE_psk_kex_modes:
524e71b7053SJung-uk Kim     case TLSEXT_TYPE_cookie:
525e71b7053SJung-uk Kim     case TLSEXT_TYPE_early_data:
526e71b7053SJung-uk Kim     case TLSEXT_TYPE_certificate_authorities:
527e71b7053SJung-uk Kim     case TLSEXT_TYPE_psk:
528e71b7053SJung-uk Kim     case TLSEXT_TYPE_post_handshake_auth:
529e71b7053SJung-uk Kim         return 1;
530e71b7053SJung-uk Kim     default:
531e71b7053SJung-uk Kim         return 0;
532e71b7053SJung-uk Kim     }
533e71b7053SJung-uk Kim }
534