@@ -220,25 +220,20 @@ public boolean verify(X509CertificateSignature signature, String... headers) thr
220220 private X509Certificate findTrustAnchor (X509Certificate topCert , X509Certificate [] trustAnchors ) {
221221 X500Principal issuer = topCert .getIssuerX500Principal ();
222222
223- // Check if the top cert is the trust anchor, this can happen if the full chain, including trust anchor, is sent or a leaf
224- // cert is trusted directly
225- if (topCert .getSubjectX500Principal ().equals (issuer )) {
226- for (X509Certificate anchor : trustAnchors ) {
227- // Match by public key to handle the case where the trust store contains the exact same issuer with different key-pair
228- if (anchor .getPublicKey ().equals (topCert .getPublicKey ())) {
229- return anchor ;
230- }
223+ for (X509Certificate anchor : trustAnchors ) {
224+ // Check if the top cert itself is the trust anchor (handles directly trusted certs and full chains)
225+ // Per X.509 spec, a certificate is uniquely identified by issuer DN + serial number
226+ if (anchor .getIssuerX500Principal ().equals (topCert .getIssuerX500Principal ())
227+ && anchor .getSerialNumber ().equals (topCert .getSerialNumber ())) {
228+ return anchor ;
231229 }
232- }
233230
234- for (X509Certificate anchor : trustAnchors ) {
235231 if (anchor .getSubjectX500Principal ().equals (issuer )) {
236232 try {
237233 // Verify this anchor actually signed the top cert
238234 topCert .verify (anchor .getPublicKey ());
239235 return anchor ;
240236 } catch (GeneralSecurityException e ) {
241- // This anchor's subject matches, but it didn't sign the cert
242237 logger .trace (
243238 "Trust anchor [{}] matches issuer name but did not sign the certificate" ,
244239 anchor .getSubjectX500Principal ()
0 commit comments