diff --git a/examples/certs/test/eku-any-mixed-cert.pem b/examples/certs/test/eku-any-mixed-cert.pem new file mode 100644 index 0000000..ec9d893 --- /dev/null +++ b/examples/certs/test/eku-any-mixed-cert.pem @@ -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----- diff --git a/examples/certs/update-certs.sh b/examples/certs/update-certs.sh index 9368f48..8dc1641 100755 --- a/examples/certs/update-certs.sh +++ b/examples/certs/update-certs.sh @@ -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" </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 diff --git a/native/com_wolfssl_WolfSSLCertificate.c b/native/com_wolfssl_WolfSSLCertificate.c index 95f5cf9..0f7137a 100644 --- a/native/com_wolfssl_WolfSSLCertificate.c +++ b/native/com_wolfssl_WolfSSLCertificate.c @@ -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); diff --git a/src/java/com/wolfssl/WolfSSLCertificate.java b/src/java/com/wolfssl/WolfSSLCertificate.java index 1a9d13d..10c3b84 100644 --- a/src/java/com/wolfssl/WolfSSLCertificate.java +++ b/src/java/com/wolfssl/WolfSSLCertificate.java @@ -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 diff --git a/src/test/com/wolfssl/test/WolfSSLCertificateTest.java b/src/test/com/wolfssl/test/WolfSSLCertificateTest.java index d10ba28..34e24b7 100644 --- a/src/test/com/wolfssl/test/WolfSSLCertificateTest.java +++ b/src/test/com/wolfssl/test/WolfSSLCertificateTest.java @@ -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;