F-9112: include anyExtendedKeyUsage OID in X509 extended key usage results

pull/396/head
Chris Conlon 2026-08-11 15:24:49 -06:00
parent d853121a7c
commit 0007aef707
5 changed files with 154 additions and 1 deletions

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDYTCCAkmgAwIBAgIUNHvAOrmS13x7g9fHFkcCGYOshsgwDQYJKoZIhvcNAQEL
BQAwQTEbMBkGA1UEAwwSVGVzdCBFS1UgQW55IE1peGVkMRUwEwYDVQQKDAx3b2xm
U1NMIFRlc3QxCzAJBgNVBAYTAlVTMB4XDTI2MDgxMTE4NTk0OVoXDTM2MDgwODE4
NTk0OVowQTEbMBkGA1UEAwwSVGVzdCBFS1UgQW55IE1peGVkMRUwEwYDVQQKDAx3
b2xmU1NMIFRlc3QxCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAuT3XvvOYndhVp42+KMln9eO6DHvnmVPe/Hairx3KEYMuSfbtcn3q
3eju+xKlKF1N5NQN4qjS8GuJEExMt0f9CPUeZXBpKJabmHKC+LbYerLNS5FGQhVa
EgcCbNC1ajVIGXywplR+QW+4w1sDEu6fIlGcLA12KphasYA43TF4s+233d2Cj/3E
isXYRjdOudBkYvAUzuB8ow63HAWl5mJV3dlpQFJhzRKfTcBja7XeFNpOXmJxlBM/
VaisHU5fDHv8/nR39MNJUorQ236T5vZeTXwfpzJmS8QqyvGT0BRKJOhYGCL/Gk5v
MryICN/LsTrU97oHg09gx4xrCfCpBpsvsQIDAQABo1EwTzAJBgNVHRMEAjAAMCMG
A1UdJQQcMBoGBFUdJQAGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUiSQ2
7FNygC+tkNKJjao0QssDMFgwDQYJKoZIhvcNAQELBQADggEBACtyhD6edgYiVSRY
R3Gks9yvndaB2y+58U1oQzTL3/4y8+bEGir5tTUn/BlpsYmQ1g6ymHo57DFvzrnL
JHG0p3MgLuyzLaIEYpf//U8xtmvhXBUROfsISUPfWFMQnvZ6DGxBt54PSP5GSsYa
Yal9thaaXofQkAp1ueJ6Vwe2RAJ/WMYgkGSOXzypWUtKwMzhfKS+ZR2wO0l0WlhN
bY+5U6OgnH0Oh74GL4h2CogeccJm03YRiuzmOnB9YYQErEC3v3JtAL/LxHOKnLZz
+0rsIFZF78dEsooZs8X9f/TVUB7ebvyIT/tq7iyDT/+FwkfXmSHVJyQDJ0vTQc2k
IUOMxoI=
-----END CERTIFICATE-----

View File

@ -129,6 +129,37 @@ if [ $? -ne 0 ]; then
fi
rm -rf "${TMP_DIR}"
# Generate mixed Extended Key Usage test cert, EKU holds anyExtendedKeyUsage
# (2.5.29.37.0) alongside serverAuth and clientAuth
printf "Generating test/eku-any-mixed-cert.pem\n"
mkdir -p test
TMP_DIR="$(mktemp -d)"
cat > "${TMP_DIR}/openssl.cnf" <<EOF
[ req ]
distinguished_name = dn
x509_extensions = v3_req
prompt = no
[ dn ]
CN = Test EKU Any Mixed
O = wolfSSL Test
C = US
[ v3_req ]
basicConstraints = CA:FALSE
extendedKeyUsage = 2.5.29.37.0, serverAuth, clientAuth
EOF
openssl req -new -newkey rsa:2048 -nodes -x509 -days 3650 \
-keyout "${TMP_DIR}/eku-any-mixed-key.pem" -out test/eku-any-mixed-cert.pem \
-config "${TMP_DIR}/openssl.cnf" >/dev/null 2>&1
if [ $? -ne 0 ]; then
printf "Failed to generate test/eku-any-mixed-cert.pem\n"
rm -rf "${TMP_DIR}"
exit 1
fi
rm -rf "${TMP_DIR}"
# Remove text info from intermediate certs, causes issues on Android (WRONG TAG)
printf "Removing text info from intermediate certs\n"
sed -i.bak -n '/-----BEGIN CERTIFICATE-----/,$p' ca-cert.pem

View File

@ -2229,6 +2229,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1ex
if (ekuBits & XKU_SMIME) ekuCount++;
if (ekuBits & XKU_TIMESTAMP) ekuCount++;
if (ekuBits & XKU_OCSP_SIGN) ekuCount++;
if (ekuBits & XKU_ANYEKU) ekuCount++;
if (ekuCount == 0) {
return NULL;
@ -2257,7 +2258,11 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1ex
EKU_EMAILPROTECT_OID);
idx = addEkuOid(jenv, ret, idx, ekuBits, XKU_TIMESTAMP,
EKU_TIMESTAMP_OID);
(void)addEkuOid(jenv, ret, idx, ekuBits, XKU_OCSP_SIGN, EKU_OCSP_SIGN_OID);
idx = addEkuOid(jenv, ret, idx, ekuBits, XKU_OCSP_SIGN,
EKU_OCSP_SIGN_OID);
/* NID_anyExtendedKeyUsage used here since no EKU_*_OID sum for anyEKU */
(void)addEkuOid(jenv, ret, idx, ekuBits, XKU_ANYEKU,
NID_anyExtendedKeyUsage);
(*jenv)->DeleteLocalRef(jenv, stringClass);

