Add Next Protocol Negotiation.

This commit is contained in:
Ben Laurie
2010-07-28 10:06:55 +00:00
parent b122e482f9
commit ee2ffc2794
18 changed files with 722 additions and 3 deletions

View File

@@ -538,7 +538,14 @@ int ssl3_accept(SSL *s)
* the client uses its key from the certificate
* for key exchange.
*/
#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NPN)
s->state=SSL3_ST_SR_FINISHED_A;
#else
if (s->s3->next_proto_neg_seen)
s->state=SSL3_ST_SR_NEXT_PROTO_A;
else
s->state=SSL3_ST_SR_FINISHED_A;
#endif
s->init_num = 0;
}
else
@@ -581,10 +588,27 @@ int ssl3_accept(SSL *s)
ret=ssl3_get_cert_verify(s);
if (ret <= 0) goto end;
#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NPN)
s->state=SSL3_ST_SR_FINISHED_A;
#else
if (s->s3->next_proto_neg_seen)
s->state=SSL3_ST_SR_NEXT_PROTO_A;
else
s->state=SSL3_ST_SR_FINISHED_A;
#endif
s->init_num=0;
break;
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
case SSL3_ST_SR_NEXT_PROTO_A:
case SSL3_ST_SR_NEXT_PROTO_B:
ret=ssl3_get_next_proto(s);
if (ret <= 0) goto end;
s->init_num = 0;
s->state=SSL3_ST_SR_FINISHED_A;
break;
#endif
case SSL3_ST_SR_FINISHED_A:
case SSL3_ST_SR_FINISHED_B:
ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
@@ -655,7 +679,16 @@ int ssl3_accept(SSL *s)
if (ret <= 0) goto end;
s->state=SSL3_ST_SW_FLUSH;
if (s->hit)
{
#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NPN)
s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
#else
if (s->s3->next_proto_neg_seen)
s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A;
else
s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
#endif
}
else
s->s3->tmp.next_state=SSL_ST_OK;
s->init_num=0;
@@ -3177,4 +3210,72 @@ int ssl3_send_cert_status(SSL *s)
/* SSL3_ST_SW_CERT_STATUS_B */
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
}
# ifndef OPENSSL_NO_NPN
/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
* sets the next_proto member in s if found */
int ssl3_get_next_proto(SSL *s)
{
int ok;
unsigned proto_len, padding_len;
long n;
const unsigned char *p;
/* Clients cannot send a NextProtocol message if we didn't see the
* extension in their ClientHello */
if (!s->s3->next_proto_neg_seen)
{
SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
return -1;
}
n=s->method->ssl_get_message(s,
SSL3_ST_SR_NEXT_PROTO_A,
SSL3_ST_SR_NEXT_PROTO_B,
SSL3_MT_NEXT_PROTO,
129,
&ok);
if (!ok)
return((int)n);
/* s->state doesn't reflect whether ChangeCipherSpec has been received
* in this handshake, but s->s3->change_cipher_spec does (will be reset
* by ssl3_get_finished). */
if (!s->s3->change_cipher_spec)
{
SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
return -1;
}
if (n < 2)
return 0; /* The body must be > 1 bytes long */
p=(unsigned char *)s->init_msg;
/* The payload looks like:
* uint8 proto_len;
* uint8 proto[proto_len];
* uint8 padding_len;
* uint8 padding[padding_len];
*/
proto_len = p[0];
if (proto_len + 2 > s->init_num)
return 0;
padding_len = p[proto_len + 1];
if (proto_len + padding_len + 2 != s->init_num)
return 0;
s->next_proto_negotiated = OPENSSL_malloc(proto_len);
if (!s->next_proto_negotiated)
{
SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE);
return 0;
}
memcpy(s->next_proto_negotiated, p + 1, proto_len);
s->next_proto_negotiated_len = proto_len;
return 1;
}
# endif
#endif