Skip to content

Commit a398f82

Browse files
Trevorbenlaurie
authored andcommitted
Add support for arbitrary TLS extensions.
Contributed by Trevor Perrin.
1 parent 6d84daa commit a398f82

File tree

17 files changed

+791
-5
lines changed

17 files changed

+791
-5
lines changed

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
Changes between 1.0.x and 1.1.0 [xx XXX xxxx]
66

7+
*) Add callbacks for arbitrary TLS extensions.
8+
[Trevor Perrin <[email protected]> and Ben Laurie]
9+
710
*) Support for DTLS 1.2. This adds two sets of DTLS methods: DTLS_*_method()
811
supports both DTLS 1.2 and 1.0 and should use whatever version the peer
912
supports and DTLSv1_2_*_method() which supports DTLS 1.2 only.

apps/s_client.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ static void sc_usage(void)
365365
# ifndef OPENSSL_NO_NEXTPROTONEG
366366
BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n");
367367
# endif
368+
#ifndef OPENSSL_NO_TLSEXT
369+
BIO_printf(bio_err," -serverinfo types - send empty ClientHello extensions (comma-separated numbers)\n");
370+
#endif
368371
#endif
369372
BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
370373
BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n");
@@ -542,6 +545,26 @@ static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, con
542545
return SSL_TLSEXT_ERR_OK;
543546
}
544547
# endif /* ndef OPENSSL_NO_NEXTPROTONEG */
548+
549+
static int serverinfo_cli_cb(SSL* s, unsigned short ext_type,
550+
const unsigned char* in, unsigned short inlen,
551+
int* al, void* arg)
552+
{
553+
char pem_name[100];
554+
unsigned char ext_buf[4 + 65536];
555+
556+
/* Reconstruct the type/len fields prior to extension data */
557+
ext_buf[0] = ext_type >> 8;
558+
ext_buf[1] = ext_type & 0xFF;
559+
ext_buf[2] = inlen >> 8;
560+
ext_buf[3] = inlen & 0xFF;
561+
memcpy(ext_buf+4, in, inlen);
562+
563+
BIO_snprintf(pem_name, sizeof(pem_name), "SERVER_INFO %d", ext_type);
564+
PEM_write_bio(bio_c_out, pem_name, "", ext_buf, 4 + inlen);
565+
return 1;
566+
}
567+
545568
#endif
546569

547570
enum
@@ -614,6 +637,9 @@ int MAIN(int argc, char **argv)
614637
# ifndef OPENSSL_NO_NEXTPROTONEG
615638
const char *next_proto_neg_in = NULL;
616639
# endif
640+
# define MAX_SI_TYPES 100
641+
unsigned short serverinfo_types[MAX_SI_TYPES];
642+
int serverinfo_types_count = 0;
617643
#endif
618644
char *sess_in = NULL;
619645
char *sess_out = NULL;
@@ -968,6 +994,29 @@ static char *jpake_secret = NULL;
968994
next_proto_neg_in = *(++argv);
969995
}
970996
# endif
997+
else if (strcmp(*argv,"-serverinfo") == 0)
998+
{
999+
char *c;
1000+
int start = 0;
1001+
int len;
1002+
1003+
if (--argc < 1) goto bad;
1004+
c = *(++argv);
1005+
serverinfo_types_count = 0;
1006+
len = strlen(c);
1007+
for (i = 0; i <= len; ++i)
1008+
{
1009+
if (i == len || c[i] == ',')
1010+
{
1011+
serverinfo_types[serverinfo_types_count]
1012+
= atoi(c+start);
1013+
serverinfo_types_count++;
1014+
start = i+1;
1015+
}
1016+
if (serverinfo_types_count == MAX_SI_TYPES)
1017+
break;
1018+
}
1019+
}
9711020
#endif
9721021
#ifdef FIONBIO
9731022
else if (strcmp(*argv,"-nbio") == 0)
@@ -1261,6 +1310,19 @@ static char *jpake_secret = NULL;
12611310
if (next_proto.data)
12621311
SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto);
12631312
#endif
1313+
#ifndef OPENSSL_NO_TLSEXT
1314+
if (serverinfo_types_count)
1315+
{
1316+
for (i = 0; i < serverinfo_types_count; i++)
1317+
{
1318+
SSL_CTX_set_custom_cli_ext(ctx,
1319+
serverinfo_types[i],
1320+
NULL,
1321+
serverinfo_cli_cb,
1322+
NULL);
1323+
}
1324+
}
1325+
#endif
12641326

12651327
if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
12661328
#if 0

