Check for EVP_MD being NULL inside ssl.
authorslontis <shane.lontis@oracle.com>
Tue, 12 Jul 2022 04:28:37 +0000 (14:28 +1000)
committerHugo Landau <hlandau@openssl.org>
Wed, 13 Jul 2022 07:03:17 +0000 (08:03 +0100)
Fix multiple places that could potentially segfault if memory
allocations fail. e.g. ssl_load_ciphers() could fail while calling
ssl_evp_md_fetch().

Found by #18355

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/18784)

(cherry picked from commit b740012f77aed97cb4b3cd8a4f1fb2f668542795)

ssl/s3_lib.c
ssl/ssl_ciph.c
ssl/statem/extensions_srvr.c
ssl/statem/statem_clnt.c
ssl/tls13_enc.c

index f530c5066d6baab2d6193a25fd629de480c499fd..78d4f040565d1d54f83abbd4fc73504f614846b7 100644 (file)
@@ -4301,9 +4301,10 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
 
             if (prefer_sha256) {
                 const SSL_CIPHER *tmp = sk_SSL_CIPHER_value(allow, ii);
+                const EVP_MD *md = ssl_md(s->ctx, tmp->algorithm2);
 
-                if (EVP_MD_is_a(ssl_md(s->ctx, tmp->algorithm2),
-                                       OSSL_DIGEST_NAME_SHA2_256)) {
+                if (md != NULL
+                        && EVP_MD_is_a(md, OSSL_DIGEST_NAME_SHA2_256)) {
                     ret = tmp;
                     break;
                 }
index 54431b79c66a5bf7cbfe98c659537d31f23f2f44..942ab5c6db81822f783e757347ce56ad0bf2e054 100644 (file)
@@ -555,11 +555,14 @@ int ssl_cipher_get_evp(SSL_CTX *ctx, const SSL_SESSION *s,
         if (c->algorithm_mac == SSL_AEAD)
             mac_pkey_type = NULL;
     } else {
-        if (!ssl_evp_md_up_ref(ctx->ssl_digest_methods[i])) {
+        const EVP_MD *digest = ctx->ssl_digest_methods[i];
+
+        if (digest == NULL
+                || !ssl_evp_md_up_ref(digest)) {
             ssl_evp_cipher_free(*enc);
             return 0;
         }
-        *md = ctx->ssl_digest_methods[i];
+        *md = digest;
         if (mac_pkey_type != NULL)
             *mac_pkey_type = ctx->ssl_mac_pkey_id[i];
         if (mac_secret_size != NULL)
index 7a38e01e436c8d9832f7261bbfdd05ba973f9cce..bf89e8247d6ad454cbe9dd7cdddeedcc6a5a27a2 100644 (file)
@@ -1154,6 +1154,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         }
 
         md = ssl_md(s->ctx, sess->cipher->algorithm2);
+        if (md == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
         if (!EVP_MD_is_a(md,
                 EVP_MD_get0_name(ssl_md(s->ctx,
                                         s->s3.tmp.new_cipher->algorithm2)))) {
index b59eddae332a72bd4449fa6a2f9e2688027bd729..3af7234342d2d31b9e6cfe309868c46398c91905 100644 (file)
@@ -1346,12 +1346,14 @@ static int set_client_ciphersuite(SSL *s, const unsigned char *cipherchars)
         s->session->cipher_id = s->session->cipher->id;
     if (s->hit && (s->session->cipher_id != c->id)) {
         if (SSL_IS_TLS13(s)) {
+            const EVP_MD *md = ssl_md(s->ctx, c->algorithm2);
+
             /*
              * In TLSv1.3 it is valid for the server to select a different
              * ciphersuite as long as the hash is the same.
              */
-            if (ssl_md(s->ctx, c->algorithm2)
-                    != ssl_md(s->ctx, s->session->cipher->algorithm2)) {
+            if (md == NULL
+                    || md != ssl_md(s->ctx, s->session->cipher->algorithm2)) {
                 SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
                          SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED);
                 return 0;
index 13b4d71a1e4d6674ef22f795142c8397346ddcc4..07d065e35e957accfc5e952154252bde40b79e7f 100644 (file)
@@ -257,13 +257,17 @@ int tls13_generate_master_secret(SSL *s, unsigned char *out,
 size_t tls13_final_finish_mac(SSL *s, const char *str, size_t slen,
                              unsigned char *out)
 {
-    const char *mdname = EVP_MD_get0_name(ssl_handshake_md(s));
+    const EVP_MD *md = ssl_handshake_md(s);
+    const char *mdname = EVP_MD_get0_name(md);
     unsigned char hash[EVP_MAX_MD_SIZE];
     unsigned char finsecret[EVP_MAX_MD_SIZE];
     unsigned char *key = NULL;
     size_t len = 0, hashlen;
     OSSL_PARAM params[2], *p = params;
 
+    if (md == NULL)
+        return 0;
+
     /* Safe to cast away const here since we're not "getting" any data */
     if (s->ctx->propq != NULL)
         *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_PROPERTIES,
@@ -281,7 +285,7 @@ size_t tls13_final_finish_mac(SSL *s, const char *str, size_t slen,
     } else if (SSL_IS_FIRST_HANDSHAKE(s)) {
         key = s->client_finished_secret;
     } else {
-        if (!tls13_derive_finishedkey(s, ssl_handshake_md(s),
+        if (!tls13_derive_finishedkey(s, md,
                                       s->client_app_traffic_secret,
                                       finsecret, hashlen))
             goto err;
@@ -770,7 +774,7 @@ int tls13_update_key(SSL *s, int sending)
         RECORD_LAYER_reset_read_sequence(&s->rlayer);
     }
 
-    if (!derive_secret_key_and_iv(s, sending, ssl_handshake_md(s),
+    if (!derive_secret_key_and_iv(s, sending, md,
                                   s->s3.tmp.new_sym_enc, insecret, NULL,
                                   application_traffic,
                                   sizeof(application_traffic) - 1, secret, key,
@@ -815,7 +819,7 @@ int tls13_export_keying_material(SSL *s, unsigned char *out, size_t olen,
     unsigned int hashsize, datalen;
     int ret = 0;
 
-    if (ctx == NULL || !ossl_statem_export_allowed(s))
+    if (ctx == NULL || md == NULL || !ossl_statem_export_allowed(s))
         goto err;
 
     if (!use_context)
@@ -884,7 +888,8 @@ int tls13_export_keying_material_early(SSL *s, unsigned char *out, size_t olen,
      *
      * Here Transcript-Hash is the cipher suite hash algorithm.
      */
-    if (EVP_DigestInit_ex(ctx, md, NULL) <= 0
+    if (md == NULL
+            || EVP_DigestInit_ex(ctx, md, NULL) <= 0
             || EVP_DigestUpdate(ctx, context, contextlen) <= 0
             || EVP_DigestFinal_ex(ctx, hash, &hashsize) <= 0
             || EVP_DigestInit_ex(ctx, md, NULL) <= 0