Security hardening: Expose Build flags for Position Independed Execution (PIE)
[openssl.git] / crypto / x509 / x509_cmp.c
index 1231fb4be1d5abf1676bbd9f60e5cfd4fec545ba..7094280d485e868590b0addd64bf66665e363151 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -39,16 +39,22 @@ unsigned long X509_issuer_and_serial_hash(X509 *a)
     unsigned long ret = 0;
     EVP_MD_CTX *ctx = EVP_MD_CTX_new();
     unsigned char md[16];
-    char *f;
+    char *f = NULL;
+    EVP_MD *digest = NULL;
 
     if (ctx == NULL)
         goto err;
     f = X509_NAME_oneline(a->cert_info.issuer, NULL, 0);
-    if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL))
+    if (f == NULL)
+        goto err;
+    digest = EVP_MD_fetch(a->libctx, SN_md5, a->propq);
+    if (digest == NULL)
+        goto err;
+
+    if (!EVP_DigestInit_ex(ctx, digest, NULL))
         goto err;
     if (!EVP_DigestUpdate(ctx, (unsigned char *)f, strlen(f)))
         goto err;
-    OPENSSL_free(f);
     if (!EVP_DigestUpdate
         (ctx, (unsigned char *)a->cert_info.serialNumber.data,
          (unsigned long)a->cert_info.serialNumber.length))
@@ -59,6 +65,8 @@ unsigned long X509_issuer_and_serial_hash(X509 *a)
            ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)
         ) & 0xffffffffL;
  err:
+    OPENSSL_free(f);
+    EVP_MD_free(digest);
     EVP_MD_CTX_free(ctx);
     return ret;
 }
@@ -81,7 +89,13 @@ int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b)
 
 int X509_CRL_match(const X509_CRL *a, const X509_CRL *b)
 {
-    int rv = memcmp(a->sha1_hash, b->sha1_hash, 20);
+    int rv;
+
+    if ((a->flags & EXFLAG_NO_FINGERPRINT) == 0
+            && (b->flags & EXFLAG_NO_FINGERPRINT) == 0)
+        rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
+    else
+        return -2;
 
     return rv < 0 ? -1 : rv > 0;
 }
@@ -140,19 +154,21 @@ unsigned long X509_subject_name_hash_old(X509 *x)
  */
 int X509_cmp(const X509 *a, const X509 *b)
 {
-    int rv;
+    int rv = 0;
 
     if (a == b) /* for efficiency */
         return 0;
-    /* ensure hash is valid */
-    if (X509_check_purpose((X509 *)a, -1, 0) != 1)
-        return -2;
-    if (X509_check_purpose((X509 *)b, -1, 0) != 1)
-        return -2;
 
-    rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
+    /* attempt to compute cert hash */
+    (void)X509_check_purpose((X509 *)a, -1, 0);
+    (void)X509_check_purpose((X509 *)b, -1, 0);
+
+    if ((a->ex_flags & EXFLAG_NO_FINGERPRINT) == 0
+            && (b->ex_flags & EXFLAG_NO_FINGERPRINT) == 0)
+        rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
     if (rv != 0)
         return rv < 0 ? -1 : 1;
+
     /* Check for match against stored encoding too */
     if (!a->cert_info.enc.modified && !b->cert_info.enc.modified) {
         if (a->cert_info.enc.len < b->cert_info.enc.len)
@@ -165,14 +181,13 @@ int X509_cmp(const X509 *a, const X509 *b)
     return rv < 0 ? -1 : rv > 0;
 }
 
-int X509_add_cert_new(STACK_OF(X509) **sk, X509 *cert, int flags)
+int ossl_x509_add_cert_new(STACK_OF(X509) **p_sk, X509 *cert, int flags)
 {
-    if (*sk == NULL
-            && (*sk = sk_X509_new_null()) == NULL) {
-        ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+    if (*p_sk == NULL && (*p_sk = sk_X509_new_null()) == NULL) {
+        ERR_raise(ERR_LIB_X509, ERR_R_CRYPTO_LIB);
         return 0;
     }
-    return X509_add_cert(*sk, cert, flags);
+    return X509_add_cert(*p_sk, cert, flags);
 }
 
 int X509_add_cert(STACK_OF(X509) *sk, X509 *cert, int flags)
@@ -193,11 +208,15 @@ int X509_add_cert(STACK_OF(X509) *sk, X509 *cert, int flags)
                 return 1;
         }
     }