apps/s_server.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ static int cert_chain = 0;
318318
#ifndef OPENSSL_NO_TLSEXT
319319
static BIO *authz_in = NULL;
320320
static const char *s_authz_file = NULL;
321+
static BIO *serverinfo_in = NULL;
322+
static const char *s_serverinfo_file = NULL;
321323
#endif
322324

323325
#ifndef OPENSSL_NO_PSK
@@ -479,6 +481,9 @@ static void sv_usage(void)
479481
BIO_printf(bio_err," -cert arg - certificate file to use\n");
480482
BIO_printf(bio_err," (default is %s)\n",TEST_CERT);
481483
BIO_printf(bio_err," -authz arg - binary authz file for certificate\n");
484+
#ifndef OPENSSL_NO_TLSEXT
485+
BIO_printf(bio_err," -serverinfo arg - PEM serverinfo file for certificate\n");
486+
#endif
482487
BIO_printf(bio_err," -crl_check - check the peer certificate has not been revoked by its CA.\n" \
483488
" The CRL(s) are appended to the certificate file\n");
484489
BIO_printf(bio_err," -crl_check_all - check the peer certificate has not been revoked by its CA\n" \
@@ -1093,6 +1098,11 @@ int MAIN(int argc, char *argv[])
10931098
if (--argc < 1) goto bad;
10941099
s_authz_file = *(++argv);
10951100
}
1101+
else if (strcmp(*argv,"-serverinfo") == 0)
1102+
{
1103+
if (--argc < 1) goto bad;
1104+
s_serverinfo_file = *(++argv);
1105+
}
10961106
#endif
10971107
else if (strcmp(*argv,"-certform") == 0)
10981108
{
@@ -1853,6 +1863,9 @@ int MAIN(int argc, char *argv[])
18531863
#ifndef OPENSSL_NO_TLSEXT
18541864
if (s_authz_file != NULL && !SSL_CTX_use_authz_file(ctx, s_authz_file))
18551865
goto end;
1866+
if (s_serverinfo_file != NULL
1867+
&& !SSL_CTX_use_serverinfo_file(ctx, s_serverinfo_file))
1868+
goto end;
18561869
#endif
18571870
#ifndef OPENSSL_NO_TLSEXT
18581871
if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2, NULL, build_chain))
@@ -2032,6 +2045,8 @@ int MAIN(int argc, char *argv[])
20322045
EVP_PKEY_free(s_key2);
20332046
if (authz_in != NULL)
20342047
BIO_free(authz_in);
2048+
if (serverinfo_in != NULL)
2049+
BIO_free(serverinfo_in);
20352050
#endif
20362051
ssl_excert_free(exc);
20372052
if (ssl_args)

ssl/s3_lib.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3026,6 +3026,8 @@ void ssl3_free(SSL *s)
30263026
#ifndef OPENSSL_NO_TLSEXT
30273027
if (s->s3->tlsext_authz_client_types != NULL)
30283028
OPENSSL_free(s->s3->tlsext_authz_client_types);
3029+
if (s->s3->tlsext_custom_types != NULL)
3030+
OPENSSL_free(s->s3->tlsext_custom_types);
30293031
#endif
30303032
OPENSSL_cleanse(s->s3,sizeof *s->s3);
30313033
OPENSSL_free(s->s3);
@@ -3076,6 +3078,12 @@ void ssl3_clear(SSL *s)
30763078
OPENSSL_free(s->s3->tlsext_authz_client_types);
30773079
s->s3->tlsext_authz_client_types = NULL;
30783080
}
3081+
if (s->s3->tlsext_custom_types != NULL)
3082+
{
3083+
OPENSSL_free(s->s3->tlsext_custom_types);
3084+
s->s3->tlsext_custom_types = NULL;
3085+
}
3086+
s->s3->tlsext_custom_types_count = 0;
30793087
#endif
30803088

30813089
rp = s->s3->rbuf.buf;

ssl/ssl.h

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,56 @@ DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE)
383383
typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
384384
typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
385385

