|
45 | 45 | import java.security.cert.Certificate; |
46 | 46 | import java.security.cert.CertificateFactory; |
47 | 47 | import java.security.cert.CertificateException; |
| 48 | +import java.security.cert.CertificateParsingException; |
48 | 49 | import java.security.cert.X509Certificate; |
49 | 50 | import java.net.Socket; |
50 | 51 | import java.net.InetSocketAddress; |
@@ -1145,6 +1146,7 @@ public void testCheckServerTrustedWithChainWrongOrder() |
1145 | 1146 | pass("\t... passed"); |
1146 | 1147 | } |
1147 | 1148 |
|
| 1149 | + |
1148 | 1150 | @Test |
1149 | 1151 | public void testCheckServerTrustedWithChainReturnsChain() |
1150 | 1152 | throws NoSuchProviderException, NoSuchAlgorithmException, |
@@ -2487,6 +2489,117 @@ public void testX509ExtendedTrustManagerExternal() |
2487 | 2489 | pass("\t... passed"); |
2488 | 2490 | } |
2489 | 2491 |
|
| 2492 | + @Test |
| 2493 | + public void testExtendedKeyUsageWithLeafNotFirst() throws Exception { |
| 2494 | + |
| 2495 | + System.out.print("\tTesting EKU validation with leaf not first"); |
| 2496 | + |
| 2497 | + /* This test reproduces the case where a certificate chain arrives |
| 2498 | + * with CA before leaf cert and helps verify the peer chain sorting |
| 2499 | + * logic. It exercises a common code path to validate the Extended |
| 2500 | + * Key Usage as a sanity check. */ |
| 2501 | + |
| 2502 | + String eccServerCert = |
| 2503 | + "examples/certs/intermediate/server-int-ecc-cert.pem"; |
| 2504 | + String eccInt2CaCert = |
| 2505 | + "examples/certs/intermediate/ca-int2-ecc-cert.pem"; |
| 2506 | + String eccIntCaCert = |
| 2507 | + "examples/certs/intermediate/ca-int-ecc-cert.pem"; |
| 2508 | + |
| 2509 | + FileInputStream fis; |
| 2510 | + BufferedInputStream bis; |
| 2511 | + X509Certificate[] certArray = new X509Certificate[3]; |
| 2512 | + |
| 2513 | + if (WolfSSLTestFactory.isAndroid()) { |
| 2514 | + eccServerCert = "/sdcard/" + eccServerCert; |
| 2515 | + eccInt2CaCert = "/sdcard/" + eccInt2CaCert; |
| 2516 | + eccIntCaCert = "/sdcard/" + eccIntCaCert; |
| 2517 | + } |
| 2518 | + |
| 2519 | + /* Load certificates in REVERSE order (CA first, server last) |
| 2520 | + * to simulate the bug scenario */ |
| 2521 | + CertificateFactory cf = CertificateFactory.getInstance("X.509"); |
| 2522 | + |
| 2523 | + /* certArray[0]: Intermediate2 CA - has CA:TRUE, no serverAuth EKU */ |
| 2524 | + fis = new FileInputStream(eccInt2CaCert); |
| 2525 | + bis = new java.io.BufferedInputStream(fis); |
| 2526 | + certArray[0] = (X509Certificate)cf.generateCertificate(bis); |
| 2527 | + bis.close(); |
| 2528 | + fis.close(); |
| 2529 | + |
| 2530 | + /* certArray[1]: Intermediate CA - has CA:TRUE, no serverAuth EKU */ |
| 2531 | + fis = new FileInputStream(eccIntCaCert); |
| 2532 | + bis = new java.io.BufferedInputStream(fis); |
| 2533 | + certArray[1] = (X509Certificate)cf.generateCertificate(bis); |
| 2534 | + bis.close(); |
| 2535 | + fis.close(); |
| 2536 | + |
| 2537 | + /* certArray[2]: Server cert - has CA:FALSE, HAS serverAuth EKU */ |
| 2538 | + fis = new FileInputStream(eccServerCert); |
| 2539 | + bis = new java.io.BufferedInputStream(fis); |
| 2540 | + certArray[2] = (X509Certificate)cf.generateCertificate(bis); |
| 2541 | + bis.close(); |
| 2542 | + fis.close(); |
| 2543 | + |
| 2544 | + /* Create wolfSSL TrustManager for verification. */ |
| 2545 | + TrustManager[] baseTm = tf.createTrustManager("SunX509", |
| 2546 | + tf.caJKS, provider); |
| 2547 | + WolfSSLTrustX509 wolfTm = (WolfSSLTrustX509) baseTm[0]; |
| 2548 | + |
| 2549 | + /* Call checkServerTrusted() with chain-returning overload. |
| 2550 | + * The sorting logic code should: |
| 2551 | + * 1. Identify the leaf using BasicConstraints (index 2) |
| 2552 | + * 2. Move server cert to index 0 |
| 2553 | + * 3. Return chain with server cert first */ |
| 2554 | + List<X509Certificate> sortedChain = null; |
| 2555 | + try { |
| 2556 | + sortedChain = wolfTm.checkServerTrusted( |
| 2557 | + certArray, "EC", (String)null); |
| 2558 | + |
| 2559 | + } catch (CertificateException e) { |
| 2560 | + e.printStackTrace(); |
| 2561 | + fail("checkServerTrusted() threw exception: " + e.getMessage()); |
| 2562 | + } |
| 2563 | + |
| 2564 | + /* Validate Extended Key Usage on the peer cert. |
| 2565 | + * The peer cert should be first in the sorted chain. */ |
| 2566 | + if (sortedChain == null || sortedChain.size() == 0) { |
| 2567 | + fail("Sorted chain is null or empty"); |
| 2568 | + } |
| 2569 | + |
| 2570 | + X509Certificate peerCert = sortedChain.get(0); |
| 2571 | + List<String> ekuOids = null; |
| 2572 | + |
| 2573 | + try { |
| 2574 | + ekuOids = peerCert.getExtendedKeyUsage(); |
| 2575 | + |
| 2576 | + } catch (java.security.cert.CertificateParsingException e) { |
| 2577 | + e.printStackTrace(); |
| 2578 | + fail("Failed to parse Extended Key Usage: " + e.getMessage()); |
| 2579 | + } |
| 2580 | + |
| 2581 | + /* Check for serverAuth EKU (1.3.6.1.5.5.7.3.1) */ |
| 2582 | + boolean hasServerAuth = false; |
| 2583 | + if (ekuOids != null) { |
| 2584 | + for (String oid : ekuOids) { |
| 2585 | + if (oid.equals("1.3.6.1.5.5.7.3.1")) { |
| 2586 | + hasServerAuth = true; |
| 2587 | + break; |
| 2588 | + } |
| 2589 | + } |
| 2590 | + } |
| 2591 | + |
| 2592 | + if (!hasServerAuth) { |
| 2593 | + fail("EKU validation failed. The certificate chain was not " + |
| 2594 | + "properly sorted, and a CA cert (without serverAuth EKU) " + |
| 2595 | + "was treated as the peer cert instead of the server cert." + |
| 2596 | + "Peer cert: " + peerCert.getSubjectX500Principal() + |
| 2597 | + ", EKU list: " + ekuOids); |
| 2598 | + } |
| 2599 | + |
| 2600 | + System.out.println("\t... passed"); |
| 2601 | + } |
| 2602 | + |
2490 | 2603 | /* TrustManager that trusts all certificates */ |
2491 | 2604 | TrustManager[] trustAllCerts = { |
2492 | 2605 | new X509ExtendedTrustManager() { |
|
0 commit comments