Skip to content

Commit af2db04

Browse files
tmshortRich Salz
authored andcommitted
Fix ALPN
* Perform ALPN after the SNI callback; the SSL_CTX may change due to that processing * Add flags to indicate that we actually sent ALPN, to properly error out if unexpectedly received. * document ALPN functions * unit tests Backport of commit 817cd0d Reviewed-by: Emilia Käsper <[email protected]> Reviewed-by: Dr. Stephen Henson <[email protected]>
1 parent 21211ad commit af2db04

File tree

8 files changed

+399
-42
lines changed

8 files changed

+399
-42
lines changed

CHANGES

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

55
Changes between 1.0.2g and 1.0.2h [xx XXX xxxx]
66

7+
*) Modify behavior of ALPN to invoke callback after SNI/servername
8+
callback, such that updates to the SSL_CTX affect ALPN.
9+
[Todd Short]
10+
711
*) Remove LOW from the DEFAULT cipher list. This removes singles DES from the
812
default.
913
[Kurt Roeckx]
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
=pod
2+
3+
=head1 NAME
4+
5+
SSL_CTX_set_alpn_protos, SSL_set_alpn_protos, SSL_CTX_set_alpn_select_cb,
6+
SSL_select_next_proto, SSL_get0_alpn_selected - handle application layer
7+
protocol negotiation (ALPN)
8+
9+
=head1 SYNOPSIS
10+
11+
#include <openssl/ssl.h>
12+
13+
int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
14+
unsigned protos_len);
15+
int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
16+
unsigned protos_len);
17+
void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
18+
int (*cb) (SSL *ssl,
19+
const unsigned char **out,
20+
unsigned char *outlen,
21+
const unsigned char *in,
22+
unsigned int inlen,
23+
void *arg), void *arg);
24+
int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
25+
const unsigned char *server,
26+
unsigned int server_len,
27+
const unsigned char *client,
28+
unsigned int client_len)
29+
void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
30+
unsigned int *len);
31+
32+
=head1 DESCRIPTION
33+
34+
SSL_CTX_set_alpn_protos() and SSL_set_alpn_protos() are used by the client to
35+
set the list of protocols available to be negotiated. The B<protos> must be in
36+
protocol-list format, described below. The length of B<protos> is specified in
37+
B<protos_len>.
38+
39+
SSL_CTX_set_alpn_select_cb() sets the application callback B<cb> used by a
40+
server to select which protocol to use for the incoming connection. When B<cb>
41+
is NULL, ALPN is not used. The B<arg> value is a pointer which is passed to
42+
the application callback.
43+
44+
B<cb> is the application defined callback. The B<in>, B<inlen> parameters are a
45+
vector in protocol-list format. The value of the B<out>, B<outlen> vector
46+
should be set to the value of a single protocol selected from the B<in>,
47+
B<inlen> vector. The B<arg> parameter is the pointer set via
48+
SSL_CTX_set_alpn_select_cb().
49+
50+
SSL_select_next_proto() is a helper function used to select protocols. It
51+
implements the standard protocol selection. It is expected that this function
52+
is called from the application callback B<cb>. The protocol data in B<server>,
53+
B<server_len> and B<client>, B<client_len> must be in the protocol-list format
54+
described below. The first item in the B<server>, B<server_len> list that
55+
matches an item in the B<client>, B<client_len> list is selected, and returned
56+
in B<out>, B<outlen>. The B<out> value will point into either B<server> or
57+
B<client>, so it should be copied immediately. If no match is found, the first
58+
item in B<client>, B<client_len> is returned in B<out>, B<outlen>. This
59+
function can also be used in the NPN callback.
60+
61+
SSL_get0_alpn_selected() returns a pointer to the selected protocol in B<data>
62+
with length B<len>. It is not NUL-terminated. B<data> is set to NULL and B<len>
63+
is set to 0 if no protocol has been selected. B<data> must not be freed.
64+
65+
=head1 NOTES
66+
67+
The protocol-lists must be in wire-format, which is defined as a vector of
68+
non-empty, 8-bit length-prefixed, byte strings. The length-prefix byte is not
69+
included in the length. Each string is limited to 255 bytes. A byte-string
70+
length of 0 is invalid. A truncated byte-string is invalid. The length of the
71+
vector is not in the vector itself, but in a separate variable.
72+
73+
Example:
74+
75+
unsigned char vector[] = {
76+
6, 's', 'p', 'd', 'y', '/', '1',
77+
8, 'h', 't', 't', 'p', '/', '1', '.', '1'
78+
};
79+
unsigned int length = sizeof(vector);
80+
81+
The ALPN callback is executed after the servername callback; as that servername
82+
callback may update the SSL_CTX, and subsequently, the ALPN callback.
83+
84+
If there is no ALPN proposed in the ClientHello, the ALPN callback is not
85+
invoked.
86+
87+
=head1 RETURN VALUES
88+
89+
SSL_CTX_set_alpn_protos() and SSL_set_alpn_protos() return 0 on success, and
90+
non-0 on failure. WARNING: these functions reverse the return value convention.
91+
92+
SSL_select_next_proto() returns one of the following:
93+
94+
=over 4
95+
96+
=item OPENSSL_NPN_NEGOTIATED
97+
98+
A match was found and is returned in B<out>, B<outlen>.
99+
100+
=item OPENSSL_NPN_NO_OVERLAP
101+
102+
No match was found. The first item in B<client>, B<client_len> is returned in
103+
B<out>, B<outlen>.
104+
105+
=back
106+
107+
The ALPN select callback B<cb>, must return one of the following:
108+
109+
=over 4
110+
111+
=item SSL_TLSEXT_ERR_OK
112+
113+
ALPN protocol selected.
114+
115+
=item SSL_TLSEXT_ERR_NOACK
116+
117+
ALPN protocol not selected.
118+
119+
=back
120+
121+
=head1 SEE ALSO
122+
123+
L<ssl(3)>, L<SSL_CTX_set_tlsext_servername_callback(3)>,
124+
L<SSL_CTX_set_tlsext_servername_arg(3)>
125+
126+
=cut

