summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorTodd Short <tshort@akamai.com>2021-03-22 12:56:36 -0400
committerTomas Mraz <tomas@openssl.org>2021-04-13 12:31:02 +0200
commit86a90dc749af91f8a7b8da6628c9ffca2bae3009 (patch)
tree19dcc6dd6c5960ab0e55a920d75517cb716e0f0a /ssl
parentf82f5392f39797c1cf3a5d114c0125f121b0f769 (diff)
Handle set_alpn_protos inputs better.
It's possible to set an invalid protocol list that will be sent in a ClientHello. This validates the inputs to make sure this does not happen. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14679)
Diffstat (limited to 'ssl')
-rw-r--r--ssl/ssl_lib.c49
1 files changed, 43 insertions, 6 deletions
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 58f8f3c14c..5501ecdb58 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2829,6 +2829,19 @@ void SSL_CTX_set_npn_select_cb(SSL_CTX *ctx,
}
#endif
+static int alpn_value_ok(const unsigned char *protos, unsigned int protos_len)
+{
+ unsigned int idx;
+
+ if (protos_len < 2 || protos == NULL)
+ return 0;
+
+ for (idx = 0; idx < protos_len; idx += protos[idx] + 1) {
+ if (protos[idx] == 0)
+ return 0;
+ }
+ return idx == protos_len;
+}
/*
* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
* |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
@@ -2837,13 +2850,25 @@ void SSL_CTX_set_npn_select_cb(SSL_CTX *ctx,
int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
unsigned int protos_len)
{
- OPENSSL_free(ctx->ext.alpn);
- ctx->ext.alpn = OPENSSL_memdup(protos, protos_len);
- if (ctx->ext.alpn == NULL) {
+ unsigned char *alpn;
+
+ if (protos_len == 0 || protos == NULL) {
+ OPENSSL_free(ctx->ext.alpn);
+ ctx->ext.alpn = NULL;
ctx->ext.alpn_len = 0;
+ return 0;
+ }
+ /* Not valid per RFC */
+ if (!alpn_value_ok(protos, protos_len))
+ return 1;
+
+ alpn = OPENSSL_memdup(protos, protos_len);
+ if (alpn == NULL) {
SSLerr(SSL_F_SSL_CTX_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
return 1;
}
+ OPENSSL_free(ctx->ext.alpn);
+ ctx->ext.alpn = alpn;
ctx->ext.alpn_len = protos_len;
return 0;
@@ -2857,13 +2882,25 @@ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
unsigned int protos_len)
{
- OPENSSL_free(ssl->ext.alpn);
- ssl->ext.alpn = OPENSSL_memdup(protos, protos_len);
- if (ssl->ext.alpn == NULL) {
+ unsigned char *alpn;
+
+ if (protos_len == 0 || protos == NULL) {
+ OPENSSL_free(ssl->ext.alpn);
+ ssl->ext.alpn = NULL;
ssl->ext.alpn_len = 0;
+ return 0;
+ }
+ /* Not valid per RFC */
+ if (!alpn_value_ok(protos, protos_len))
+ return 1;
+
+ alpn = OPENSSL_memdup(protos, protos_len);
+ if (alpn == NULL) {
SSLerr(SSL_F_SSL_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
return 1;
}
+ OPENSSL_free(ssl->ext.alpn);
+ ssl->ext.alpn = alpn;
ssl->ext.alpn_len = protos_len;
return 0;