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