/* Provenance: openssl/openssl do_x509_check (fixed). * repo: openssl/openssl * commit: 06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6 * parent: 9aae56395aa8e77c44a9df83fd395a644d016635 * commit_url: https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6 * cve: CVE-2024-6119 * license: Apache-2.0 * function: do_x509_check * relpath: crypto/x509/v3_utl.c */ static int do_x509_check(X509 *x, const char *chk, size_t chklen, unsigned int flags, int check_type, char **peername) { GENERAL_NAMES *gens = NULL; const X509_NAME *name = NULL; int i; int cnid = NID_undef; int alt_type; int san_present = 0; int rv = 0; equal_fn equal; /* See below, this flag is internal-only */ flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS; if (check_type == GEN_EMAIL) { cnid = NID_pkcs9_emailAddress; alt_type = V_ASN1_IA5STRING; equal = equal_email; } else if (check_type == GEN_DNS) { cnid = NID_commonName; /* Implicit client-side DNS sub-domain pattern */ if (chklen > 1 && chk[0] == '.') flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; alt_type = V_ASN1_IA5STRING; if (flags & X509_CHECK_FLAG_NO_WILDCARDS) equal = equal_nocase; else equal = equal_wildcard; } else { alt_type = V_ASN1_OCTET_STRING; equal = equal_case; } if (chklen == 0) chklen = strlen(chk); gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); if (gens) { for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { GENERAL_NAME *gen; ASN1_STRING *cstr; gen = sk_GENERAL_NAME_value(gens, i); switch (gen->type) { default: continue; case GEN_OTHERNAME: switch (OBJ_obj2nid(gen->d.otherName->type_id)) { default: continue; case NID_id_on_SmtpUTF8Mailbox: /*- * https://datatracker.ietf.org/doc/html/rfc8398#section-3 * * Due to name constraint compatibility reasons described * in Section 6, SmtpUTF8Mailbox subjectAltName MUST NOT * be used unless the local-part of the email address * contains non-ASCII characters. When the local-part is * ASCII, rfc822Name subjectAltName MUST be used instead * of SmtpUTF8Mailbox. This is compatible with legacy * software that supports only rfc822Name (and not * SmtpUTF8Mailbox). [...] * * SmtpUTF8Mailbox is encoded as UTF8String. * * If it is not a UTF8String then that is unexpected, and * we ignore the invalid SAN (neither set san_present nor * consider it a candidate for equality). This does mean * that the subject CN may be considered, as would be the * case when the malformed SmtpUtf8Mailbox SAN is instead * simply absent. * * When CN-ID matching is not desirable, applications can * choose to turn it off, doing so is at this time a best * practice. */ if (check_type != GEN_EMAIL || gen->d.otherName->value->type != V_ASN1_UTF8STRING) continue; alt_type = 0; cstr = gen->d.otherName->value->value.utf8string; break; } break; case GEN_EMAIL: if (check_type != GEN_EMAIL) continue; cstr = gen->d.rfc822Name; break; case GEN_DNS: if (check_type != GEN_DNS) continue; cstr = gen->d.dNSName; break; case GEN_IPADD: if (check_type != GEN_IPADD) continue; cstr = gen->d.iPAddress; break; } san_present = 1; /* Positive on success, negative on error! */ if ((rv = do_check_string(cstr, alt_type, equal, flags, chk, chklen, peername)) != 0) break; } GENERAL_NAMES_free(gens); if (rv != 0) return rv; if (san_present && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)) return 0; } /* We're done if CN-ID is not pertinent */ if (cnid == NID_undef || (flags & X509_CHECK_FLAG_NEVER_CHECK_SUBJECT)) return 0; i = -1; name = X509_get_subject_name(x); while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) { const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne); /* Positive on success, negative on error! */ if ((rv = do_check_string(str, -1, equal, flags, chk, chklen, peername)) != 0) return rv; } return 0; }