*/
if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
if (clienthello->dtls_cookie_len == 0)
- return 1;
+ return MSG_PROCESS_FINISHED_READING;
}
}
DOWNGRADE dgrd = DOWNGRADE_NONE;
/* Finished parsing the ClientHello, now we can start processing it */
- /* Give the early callback a crack at things */
- if (s->ctx->early_cb != NULL) {
- int code;
- /* A failure in the early callback terminates the connection. */
- code = s->ctx->early_cb(s, &al, s->ctx->early_cb_arg);
- if (code == 0)
+ /* Give the ClientHello callback a crack at things */
+ if (s->ctx->client_hello_cb != NULL) {
+ /* A failure in the ClientHello callback terminates the connection. */
+ switch (s->ctx->client_hello_cb(s, &al, s->ctx->client_hello_cb_arg)) {
+ case SSL_CLIENT_HELLO_SUCCESS:
+ break;
+ case SSL_CLIENT_HELLO_RETRY:
+ s->rwstate = SSL_CLIENT_HELLO_CB;
+ return -1;
+ case SSL_CLIENT_HELLO_ERROR:
+ default:
goto err;
- if (code < 0) {
- s->rwstate = SSL_EARLY_WORK;
- return code;
}
}
* Call the alpn_select callback if needed. Upon success, returns 1.
* Upon failure, returns 0 and sets |*al| to the appropriate fatal alert.
*/
-static int tls_handle_alpn(SSL *s, int *al)
+int tls_handle_alpn(SSL *s, int *al)
{
const unsigned char *selected = NULL;
unsigned char selected_len = 0;
/* ALPN takes precedence over NPN. */
s->s3->npn_seen = 0;
#endif
- } else if (r == SSL_TLSEXT_ERR_NOACK) {
- /* Behave as if no callback was present. */
+
+ /* Check ALPN is consistent with session */
+ if (s->session->ext.alpn_selected == NULL
+ || selected_len != s->session->ext.alpn_selected_len
+ || memcmp(selected, s->session->ext.alpn_selected,
+ selected_len) != 0) {
+ /* Not consistent so can't be used for early_data */
+ s->ext.early_data_ok = 0;
+
+ if (!s->hit) {
+ /* If a new session update it with the new ALPN value */
+ s->session->ext.alpn_selected = OPENSSL_memdup(selected,
+ selected_len);
+ if (s->session->ext.alpn_selected == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->ext.alpn_selected_len = selected_len;
+ }
+ }
+
return 1;
- } else {
+ } else if (r != SSL_TLSEXT_ERR_NOACK) {
*al = SSL_AD_NO_APPLICATION_PROTOCOL;
return 0;
}
+ /*
+ * If r == SSL_TLSEXT_ERR_NOACK then behave as if no callback was
+ * present.
+ */
+ }
+
+ /* Check ALPN is consistent with session */
+ if (s->session->ext.alpn_selected != NULL) {
+ /* Not consistent so can't be used for early_data */
+ s->ext.early_data_ok = 0;
}
return 1;
}
/*
* Call alpn_select callback if needed. Has to be done after SNI and
- * cipher negotiation (HTTP/2 restricts permitted ciphers).
+ * cipher negotiation (HTTP/2 restricts permitted ciphers). In TLSv1.3
+ * we already did this because cipher negotiation happens earlier, and
+ * we must handle ALPN before we decide whether to accept early_data.
*/
- if (!tls_handle_alpn(s, &al)) {
+ if (!SSL_IS_TLS13(s) && !tls_handle_alpn(s, &al)) {
SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
SSL_R_CLIENTHELLO_TLSEXT);
goto f_err;
MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
{
- int i, al = SSL_AD_INTERNAL_ERROR, ret = MSG_PROCESS_ERROR;
+ int i, al = SSL_AD_INTERNAL_ERROR;
+ MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
X509 *x = NULL;
unsigned long l, llen;
const unsigned char *certstart, *certbytes;