View File

@ -1140,6 +1140,7 @@ public class WolfSSLCertificate implements Serializable {
* emailProtection
* timeStamping
* OCSPSigning
* any
*
* @param isCritical Boolean flag indicating if this extension is
* critical
@ -1961,6 +1962,7 @@ public class WolfSSLCertificate implements Serializable {
* - 1.3.6.1.5.5.7.3.2 (TLS Web Client Authentication / clientAuth)
* - 1.3.6.1.5.5.7.3.3 (Code Signing / codeSigning)
* - 1.3.6.1.5.5.7.3.4 (Email Protection / emailProtection)
* - 2.5.29.37.0 (Any Extended Key Usage / anyExtendedKeyUsage)
*
* @return Array of OID strings, or null if Extended Key Usage extension
* is not present in certificate

View File

@ -83,6 +83,8 @@ public class WolfSSLCertificateTest {
public static String external = "examples/certs/ca-google-root.der";
public static String sanTestDir = "examples/certs/san-test";
public static String crlDpCertPem = "examples/certs/test/crl-dp-cert.pem";
public static String ekuAnyMixedCertPem =
"examples/certs/test/eku-any-mixed-cert.pem";
public static String sanTestUpnCert = null;
public static String sanTestAllTypesCert = null;
public static String sanTestAllTypesDer = null;
@ -149,6 +151,7 @@ public class WolfSSLCertificateTest {
external = WolfSSLTestCommon.getPath(external);
sanTestDir = WolfSSLTestCommon.getPath(sanTestDir);
crlDpCertPem = WolfSSLTestCommon.getPath(crlDpCertPem);
ekuAnyMixedCertPem = WolfSSLTestCommon.getPath(ekuAnyMixedCertPem);
sanTestUpnCert = sanTestDir + "/san-test-othername-upn.pem";
sanTestAllTypesCert = sanTestDir + "/san-test-all-types.pem";
sanTestAllTypesDer = sanTestDir + "/san-test-all-types.der";
@ -634,6 +637,97 @@ public class WolfSSLCertificateTest {
}
}
/* Generate a self-signed cert with the given EKU value string,
* return its DER encoding. */
private byte[] genEkuTestCertDer(String ekuValues)
throws WolfSSLException, WolfSSLJNIException, IOException {
WolfSSLCertificate x509 = new WolfSSLCertificate();
WolfSSLX509Name name = null;
try {
Instant now = Instant.now();
x509.setNotBefore(Date.from(now));
x509.setNotAfter(Date.from(now.plus(Duration.ofDays(365))));
x509.setSerialNumber(BigInteger.valueOf(1124));
name = new WolfSSLX509Name();
name.setCommonName("eku test");
x509.setSubjectName(name);
x509.setPublicKey(cliKeyPubDer, WolfSSL.RSAk,
WolfSSL.SSL_FILETYPE_ASN1);
x509.addExtension(WolfSSL.NID_ext_key_usage, ekuValues, false);
x509.signCert(cliKeyDer, WolfSSL.RSAk,
WolfSSL.SSL_FILETYPE_ASN1, "SHA256");
return x509.getDer();
} finally {
if (name != null) {
name.free();
}
x509.free();
}
}
@Test
public void test_getExtendedKeyUsageAnyOnly()
throws WolfSSLException, WolfSSLJNIException, IOException {
Assume.assumeTrue(WolfSSL.FileSystemEnabled());
Assume.assumeTrue(WolfSSL.getLibVersionHex() > 0x05006003);
WolfSSLCertificate cert =
new WolfSSLCertificate(genEkuTestCertDer("any"));
try {
String[] eku = cert.getExtendedKeyUsage();
assertNotNull("EKU arr should not be null for any only cert", eku);
assertEquals(1, eku.length);
assertEquals("2.5.29.37.0", eku[0]);
} finally {
cert.free();
}
}
@Test
public void test_getExtendedKeyUsageMixedWithAny()
throws WolfSSLException, WolfSSLJNIException, IOException {
Assume.assumeTrue(WolfSSL.FileSystemEnabled());
String[] expected = {
"1.3.6.1.5.5.7.3.1",
"1.3.6.1.5.5.7.3.2",
"2.5.29.37.0"
};
/* Fixture cert EKU holds anyExtendedKeyUsage plus serverAuth and
* clientAuth. wolfSSL cert generation cannot produce this mix, the
* encoder collapses EKU to the any OID alone when any is set. */
WolfSSLCertificate cert = new WolfSSLCertificate(
ekuAnyMixedCertPem, WolfSSL.SSL_FILETYPE_PEM);
try {
String[] eku = cert.getExtendedKeyUsage();
assertNotNull("EKU array should not be null for mixed cert", eku);
assertEquals(expected.length, eku.length);
for (String exp : expected) {
boolean found = false;
for (String oid : eku) {
if (oid.equals(exp)) {
found = true;
break;
}
}
assertTrue("Missing expected OID: " + exp, found);
}
} finally {
cert.free();
}
}
@Test
public void test_getAiaMulti() {
String[] ocsp;