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;
{
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)
}
+#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;
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;
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;
unsigned short type;
unsigned short size;
- unsigned short len;
unsigned char *data = *p;
int tlsext_servername = 0;
int renegotiate_seen = 0;
if (data >= (d+n-2))
goto ri_check;
- n2s(data,len);
+ n2s(data,length);
+ if (data+length != d+n)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
while(data <= (d+n-4))
{
/* 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))
* which doesn't support RI so for the immediate future tolerate RI
* absence on initial connect only.
*/
- if (!renegotiate_seen &&
- (s->new_session || !(s->options & SSL_OP_LEGACY_SERVER_CONNECT))
+ if (!renegotiate_seen
+ && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
&& !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
{
*al = SSL_AD_HANDSHAKE_FAILURE;