static int init_npn(SSL *s, unsigned int context);
#endif
static int init_alpn(SSL *s, unsigned int context);
-static int final_alpn(SSL *s, unsigned int context, int sent, int *al);
static int init_sig_algs(SSL *s, unsigned int context);
static int init_certificate_authorities(SSL *s, unsigned int context);
static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO
| SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
init_alpn, tls_parse_ctos_alpn, tls_parse_stoc_alpn,
- tls_construct_stoc_alpn, tls_construct_ctos_alpn, final_alpn
+ tls_construct_stoc_alpn, tls_construct_ctos_alpn, NULL
},
#ifndef OPENSSL_NO_SRTP
{
return 1;
}
-static int final_alpn(SSL *s, unsigned int context, int sent, int *al)
-{
- const unsigned char *selected = NULL;
- unsigned char selected_len = 0;
-
- if (!s->server)
- return 1;
-
- if (s->ctx->ext.alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
- int r = s->ctx->ext.alpn_select_cb(s, &selected, &selected_len,
- s->s3->alpn_proposed,
- (unsigned int)s->s3->alpn_proposed_len,
- s->ctx->ext.alpn_select_cb_arg);
-
- if (r == SSL_TLSEXT_ERR_OK) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
- if (s->s3->alpn_selected == NULL) {
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- s->s3->alpn_selected_len = selected_len;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* 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. */
- return 1;
- } else {
- *al = SSL_AD_NO_APPLICATION_PROTOCOL;
- return 0;
- }
- }
-
- return 1;
-}
-
static int init_sig_algs(SSL *s, unsigned int context)
{
/* Clear any signature algorithms extension received */
return 1;
}
+/*
+ * 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)
+{
+ const unsigned char *selected = NULL;
+ unsigned char selected_len = 0;
+
+ if (s->ctx->ext.alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
+ int r = s->ctx->ext.alpn_select_cb(s, &selected, &selected_len,
+ s->s3->alpn_proposed,
+ (unsigned int)s->s3->alpn_proposed_len,
+ s->ctx->ext.alpn_select_cb_arg);
+
+ if (r == SSL_TLSEXT_ERR_OK) {
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
+ if (s->s3->alpn_selected == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->s3->alpn_selected_len = selected_len;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ /* 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. */
+ return 1;
+ } else {
+ *al = SSL_AD_NO_APPLICATION_PROTOCOL;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
{
int al = SSL_AD_HANDSHAKE_FAILURE;
SSL_R_CLIENTHELLO_TLSEXT);
goto f_err;
}
+ /*
+ * Call alpn_select callback if needed. Has to be done after SNI and
+ * cipher negotiation (HTTP/2 restricts permitted ciphers).
+ */
+ if (!tls_handle_alpn(s, &al)) {
+ SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+ SSL_R_CLIENTHELLO_TLSEXT);
+ goto f_err;
+ }
wst = WORK_MORE_C;
}