386+
#ifndef OPENSSL_NO_TLSEXT
387+
/* Callbacks and structures for handling custom TLS Extensions:
388+
* cli_ext_first_cb - sends data for ClientHello TLS Extension
389+
* cli_ext_second_cb - receives data from ServerHello TLS Extension
390+
* srv_ext_first_cb - receives data from ClientHello TLS Extension
391+
* srv_ext_second_cb - sends data for ServerHello TLS Extension
392+
*
393+
* All these functions return nonzero on success. Zero will terminate
394+
* the handshake (and return a specific TLS Fatal alert, if the function
395+
* declaration has an "al" parameter).
396+
*
397+
* "ext_type" is a TLS "ExtensionType" from 0-65535.
398+
* "in" is a pointer to TLS "extension_data" being provided to the cb.
399+
* "out" is used by the callback to return a pointer to "extension data"
400+
* which OpenSSL will later copy into the TLS handshake. The contents
401+
* of this buffer should not be changed until the handshake is complete.
402+
* "inlen" and "outlen" are TLS Extension lengths from 0-65535.
403+
* "al" is a TLS "AlertDescription" from 0-255 which WILL be sent as a
404+
* fatal TLS alert, if the callback returns zero.
405+
*/
406+
typedef int (*custom_cli_ext_first_cb_fn)(SSL *s, unsigned short ext_type,
407+
const unsigned char **out,
408+
unsigned short *outlen, void *arg);
409+
typedef int (*custom_cli_ext_second_cb_fn)(SSL *s, unsigned short ext_type,
410+
const unsigned char *in,
411+
unsigned short inlen, int *al,
412+
void *arg);
413+
414+
typedef int (*custom_srv_ext_first_cb_fn)(SSL *s, unsigned short ext_type,
415+
const unsigned char *in,
416+
unsigned short inlen, int *al,
417+
void *arg);
418+
typedef int (*custom_srv_ext_second_cb_fn)(SSL *s, unsigned short ext_type,
419+
const unsigned char **out,
420+
unsigned short *outlen, void *arg);
421+
422+
typedef struct {
423+
unsigned short ext_type;
424+
custom_cli_ext_first_cb_fn fn1;
425+
custom_cli_ext_second_cb_fn fn2;
426+
void *arg;
427+
} custom_cli_ext_record;
428+
429+
typedef struct {
430+
unsigned short ext_type;
431+
custom_srv_ext_first_cb_fn fn1;
432+
custom_srv_ext_second_cb_fn fn2;
433+
void *arg;
434+
} custom_srv_ext_record;
435+
#endif
386436

387437
#ifndef OPENSSL_NO_SSL_INTERN
388438

@@ -1064,6 +1114,12 @@ struct ssl_ctx_st
10641114
# endif /* OPENSSL_NO_EC */
10651115
int (*tlsext_authz_server_audit_proof_cb)(SSL *s, void *arg);
10661116
void *tlsext_authz_server_audit_proof_cb_arg;
1117+
1118+
/* Arrays containing the callbacks for custom TLS Extensions. */
1119+
custom_cli_ext_record *custom_cli_ext_records;
1120+
size_t custom_cli_ext_records_count;
1121+
custom_srv_ext_record *custom_srv_ext_records;
1122+
size_t custom_srv_ext_records_count;
10671123
};
10681124

10691125
#endif
@@ -1170,6 +1226,33 @@ const char *SSL_get_psk_identity_hint(const SSL *s);
11701226
const char *SSL_get_psk_identity(const SSL *s);
11711227
#endif
11721228

1229+
#ifndef OPENSSL_NO_TLSEXT
1230+
/* Register callbacks to handle custom TLS Extensions as client or server.
1231+
*
1232+
* Returns nonzero on success. You cannot register twice for the same
1233+
* extension number, and registering for an extension number already
1234+
* handled by OpenSSL will succeed, but the callbacks will not be invoked.
1235+
*
1236+
* NULL can be registered for any callback function. For the client
1237+
* functions, a NULL custom_cli_ext_first_cb_fn sends an empty ClientHello
1238+
* Extension, and a NULL custom_cli_ext_second_cb_fn ignores the ServerHello
1239+
* response (if any).
1240+
*
1241+
* For the server functions, a NULL custom_srv_ext_first_cb_fn means the
1242+
* ClientHello extension's data will be ignored, but the extension will still
1243+
* be noted and custom_srv_ext_second_cb_fn will still be invoked. If
1244+
* custom_srv_ext_second_cb_fn is NULL, an empty ServerHello extension is
1245+
* sent.
1246+
*/
1247+
int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned short ext_type,
1248+
custom_cli_ext_first_cb_fn fn1,
1249+
custom_cli_ext_second_cb_fn fn2, void *arg);
1250+
1251+
int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
1252+
custom_srv_ext_first_cb_fn fn1,
1253+
custom_srv_ext_second_cb_fn fn2, void *arg);
1254+
#endif
1255+
11731256
#define SSL_NOTHING 1
11741257
#define SSL_WRITING 2
11751258
#define SSL_READING 3
@@ -1934,6 +2017,14 @@ const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
19342017
int SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file);
19352018
int SSL_use_authz_file(SSL *ssl, const char *file);
19362019
#endif
2020+
2021+
/* Set serverinfo data for the current active cert. */
2022+
int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
2023+
size_t serverinfo_length);
2024+
#ifndef OPENSSL_NO_STDIO
2025+
int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file);
2026+
#endif /* NO_STDIO */
2027+
19372028
#endif
19382029

