Add Next Protocol Negotiation.
This commit is contained in:
112
ssl/t1_lib.c
112
ssl/t1_lib.c
@@ -494,6 +494,18 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NPN
|
||||
if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
|
||||
{
|
||||
/* The client advertises an emtpy extension to indicate its
|
||||
* support for Next Protocol Negotiation */
|
||||
if (limit - ret - 4 < 0)
|
||||
return NULL;
|
||||
s2n(TLSEXT_TYPE_next_proto_neg,ret);
|
||||
s2n(0,ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((extdatalen = ret-p-2)== 0)
|
||||
return p;
|
||||
|
||||
@@ -505,6 +517,9 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
{
|
||||
int extdatalen=0;
|
||||
unsigned char *ret = p;
|
||||
#ifndef OPENSSL_NO_NPN
|
||||
char next_proto_neg_seen;
|
||||
#endif
|
||||
|
||||
/* don't add extensions for SSLv3, unless doing secure renegotiation */
|
||||
if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
|
||||
@@ -618,6 +633,28 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
||||
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NPN
|
||||
next_proto_neg_seen = s->s3->next_proto_neg_seen;
|
||||
s->s3->next_proto_neg_seen = 0;
|
||||
if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb)
|
||||
{
|
||||
const unsigned char *npa;
|
||||
unsigned int npalen;
|
||||
int r;
|
||||
|
||||
r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg);
|
||||
if (r == SSL_TLSEXT_ERR_OK)
|
||||
{
|
||||
if ((long)(limit - ret - 4 - npalen) < 0) return NULL;
|
||||
s2n(TLSEXT_TYPE_next_proto_neg,ret);
|
||||
s2n(npalen,ret);
|
||||
memcpy(ret, npa, npalen);
|
||||
ret += npalen;
|
||||
s->s3->next_proto_neg_seen = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((extdatalen = ret-p-2)== 0)
|
||||
return p;
|
||||
|
||||
@@ -958,6 +995,28 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
else
|
||||
s->tlsext_status_type = -1;
|
||||
}
|
||||
#ifndef OPENSSL_NO_NPN
|
||||
else if (type == TLSEXT_TYPE_next_proto_neg &&
|
||||
s->s3->tmp.finish_md_len == 0)
|
||||
{
|
||||
/* We shouldn't accept this extension on a
|
||||
* renegotiation.
|
||||
*
|
||||
* s->new_session will be set on renegotiation, but we
|
||||
* probably shouldn't rely that it couldn't be set on
|
||||
* the initial renegotation too in certain cases (when
|
||||
* there's some other reason to disallow resuming an
|
||||
* earlier session -- the current code won't be doing
|
||||
* anything like that, but this might change).
|
||||
|
||||
* A valid sign that there's been a previous handshake
|
||||
* in this connection is if s->s3->tmp.finish_md_len >
|
||||
* 0. (We are talking about a check that will happen
|
||||
* in the Hello protocol round, well before a new
|
||||
* Finished message could have been computed.) */
|
||||
s->s3->next_proto_neg_seen = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* session ticket processed earlier */
|
||||
data+=size;
|
||||
@@ -981,6 +1040,26 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NPN
|
||||
/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
|
||||
* elements of zero length are allowed and the set of elements must exactly fill
|
||||
* the length of the block. */
|
||||
static char ssl_next_proto_validate(unsigned char *d, unsigned len)
|
||||
{
|
||||
unsigned int off = 0;
|
||||
|
||||
while (off < len)
|
||||
{
|
||||
if (d[off] == 0)
|
||||
return 0;
|
||||
off += d[off];
|
||||
off++;
|
||||
}
|
||||
|
||||
return off == len;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
|
||||
{
|
||||
unsigned short length;
|
||||
@@ -1115,6 +1194,39 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
||||
/* Set flag to expect CertificateStatus message */
|
||||
s->tlsext_status_expected = 1;
|
||||
}
|
||||
#ifndef OPENSSL_NO_NPN
|
||||
else if (type == TLSEXT_TYPE_next_proto_neg)
|
||||
{
|
||||
unsigned char *selected;
|
||||
unsigned char selected_len;
|
||||
|
||||
/* We must have requested it. */
|
||||
if ((s->ctx->next_proto_select_cb == NULL))
|
||||
{
|
||||
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
|
||||
return 0;
|
||||
}
|
||||
/* The data must be valid */
|
||||
if (!ssl_next_proto_validate(data, size))
|
||||
{
|
||||
*al = TLS1_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, data, size, s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK)
|
||||
{
|
||||
*al = TLS1_AD_INTERNAL_ERROR;
|
||||
return 0;
|
||||
}
|
||||
s->next_proto_negotiated = OPENSSL_malloc(selected_len);
|
||||
if (!s->next_proto_negotiated)
|
||||
{
|
||||
*al = TLS1_AD_INTERNAL_ERROR;
|
||||
return 0;
|
||||
}
|
||||
memcpy(s->next_proto_negotiated, selected, selected_len);
|
||||
s->next_proto_negotiated_len = selected_len;
|
||||
}
|
||||
#endif
|
||||
else if (type == TLSEXT_TYPE_renegotiate)
|
||||
{
|
||||
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
|
||||
|
Reference in New Issue
Block a user