@@ -1674,5 +1674,108 @@ public void testAlgorithmConstraintsWithSHAVariant() throws Exception {
16741674 }
16751675 }
16761676 }
1677+
1678+ /**
1679+ * Test that zero-length cert paths are valid per RFC 5280. This occurs
1680+ * when CertPathBuilder determines the trust anchor itself is the target.
1681+ */
1682+ @ Test
1683+ public void testZeroLengthCertPath ()
1684+ throws CertificateException , NoSuchAlgorithmException ,
1685+ InvalidAlgorithmParameterException , CertPathValidatorException ,
1686+ NoSuchProviderException {
1687+
1688+ FileInputStream fis = null ;
1689+ X509Certificate caCert = null ;
1690+ CertificateFactory cf = CertificateFactory .getInstance ("X.509" );
1691+
1692+ /* Use CA cert from examples as trust anchor */
1693+ try {
1694+ fis = new FileInputStream (caCertDer );
1695+ caCert = (X509Certificate )cf .generateCertificate (fis );
1696+ fis .close ();
1697+ } catch (Exception e ) {
1698+ fail ("Failed to load CA cert: " + e .getMessage ());
1699+ }
1700+
1701+ /* Create trust anchor from CA cert */
1702+ TrustAnchor anchor = new TrustAnchor (caCert , null );
1703+ Set <TrustAnchor > anchors = new HashSet <>();
1704+ anchors .add (anchor );
1705+
1706+ /* Create empty cert path (zero-length) */
1707+ List <Certificate > emptyCertList = new ArrayList <>();
1708+ CertPath emptyPath = cf .generateCertPath (emptyCertList );
1709+ assertEquals (0 , emptyPath .getCertificates ().size ());
1710+
1711+ /* Create PKIXParameters with the trust anchor */
1712+ PKIXParameters params = new PKIXParameters (anchors );
1713+ params .setRevocationEnabled (false );
1714+
1715+ /* Validate zero-length path - should succeed */
1716+ CertPathValidator cpv =
1717+ CertPathValidator .getInstance ("PKIX" , provider );
1718+ PKIXCertPathValidatorResult result =
1719+ (PKIXCertPathValidatorResult )cpv .validate (emptyPath , params );
1720+
1721+ /* Verify result contains trust anchor and its public key */
1722+ assertNotNull (result );
1723+ assertNotNull (result .getTrustAnchor ());
1724+ assertEquals (anchor .getTrustedCert (),
1725+ result .getTrustAnchor ().getTrustedCert ());
1726+ assertNotNull (result .getPublicKey ());
1727+ assertEquals (caCert .getPublicKey (), result .getPublicKey ());
1728+ }
1729+
1730+ /**
1731+ * Test that zero-length cert path with TrustAnchor that has no
1732+ * certificate throws CertPathValidatorException.
1733+ */
1734+ @ Test
1735+ public void testZeroLengthCertPathAnchorNoCertificate ()
1736+ throws CertificateException , NoSuchAlgorithmException ,
1737+ InvalidAlgorithmParameterException , NoSuchProviderException {
1738+
1739+ CertificateFactory cf = CertificateFactory .getInstance ("X.509" );
1740+
1741+ /* Create empty cert path (zero-length) */
1742+ List <Certificate > emptyCertList = new ArrayList <>();
1743+ CertPath emptyPath = cf .generateCertPath (emptyCertList );
1744+
1745+ /* Load CA cert to get its name and public key */
1746+ FileInputStream fis = null ;
1747+ X509Certificate caCert = null ;
1748+ try {
1749+ fis = new FileInputStream (caCertDer );
1750+ caCert = (X509Certificate )cf .generateCertificate (fis );
1751+ fis .close ();
1752+ } catch (Exception e ) {
1753+ fail ("Failed to load CA cert: " + e .getMessage ());
1754+ }
1755+
1756+ /* Create TrustAnchor without certificate (using CA name and key).
1757+ * This is valid for normal cert paths but not for zero-length
1758+ * paths where we need to return the anchor's certificate. */
1759+ TrustAnchor anchorWithoutCert = new TrustAnchor (
1760+ caCert .getSubjectX500Principal (), caCert .getPublicKey (), null );
1761+ Set <TrustAnchor > anchors = new HashSet <>();
1762+ anchors .add (anchorWithoutCert );
1763+
1764+ PKIXParameters params = new PKIXParameters (anchors );
1765+ params .setRevocationEnabled (false );
1766+
1767+ /* Validate zero-length path with anchor that has no cert */
1768+ CertPathValidator cpv =
1769+ CertPathValidator .getInstance ("PKIX" , provider );
1770+
1771+ try {
1772+ cpv .validate (emptyPath , params );
1773+ fail ("Expected CertPathValidatorException for zero-length " +
1774+ "path with TrustAnchor that has no certificate" );
1775+ } catch (CertPathValidatorException e ) {
1776+ assertTrue ("Exception message should mention no certificate" ,
1777+ e .getMessage ().contains ("no certificate" ));
1778+ }
1779+ }
16771780}
16781781
0 commit comments