mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-26 20:12:44 +00:00
Avoid type errors in EAI-related name check logic.
The incorrectly typed data is read only, used in a compare operation, so neither remote code execution, nor memory content disclosure were possible. However, applications performing certificate name checks were vulnerable to denial of service. The GENERAL_TYPE data type is a union, and we must take care to access the correct member, based on `gen->type`, not all the member fields have the same structure, and a segfault is possible if the wrong member field is read. The code in question was lightly refactored with the intent to make it more obviously correct. CVE-2024-6119 (cherry picked from commit 1486960d6cdb052e4fc0109a56a0597b4e902ba1)
This commit is contained in:
parent
1070e7dca8
commit
e60dbfd00b
@ -916,36 +916,64 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen,
|
||||
ASN1_STRING *cstr;
|
||||
|
||||
gen = sk_GENERAL_NAME_value(gens, i);
|
||||
if ((gen->type == GEN_OTHERNAME) && (check_type == GEN_EMAIL)) {
|
||||
if (OBJ_obj2nid(gen->d.otherName->type_id) ==
|
||||
NID_id_on_SmtpUTF8Mailbox) {
|
||||
san_present = 1;
|
||||
|
||||
/*
|
||||
* If it is not a UTF8String then that is unexpected and we
|
||||
* treat it as no match
|
||||
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 (gen->d.otherName->value->type == V_ASN1_UTF8STRING) {
|
||||
cstr = gen->d.otherName->value->value.utf8string;
|
||||
|
||||
/* Positive on success, negative on error! */
|
||||
if ((rv = do_check_string(cstr, 0, equal, flags,
|
||||
chk, chklen, peername)) != 0)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
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;
|
||||
} else {
|
||||
if ((gen->type != check_type) && (gen->type != GEN_OTHERNAME))
|
||||
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;
|
||||
if (check_type == GEN_EMAIL)
|
||||
cstr = gen->d.rfc822Name;
|
||||
else if (check_type == GEN_DNS)
|
||||
cstr = gen->d.dNSName;
|
||||
else
|
||||
cstr = gen->d.iPAddress;
|
||||
/* Positive on success, negative on error! */
|
||||
if ((rv = do_check_string(cstr, alt_type, equal, flags,
|
||||
chk, chklen, peername)) != 0)
|
||||
|
@ -21,16 +21,18 @@ setup("test_eai_data");
|
||||
#./util/wrap.pl apps/openssl verify -nameopt utf8 -no_check_time -CAfile test/recipes/25-test_eai_data/utf8_chain.pem test/recipes/25-test_eai_data/ascii_leaf.pem
|
||||
#./util/wrap.pl apps/openssl verify -nameopt utf8 -no_check_time -CAfile test/recipes/25-test_eai_data/ascii_chain.pem test/recipes/25-test_eai_data/utf8_leaf.pem
|
||||
|
||||
plan tests => 12;
|
||||
plan tests => 16;
|
||||
|
||||
require_ok(srctop_file('test','recipes','tconversion.pl'));
|
||||
my $folder = "test/recipes/25-test_eai_data";
|
||||
|
||||
my $ascii_pem = srctop_file($folder, "ascii_leaf.pem");
|
||||
my $utf8_pem = srctop_file($folder, "utf8_leaf.pem");
|
||||
my $kdc_pem = srctop_file($folder, "kdc-cert.pem");
|
||||
|
||||
my $ascii_chain_pem = srctop_file($folder, "ascii_chain.pem");
|
||||
my $utf8_chain_pem = srctop_file($folder, "utf8_chain.pem");
|
||||
my $kdc_chain_pem = srctop_file($folder, "kdc-root-cert.pem");
|
||||
|
||||
my $out;
|
||||
my $outcnt = 0;
|
||||
@ -56,10 +58,18 @@ SKIP: {
|
||||
|
||||
ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $ascii_chain_pem, $ascii_pem])));
|
||||
ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $utf8_chain_pem, $utf8_pem])));
|
||||
ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $kdc_chain_pem, $kdc_pem])));
|
||||
|
||||
ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $ascii_chain_pem, $utf8_pem])));
|
||||
ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-CAfile", $utf8_chain_pem, $ascii_pem])));
|
||||
|
||||
# Check an otherName does not get misparsed as an DNS name, (should trigger ASAN errors if violated).
|
||||
ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_hostname", 'mx1.example.com', "-CAfile", $kdc_chain_pem, $kdc_pem])));
|
||||
# Check an otherName does not get misparsed as an email address, (should trigger ASAN errors if violated).
|
||||
ok(run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_email", 'joe@example.com', "-CAfile", $kdc_chain_pem, $kdc_pem])));
|
||||
# We expect SmtpUTF8Mailbox to be a UTF8 String, not an IA5String.
|
||||
ok(!run(app(["openssl", "verify", "-nameopt", "utf8", "-no_check_time", "-verify_email", 'moe@example.com', "-CAfile", $kdc_chain_pem, $kdc_pem])));
|
||||
|
||||
#Check that we get the expected failure return code
|
||||
with({ exit_checker => sub { return shift == 2; } },
|
||||
sub {
|
||||
|
21
test/recipes/25-test_eai_data/kdc-cert.pem
Normal file
21
test/recipes/25-test_eai_data/kdc-cert.pem
Normal file
@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDbDCCAlSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
|
||||
MCAXDTI0MDYyMDA2MTQxNVoYDzIxMjQwNjIwMDYxNDE1WjAXMRUwEwYDVQQDDAxU
|
||||
RVNULkVYQU1QTEUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6wfP+
|
||||
6go79dkpo/dGLMlPZ7Gw/Q6gUYrCWZWUEgEeRVHCrqOlgUEyA+PcWas/XDPUxXry
|
||||
BQlJHLvlqamAQn8gs4QPBARFYWKNiTVGyaRkgNA1N5gqyZdrP9UE+ZJmdqxRAAe8
|
||||
vvpGZWSgevPhLUiSCFYDiD0Rtji2Hm3rGUrReQFBQDEw2pNGwz9zIaxUs08kQZcx
|
||||
Yzyiplz5Oau+R/6sAgUwDlrD9xOlUxx/tA/MSDIfkK8qioU11uUZtO5VjkNQy/bT
|
||||
7zQMmXxWgm2MIgOs1u4YN7YGOtgqHE9v9iPHHfgrkbQDtVDGQsa8AQEhkUDSCtW9
|
||||
3VFAKx6dGNXYzFwfAgMBAAGjgcgwgcUwHQYDVR0OBBYEFFR5tZycW19DmtbL4Zqj
|
||||
te1c2vZLMAkGA1UdIwQCMAAwCQYDVR0TBAIwADCBjQYDVR0RBIGFMIGCoD8GBisG
|
||||
AQUCAqA1MDOgDhsMVEVTVC5FWEFNUExFoSEwH6ADAgEBoRgwFhsGa3JidGd0GwxU
|
||||
RVNULkVYQU1QTEWgHQYIKwYBBQUHCAmgERYPbW9lQGV4YW1wbGUuY29tgQ9qb2VA
|
||||
ZXhhbXBsZS5jb22CD214MS5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA
|
||||
T0xzVtVpRtaOzIhgzw7XQUdzWD5UEGSJJ1cBCOmKUWwDLTAouCYLFB4TbEE7MMUb
|
||||
iuMy60bjmVtvfJIXorGUgSadRe5RWJ5DamJWvPA0Q9x7blnEcXqEF+9Td+ypevgU
|
||||
UYHFmg83OYwxOsFXZ5cRuXMk3WCsDHQIBi6D1L6oDDZ2pfArs5mqm3thQKVlqyl1
|
||||
El3XRYEdqAz/5eCOFNfwxF0ALxjxVr/Z50StUZU8I7Zfev6+kHhyrR7dqzYJImv9
|
||||
0fTCOBEMjIETDsrA70OxAMu4V16nrWZdJdvzblS2qrt97Omkj+2kiPAJFB76RpwI
|
||||
oDQ9fKfUOAmUFth2/R/eGA==
|
||||
-----END CERTIFICATE-----
|
16
test/recipes/25-test_eai_data/kdc-root-cert.pem
Normal file
16
test/recipes/25-test_eai_data/kdc-root-cert.pem
Normal file
@ -0,0 +1,16 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICnDCCAYQCCQCBswYcrlZSHjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARS
|
||||
b290MCAXDTI0MDYyMDA2MTQxNVoYDzIxMjQwNjIwMDYxNDE1WjAPMQ0wCwYDVQQD
|
||||
DARSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqRj8S4kBbIUj
|
||||
61kZfi6nE35Q38U140+qt4uAiwAhKumfVHlBM0zQ98WFt5zMHIBQwIb3yjc2zj+0
|
||||
qzUnQfwm1r/RfcMmBPEti9Ge+aEMSsds2gMXziOFM8wd2aAFPy7UVE0XpEWofsRK
|
||||
MGi61MKVdPSbGIxBwY9VW38/7D/wf1HtJe7y0xpuecR7GB2XAs+qST59NjuF+7wS
|
||||
dLM8Hb3TATgeYbXXWsRJgwz+SPzExg5WmLnU+7y4brZ32dHtdSmkRVSgSlaIf7Xj
|
||||
3Tc6Zi7I+W/JYk7hy1zUexVdWCak4PHcoWrXe0gNNN/t8VfLfMExt5z/HIylXnU7
|
||||
pGUyqZlTGQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAHpLF1UCRy7b6Hk0rLokxI
|
||||
lgwiH9BU9mktigAGASvkbllpt+YbUbWnuYAvpHBGiP1qZtfX2r96UrSJaGO9BEzT
|
||||
Gp9ThnSjoj4Srul0+s/NArU22irFLmDzbalgevAmm9gMGkdqkiIm/mXbwrPj0ncl
|
||||
KGicevXryVpvaP62eZ8cc3C4p97frMmXxRX8sTdQpD/gRI7prdEILRSKveqT+AEW
|
||||
7rFGM5AOevb4U8ddop8A3D/kX0wcCAIBF6jCNk3uEJ57jVcagL04kPnVfdRiedTS
|
||||
vfq1DRNcD29d1H/9u0fHdSn1/+8Ep3X+afQ3C6//5NvOEaXcIGO4QSwkprQydfv8
|
||||
-----END CERTIFICATE-----
|
41
test/recipes/25-test_eai_data/kdc.sh
Executable file
41
test/recipes/25-test_eai_data/kdc.sh
Executable file
@ -0,0 +1,41 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
# Create a root CA, signing a leaf cert with a KDC principal otherName SAN, and
|
||||
# also a non-UTF8 smtpUtf8Mailbox SAN followed by an rfc822Name SAN and a DNS
|
||||
# name SAN. In the vulnerable EAI code, the KDC principal `otherName` should
|
||||
# trigger ASAN errors in DNS name checks, while the non-UTF8 `smtpUtf8Mailbox`
|
||||
# should likewise lead to ASAN issues with email name checks.
|
||||
|
||||
rm -f root-key.pem root-cert.pem
|
||||
openssl req -nodes -new -newkey rsa:2048 -keyout kdc-root-key.pem \
|
||||
-x509 -subj /CN=Root -days 36524 -out kdc-root-cert.pem
|
||||
|
||||
exts=$(
|
||||
printf "%s\n%s\n%s\n%s = " \
|
||||
"subjectKeyIdentifier = hash" \
|
||||
"authorityKeyIdentifier = keyid" \
|
||||
"basicConstraints = CA:false" \
|
||||
"subjectAltName"
|
||||
printf "%s, " "otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name"
|
||||
printf "%s, " "otherName:1.3.6.1.5.5.7.8.9;IA5:moe@example.com"
|
||||
printf "%s, " "email:joe@example.com"
|
||||
printf "%s\n" "DNS:mx1.example.com"
|
||||
printf "[kdc_princ_name]\n"
|
||||
printf "realm = EXP:0, GeneralString:TEST.EXAMPLE\n"
|
||||
printf "principal_name = EXP:1, SEQUENCE:kdc_principal_seq\n"
|
||||
printf "[kdc_principal_seq]\n"
|
||||
printf "name_type = EXP:0, INTEGER:1\n"
|
||||
printf "name_string = EXP:1, SEQUENCE:kdc_principal_components\n"
|
||||
printf "[kdc_principal_components]\n"
|
||||
printf "princ1 = GeneralString:krbtgt\n"
|
||||
printf "princ2 = GeneralString:TEST.EXAMPLE\n"
|
||||
)
|
||||
|
||||
printf "%s\n" "$exts"
|
||||
|
||||
openssl req -nodes -new -newkey rsa:2048 -keyout kdc-key.pem \
|
||||
-subj "/CN=TEST.EXAMPLE" |
|
||||
openssl x509 -req -out kdc-cert.pem \
|
||||
-CA "kdc-root-cert.pem" -CAkey "kdc-root-key.pem" \
|
||||
-set_serial 2 -days 36524 \
|
||||
-extfile <(printf "%s\n" "$exts")
|
Loading…
Reference in New Issue
Block a user