-    if ((flags & X509_ADD_FLAG_NO_SS) != 0 && X509_self_signed(cert, 0))
-        return 1;
+    if ((flags & X509_ADD_FLAG_NO_SS) != 0) {
+        int ret = X509_self_signed(cert, 0);
+
+        if (ret != 0)
+            return ret > 0 ? 1 : 0;
+    }
     if (!sk_X509_insert(sk, cert,
                         (flags & X509_ADD_FLAG_PREPEND) != 0 ? 0 : -1)) {
-        ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_X509, ERR_R_CRYPTO_LIB);
         return 0;
     }
     if ((flags & X509_ADD_FLAG_UP_REF) != 0)
@@ -206,16 +225,27 @@ int X509_add_cert(STACK_OF(X509) *sk, X509 *cert, int flags)
 }
 
 int X509_add_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs, int flags)
-/* compiler would allow 'const' for the list of certs, yet they are up-ref'ed */
+/* compiler would allow 'const' for the certs, yet they may get up-ref'ed */
+{
+    if (sk == NULL) {
+        ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    return ossl_x509_add_certs_new(&sk, certs, flags);
+}
+
+int ossl_x509_add_certs_new(STACK_OF(X509) **p_sk, STACK_OF(X509) *certs,
+                            int flags)
+/* compiler would allow 'const' for the certs, yet they may get up-ref'ed */
 {
-    int n = sk_X509_num(certs); /* certs may be NULL */
+    int n = sk_X509_num(certs /* may be NULL */);
     int i;
 
     for (i = 0; i < n; i++) {
         int j = (flags & X509_ADD_FLAG_PREPEND) == 0 ? i : n - 1 - i;
         /* if prepend, add certs in reverse order to keep original order */
 
-        if (!X509_add_cert(sk, sk_X509_value(certs, j), flags))
+        if (!ossl_x509_add_cert_new(p_sk, sk_X509_value(certs, j), flags))
             return 0;
     }
     return 1;
@@ -231,21 +261,27 @@ int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b)
         return -1;
 
     /* Ensure canonical encoding is present and up to date */
-    if (!a->canon_enc || a->modified) {
+    if (a->canon_enc == NULL || a->modified) {
         ret = i2d_X509_NAME((X509_NAME *)a, NULL);
         if (ret < 0)
             return -2;
     }
 
-    if (!b->canon_enc || b->modified) {
+    if (b->canon_enc == NULL || b->modified) {
         ret = i2d_X509_NAME((X509_NAME *)b, NULL);
         if (ret < 0)
             return -2;
     }
 
     ret = a->canon_enclen - b->canon_enclen;
-    if (ret == 0 && a->canon_enclen != 0)
+    if (ret == 0 && a->canon_enclen == 0)
+        return 0;
+
+    if (ret == 0) {
+        if (a->canon_enc == NULL || b->canon_enc == NULL)
+            return -2;
         ret = memcmp(a->canon_enc, b->canon_enc, a->canon_enclen);
+    }
 
     return ret < 0 ? -1 : ret > 0;
 }
@@ -256,12 +292,13 @@ unsigned long X509_NAME_hash_ex(const X509_NAME *x, OSSL_LIB_CTX *libctx,
     unsigned long ret = 0;
     unsigned char md[SHA_DIGEST_LENGTH];
     EVP_MD *sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
+    int i2d_ret;
 
     /* Make sure X509_NAME structure contains valid cached encoding */
-    i2d_X509_NAME(x, NULL);
+    i2d_ret = i2d_X509_NAME(x, NULL);
     if (ok != NULL)
         *ok = 0;
-    if (sha1 != NULL
+    if (i2d_ret >= 0 && sha1 != NULL
         && EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, sha1, NULL)) {
         ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) |
                ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)
@@ -289,7 +326,9 @@ unsigned long X509_NAME_hash_old(const X509_NAME *x)
         goto end;
 
     /* Make sure X509_NAME structure contains valid cached encoding */
-    i2d_X509_NAME(x, NULL);
+    if (i2d_X509_NAME(x, NULL) < 0)
+        goto end;
+
     if (EVP_DigestInit_ex(md_ctx, md5, NULL)
         && EVP_DigestUpdate(md_ctx, x->bytes->data, x->bytes->length)
         && EVP_DigestFinal_ex(md_ctx, md, NULL))
@@ -353,33 +392,38 @@ EVP_PKEY *X509_get_pubkey(X509 *x)
     return X509_PUBKEY_get(x->cert_info.key);
 }
 
-int X509_check_private_key(const X509 *x, const EVP_PKEY *k)
+int X509_check_private_key(const X509 *cert, const EVP_PKEY *pkey)
 {
-    const EVP_PKEY *xk;
-    int ret;
-
-    xk = X509_get0_pubkey(x);
+    const EVP_PKEY *xk = X509_get0_pubkey(cert);
 
-    if (xk)
-        ret = EVP_PKEY_eq(xk, k);
-    else
-        ret = -2;
+    if (xk == NULL) {
+        ERR_raise(ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
+        return 0;
+    }
+    return ossl_x509_check_private_key(xk, pkey);
+}
 
-    switch (ret) {
+int ossl_x509_check_private_key(const EVP_PKEY *x, const EVP_PKEY *pkey)
+{
+    if (x == NULL) {
+        ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    switch (EVP_PKEY_eq(x, pkey)) {
     case 1:
-        break;
+        return 1;
     case 0:
         ERR_raise(ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH);
-        break;
+        return 0;
     case -1:
         ERR_raise(ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH);
-        break;
+        return 0;
     case -2:
         ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE);
+        /* fall thru */
+    default:
+        return 0;
     }
-    if (ret > 0)
-        return 1;
-    return 0;
 }
 
 /*
@@ -392,13 +436,18 @@ int X509_check_private_key(const X509 *x, const EVP_PKEY *k)
 
 static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags)
 {
-    const EC_GROUP *grp = NULL;
+    char curve_name[80];
+    size_t curve_name_len;
     int curve_nid;
-    if (pkey && EVP_PKEY_id(pkey) == EVP_PKEY_EC)
-        grp = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey));
-    if (!grp)
+
+    if (pkey == NULL || !EVP_PKEY_is_a(pkey, "EC"))
         return X509_V_ERR_SUITE_B_INVALID_ALGORITHM;
-    curve_nid = EC_GROUP_get_curve_name(grp);
+
+    if (!EVP_PKEY_get_group_name(pkey, curve_name, sizeof(curve_name),
+                                 &curve_name_len))
+        return X509_V_ERR_SUITE_B_INVALID_CURVE;
+
+    curve_nid = OBJ_txt2nid(curve_name);
     /* Check curve is consistent with LOS */
     if (curve_nid == NID_secp384r1) { /* P-384 */
         /*
@@ -449,7 +498,7 @@ int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
     if (chain == NULL)
         return check_suite_b(pk, -1, &tflags);
 
-    if (X509_get_version(x) != 2) {
+    if (X509_get_version(x) != X509_VERSION_3) {
         rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
         /* Correct error depth */
         i = 0;
@@ -466,7 +515,7 @@ int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
     for (; i < sk_X509_num(chain); i++) {
         sign_nid = X509_get_signature_nid(x);
         x = sk_X509_value(chain, i);
-        if (X509_get_version(x) != 2) {
+        if (X509_get_version(x) != X509_VERSION_3) {
             rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
             goto end;
         }
@@ -518,6 +567,7 @@ int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
 }
 
 #endif
+
 /*
  * Not strictly speaking an "up_ref" as a STACK doesn't have a reference
  * count but it has the same effect by duping the STACK and upping the ref of
@@ -525,17 +575,19 @@ int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
  */
 STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain)
 {
-    STACK_OF(X509) *ret;
+    STACK_OF(X509) *ret = sk_X509_dup(chain);
     int i;
-    ret = sk_X509_dup(chain);
+
     if (ret == NULL)
         return NULL;
     for (i = 0; i < sk_X509_num(ret); i++) {
         X509 *x = sk_X509_value(ret, i);
+
         if (!X509_up_ref(x))
             goto err;
     }
     return ret;
+
  err:
     while (i-- > 0)
         X509_free(sk_X509_value(ret, i));