ssl/ssl_cert.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,8 @@ void ssl_cert_free(CERT *c)
504504
#ifndef OPENSSL_NO_TLSEXT
505505
custom_exts_free(&c->cli_ext);
506506
custom_exts_free(&c->srv_ext);
507+
if (c->alpn_proposed)
508+
OPENSSL_free(c->alpn_proposed);
507509
#endif
508510
OPENSSL_free(c);
509511
}

ssl/ssl_lib.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,16 @@ int SSL_clear(SSL *s)
244244
ssl_clear_hash_ctx(&s->write_hash);
245245

246246
s->first_packet = 0;
247-
247+
#ifndef OPENSSL_NO_TLSEXT
248+
if (s->cert != NULL) {
249+
if (s->cert->alpn_proposed) {
250+
OPENSSL_free(s->cert->alpn_proposed);
251+
s->cert->alpn_proposed = NULL;
252+
}
253+
s->cert->alpn_proposed_len = 0;
254+
s->cert->alpn_sent = 0;
255+
}
256+
#endif
248257
#if 1
249258
/*
250259
* Check to see if we were changed into a different method, if so, revert
@@ -3174,6 +3183,12 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
31743183
ssl->cert->ciphers_rawlen = ocert->ciphers_rawlen;
31753184
ocert->ciphers_raw = NULL;
31763185
}
3186+
#ifndef OPENSSL_NO_TLSEXT
3187+
ssl->cert->alpn_proposed = ocert->alpn_proposed;
3188+
ssl->cert->alpn_proposed_len = ocert->alpn_proposed_len;
3189+
ocert->alpn_proposed = NULL;
3190+
ssl->cert->alpn_sent = ocert->alpn_sent;
3191+
#endif
31773192
ssl_cert_free(ocert);
31783193
}
31793194

ssl/ssl_locl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,10 @@ typedef struct cert_st {
688688
custom_ext_methods cli_ext;
689689
custom_ext_methods srv_ext;
690690
int references; /* >1 only if SSL_copy_session_id is used */
691+
/* non-optimal, but here due to compatibility */
692+
unsigned char *alpn_proposed; /* server */
693+
unsigned int alpn_proposed_len;
694+
int alpn_sent; /* client */
691695
} CERT;
692696

693697
typedef struct sess_cert_st {

0 commit comments

Comments
 (0)