/* Provenance: openssl/openssl tls_handle_alpn (fixed). * repo: openssl/openssl * commit: 39a140597d874e554b736885ac4dea16ac40a87a * parent: 02b1636fe3db274497304a3e95a4e32ced7e841b * commit_url: https://github.com/openssl/openssl/commit/39a140597d874e554b736885ac4dea16ac40a87a * cve: CVE-2021-3449 * license: OpenSSL License * function: tls_handle_alpn * relpath: ssl/statem/statem_srvr.c */ int tls_handle_alpn(SSL *s) { 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) { s->s3.alpn_selected_len = 0; SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_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 /* 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) { /* * This is a new session and so alpn_selected should have * been initialised to NULL. We should update it with the * selected ALPN. */ if (!ossl_assert(s->session->ext.alpn_selected == NULL)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } s->session->ext.alpn_selected = OPENSSL_memdup(selected, selected_len); if (s->session->ext.alpn_selected == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; } s->session->ext.alpn_selected_len = selected_len; } } return 1; } else if (r != SSL_TLSEXT_ERR_NOACK) { SSLfatal(s, SSL_AD_NO_APPLICATION_PROTOCOL, SSL_R_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; }