19392030
#ifndef OPENSSL_NO_STDIO
@@ -2481,6 +2572,8 @@ void ERR_load_SSL_strings(void);
24812572
#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177
24822573
#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178
24832574
#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179
2575+
#define SSL_F_SSL_CTX_USE_SERVERINFO 336
2576+
#define SSL_F_SSL_CTX_USE_SERVERINFO_FILE 337
24842577
#define SSL_F_SSL_DO_HANDSHAKE 180
24852578
#define SSL_F_SSL_GET_NEW_SESSION 181
24862579
#define SSL_F_SSL_GET_PREV_SESSION 217
@@ -2655,6 +2748,7 @@ void ERR_load_SSL_strings(void);
26552748
#define SSL_R_INVALID_COMPRESSION_ALGORITHM 341
26562749
#define SSL_R_INVALID_NULL_CMD_NAME 385
26572750
#define SSL_R_INVALID_PURPOSE 278
2751+
#define SSL_R_INVALID_SERVERINFO_DATA 388
26582752
#define SSL_R_INVALID_SRP_USERNAME 357
26592753
#define SSL_R_INVALID_STATUS_RESPONSE 328
26602754
#define SSL_R_INVALID_TICKET_KEYS_LENGTH 325

ssl/ssl3.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,15 @@ typedef struct ssl3_state_st
577577
* server echoed our server_authz extension and therefore must send us
578578
* a supplemental data handshake message. */
579579
char tlsext_authz_server_promised;
580+
581+
/* tlsext_custom_types contains an array of TLS Extension types which
582+
* were advertised by the client in its ClientHello, which were not
583+
* otherwise handled by OpenSSL, and which the server has registered
584+
* a custom_srv_ext_record to handle.
585+
* The array does not contain any duplicates, and is in the same order
586+
* as the types were received in the client hello. */
587+
unsigned short *tlsext_custom_types;
588+
size_t tlsext_custom_types_count; /* how many tlsext_custom_types */
580589
#endif
581590
} SSL3_STATE;
582591

ssl/ssl_cert.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ CERT *ssl_cert_dup(CERT *cert)
329329
}
330330
}
331331
rpk->valid_flags = 0;
332-
if (cert->pkeys[i].authz != NULL)
332+
#ifndef OPENSSL_NO_TLSEXT
333+
if (cert->pkeys[i].authz != NULL)
333334
{
334335
/* Just copy everything. */
335336
ret->pkeys[i].authz_length =
@@ -339,12 +340,30 @@ CERT *ssl_cert_dup(CERT *cert)
339340
if (ret->pkeys[i].authz == NULL)
340341
{
341342
SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
342-
return(NULL);
343+
return NULL;
343344
}
344345
memcpy(ret->pkeys[i].authz,
345346
cert->pkeys[i].authz,
346347
cert->pkeys[i].authz_length);
347348
}
349+
350+
if (cert->pkeys[i].serverinfo != NULL)
351+
{
352+
/* Just copy everything. */
353+
ret->pkeys[i].serverinfo_length =
354+
cert->pkeys[i].serverinfo_length;
355+
ret->pkeys[i].serverinfo =
356+
OPENSSL_malloc(ret->pkeys[i].serverinfo_length);
357+
if (ret->pkeys[i].serverinfo == NULL)
358+
{
359+
SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
360+
return NULL;
361+
}
362+
memcpy(ret->pkeys[i].serverinfo,
363+
cert->pkeys[i].serverinfo,
364+
cert->pkeys[i].serverinfo_length);
365+
}
366+
#endif
348367
}
349368

350369
ret->references=1;
@@ -460,8 +479,16 @@ void ssl_cert_clear_certs(CERT *c)
460479
cpk->chain = NULL;
461480
}
462481
#ifndef OPENSSL_NO_TLSEXT
463-
if (cpk->authz != NULL)
482+
if (cpk->authz)
483+
{
464484
OPENSSL_free(cpk->authz);
485+
cpk->authz = NULL;
486+
}
487+
if (cpk->serverinfo)
488+
{
489+
OPENSSL_free(cpk->serverinfo);
490+
cpk->serverinfo = NULL;
491+
}
465492
#endif
466493
/* Clear all flags apart from explicit sign */
467494
cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN;

0 commit comments

Comments
 (0)