Skip to content

Commit 7232e3c

Browse files
seanjmullanslowhog
authored andcommittedApr 20, 2021
8249906: Enhance opening JARs
Reviewed-by: weijun, rhalade, mschoene
1 parent 17a741d commit 7232e3c

24 files changed

+766
-502
lines changed
 

‎src/java.base/share/classes/java/security/cert/CertPathHelperImpl.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -63,4 +63,8 @@ protected void implSetPathToNames(X509CertSelector sel,
6363
protected void implSetDateAndTime(X509CRLSelector sel, Date date, long skew) {
6464
sel.setDateAndTime(date, skew);
6565
}
66+
67+
protected boolean implIsJdkCA(TrustAnchor anchor) {
68+
return anchor.isJdkCA();
69+
}
6670
}

‎src/java.base/share/classes/java/security/cert/TrustAnchor.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
3030

3131
import javax.security.auth.x500.X500Principal;
3232

33+
import sun.security.util.AnchorCertificates;
3334
import sun.security.x509.NameConstraintsExtension;
3435
import sun.security.x509.X500Name;
3536

@@ -68,6 +69,12 @@ public class TrustAnchor {
6869
private final X509Certificate trustedCert;
6970
private byte[] ncBytes;
7071
private NameConstraintsExtension nc;
72+
private boolean jdkCA;
73+
private boolean hasJdkCABeenChecked;
74+
75+
static {
76+
CertPathHelperImpl.initialize();
77+
}
7178

7279
/**
7380
* Creates an instance of {@code TrustAnchor} with the specified
@@ -330,4 +337,18 @@ public String toString() {
330337
sb.append(" Name Constraints: " + nc.toString() + "\n");
331338
return sb.toString();
332339
}
340+
341+
/**
342+
* Returns true if anchor is a JDK CA (a root CA that is included by
343+
* default in the cacerts keystore).
344+
*/
345+
synchronized boolean isJdkCA() {
346+
if (!hasJdkCABeenChecked) {
347+
if (trustedCert != null) {
348+
jdkCA = AnchorCertificates.contains(trustedCert);
349+
}
350+
hasJdkCABeenChecked = true;
351+
}
352+
return jdkCA;
353+
}
333354
}

‎src/java.base/share/classes/java/util/jar/JarFile.java

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import jdk.internal.access.JavaUtilZipFileAccess;
3030
import sun.security.action.GetPropertyAction;
3131
import sun.security.util.ManifestEntryVerifier;
32-
import sun.security.util.SignatureFileVerifier;
3332

3433
import java.io.ByteArrayInputStream;
3534
import java.io.EOFException;

‎src/java.base/share/classes/sun/security/pkcs/SignerInfo.java

+73-65
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@
3636
import java.security.*;
3737
import java.security.spec.PSSParameterSpec;
3838
import java.util.ArrayList;
39-
import java.util.Arrays;
4039
import java.util.Collections;
41-
import java.util.EnumSet;
40+
import java.util.Date;
41+
import java.util.HashMap;
42+
import java.util.HashSet;
43+
import java.util.Map;
4244
import java.util.Set;
4345

4446
import sun.security.provider.SHAKE256;
@@ -55,16 +57,8 @@
5557
*/
5658
public class SignerInfo implements DerEncoder {
5759

58-
// Digest and Signature restrictions
59-
private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET =
60-
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
61-
62-
private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET =
63-
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
64-
6560
private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
66-
new DisabledAlgorithmConstraints(
67-
DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
61+
DisabledAlgorithmConstraints.jarConstraints();
6862

6963
BigInteger version;
7064
X500Name issuerName;
@@ -79,6 +73,14 @@ public class SignerInfo implements DerEncoder {
7973
PKCS9Attributes authenticatedAttributes;
8074
PKCS9Attributes unauthenticatedAttributes;
8175

76+
/**
77+
* A map containing the algorithms in this SignerInfo. This is used to
78+
* avoid checking algorithms to see if they are disabled more than once.
79+
* The key is the AlgorithmId of the algorithm, and the value is the name of
80+
* the field or attribute.
81+
*/
82+
private Map<AlgorithmId, String> algorithms = new HashMap<>();
83+
8284
public SignerInfo(X500Name issuerName,
8385
BigInteger serial,
8486
AlgorithmId digestAlgorithmId,
@@ -329,20 +331,15 @@ SignerInfo verify(PKCS7 block, byte[] data)
329331
throws NoSuchAlgorithmException, SignatureException {
330332

331333
try {
334+
Timestamp timestamp = getTimestamp();
332335

333336
ContentInfo content = block.getContentInfo();
334337
if (data == null) {
335338
data = content.getContentBytes();
336339
}
337340

338-
Timestamp timestamp = null;
339-
try {
340-
timestamp = getTimestamp();
341-
} catch (Exception ignore) {
342-
}
343-
344-
ConstraintsParameters cparams =
345-
new ConstraintsParameters(timestamp);
341+
String digestAlgName = digestAlgorithmId.getName();
342+
algorithms.put(digestAlgorithmId, "SignerInfo digestAlgorithm field");
346343

347344
byte[] dataSigned;
348345

@@ -368,19 +365,10 @@ SignerInfo verify(PKCS7 block, byte[] data)
368365
if (messageDigest == null) // fail if there is no message digest
369366
return null;
370367

371-
String digestAlgname = digestAlgorithmId.getName();
372-
373-
// check that digest algorithm is not restricted
374-
try {
375-
JAR_DISABLED_CHECK.permits(digestAlgname, cparams);
376-
} catch (CertPathValidatorException e) {
377-
throw new SignatureException(e.getMessage(), e);
378-
}
379-
380368
byte[] computedMessageDigest;
381-
if (digestAlgname.equals("SHAKE256")
382-
|| digestAlgname.equals("SHAKE256-LEN")) {
383-
if (digestAlgname.equals("SHAKE256-LEN")) {
369+
if (digestAlgName.equals("SHAKE256")
370+
|| digestAlgName.equals("SHAKE256-LEN")) {
371+
if (digestAlgName.equals("SHAKE256-LEN")) {
384372
int v = new DerValue(digestAlgorithmId
385373
.getEncodedParams()).getInteger();
386374
if (v != 512) {
@@ -392,15 +380,12 @@ SignerInfo verify(PKCS7 block, byte[] data)
392380
md.update(data, 0, data.length);
393381
computedMessageDigest = md.digest();
394382
} else {
395-
MessageDigest md = MessageDigest.getInstance(digestAlgname);
383+
MessageDigest md = MessageDigest.getInstance(digestAlgName);
396384
computedMessageDigest = md.digest(data);
397385
}
398386

399-
if (messageDigest.length != computedMessageDigest.length)
387+
if (!MessageDigest.isEqual(messageDigest, computedMessageDigest)) {
400388
return null;
401-
for (int i = 0; i < messageDigest.length; i++) {
402-
if (messageDigest[i] != computedMessageDigest[i])
403-
return null;
404389
}
405390

406391
// message digest attribute matched
@@ -414,16 +399,18 @@ SignerInfo verify(PKCS7 block, byte[] data)
414399

415400
// put together digest algorithm and encryption algorithm
416401
// to form signing algorithm. See makeSigAlg for details.
417-
String algname = makeSigAlg(
402+
String sigAlgName = makeSigAlg(
418403
digestAlgorithmId,
419404
digestEncryptionAlgorithmId,
420405
authenticatedAttributes == null);
421406

422-
// check that jar signature algorithm is not restricted
423-
try {
424-
JAR_DISABLED_CHECK.permits(algname, cparams);
425-
} catch (CertPathValidatorException e) {
426-
throw new SignatureException(e.getMessage(), e);
407+
KnownOIDs oid = KnownOIDs.findMatch(sigAlgName);
408+
if (oid != null) {
409+
AlgorithmId sigAlgId =
410+
new AlgorithmId(ObjectIdentifier.of(oid),
411+
digestEncryptionAlgorithmId.getParameters());
412+
algorithms.put(sigAlgId,
413+
"SignerInfo digestEncryptionAlgorithm field");
427414
}
428415

429416
X509Certificate cert = getCertificate(block);
@@ -432,14 +419,6 @@ SignerInfo verify(PKCS7 block, byte[] data)
432419
}
433420
PublicKey key = cert.getPublicKey();
434421

435-
// check if the public key is restricted
436-
if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
437-
throw new SignatureException("Public key check failed. " +
438-
"Disabled key used: " +
439-
KeyUtil.getKeySize(key) + " bit " +
440-
key.getAlgorithm());
441-
}
442-
443422
if (cert.hasUnsupportedCriticalExtension()) {
444423
throw new SignatureException("Certificate has unsupported "
445424
+ "critical extension(s)");
@@ -476,13 +455,13 @@ SignerInfo verify(PKCS7 block, byte[] data)
476455
}
477456
}
478457

479-
Signature sig = Signature.getInstance(algname);
458+
Signature sig = Signature.getInstance(sigAlgName);
480459

481460
AlgorithmParameters ap =
482461
digestEncryptionAlgorithmId.getParameters();
483462
try {
484463
SignatureUtil.initVerifyWithParam(sig, key,
485-
SignatureUtil.getParamSpec(algname, ap));
464+
SignatureUtil.getParamSpec(sigAlgName, ap));
486465
} catch (ProviderException | InvalidAlgorithmParameterException |
487466
InvalidKeyException e) {
488467
throw new SignatureException(e.getMessage(), e);
@@ -492,9 +471,8 @@ SignerInfo verify(PKCS7 block, byte[] data)
492471
if (sig.verify(encryptedDigest)) {
493472
return this;
494473
}
495-
} catch (IOException e) {
496-
throw new SignatureException("IO error verifying signature:\n" +
497-
e.getMessage());
474+
} catch (IOException | CertificateException e) {
475+
throw new SignatureException("Error verifying signature", e);
498476
}
499477
return null;
500478
}
@@ -654,6 +632,9 @@ public Timestamp getTimestamp()
654632
// Extract the signer (the Timestamping Authority)
655633
// while verifying the content
656634
SignerInfo[] tsa = tsToken.verify(encTsTokenInfo);
635+
if (tsa == null || tsa.length == 0) {
636+
throw new SignatureException("Unable to verify timestamp");
637+
}
657638
// Expect only one signer
658639
ArrayList<X509Certificate> chain = tsa[0].getCertificateChain(tsToken);
659640
CertificateFactory cf = CertificateFactory.getInstance("X.509");
@@ -662,6 +643,7 @@ public Timestamp getTimestamp()
662643
TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
663644
// Check that the signature timestamp applies to this signature
664645
verifyTimestamp(tsTokenInfo);
646+
algorithms.putAll(tsa[0].algorithms);
665647
// Create a timestamp object
666648
timestamp = new Timestamp(tsTokenInfo.getDate(), tsaChain);
667649
return timestamp;
@@ -674,18 +656,13 @@ public Timestamp getTimestamp()
674656
*/
675657
private void verifyTimestamp(TimestampToken token)
676658
throws NoSuchAlgorithmException, SignatureException {
677-
String digestAlgname = token.getHashAlgorithm().getName();
678-
// check that algorithm is not restricted
679-
if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, digestAlgname,
680-
null)) {
681-
throw new SignatureException("Timestamp token digest check failed. " +
682-
"Disabled algorithm used: " + digestAlgname);
683-
}
684659

685-
MessageDigest md =
686-
MessageDigest.getInstance(digestAlgname);
660+
AlgorithmId digestAlgId = token.getHashAlgorithm();
661+
algorithms.put(digestAlgId, "TimestampToken digestAlgorithm field");
662+
663+
MessageDigest md = MessageDigest.getInstance(digestAlgId.getName());
687664

688-
if (!Arrays.equals(token.getHashedMessage(),
665+
if (!MessageDigest.isEqual(token.getHashedMessage(),
689666
md.digest(encryptedDigest))) {
690667

691668
throw new SignatureException("Signature timestamp (#" +
@@ -726,4 +703,35 @@ public String toString() {
726703
}
727704
return out;
728705
}
706+
707+
/**
708+
* Verify all of the algorithms in the array of SignerInfos against the
709+
* constraints in the jdk.jar.disabledAlgorithms security property.
710+
*
711+
* @param infos array of SignerInfos
712+
* @param params constraint parameters
713+
* @param name the name of the signer's PKCS7 file
714+
* @return a set of algorithms that passed the checks and are not disabled
715+
*/
716+
public static Set<String> verifyAlgorithms(SignerInfo[] infos,
717+
JarConstraintsParameters params, String name) throws SignatureException {
718+
Map<AlgorithmId, String> algorithms = new HashMap<>();
719+
for (SignerInfo info : infos) {
720+
algorithms.putAll(info.algorithms);
721+
}
722+
723+
Set<String> enabledAlgorithms = new HashSet<>();
724+
try {
725+
for (Map.Entry<AlgorithmId, String> algorithm : algorithms.entrySet()) {
726+
params.setExtendedExceptionMsg(name, algorithm.getValue());
727+
AlgorithmId algId = algorithm.getKey();
728+
JAR_DISABLED_CHECK.permits(algId.getName(),
729+
algId.getParameters(), params);
730+
enabledAlgorithms.add(algId.getName());
731+
}
732+
} catch (CertPathValidatorException e) {
733+
throw new SignatureException(e);
734+
}
735+
return enabledAlgorithms;
736+
}
729737
}

‎src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java

+46-89
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,6 @@
2727

2828
import java.security.AlgorithmConstraints;
2929
import java.security.CryptoPrimitive;
30-
import java.security.Timestamp;
31-
import java.security.cert.CertPathValidator;
3230
import java.util.Collection;
3331
import java.util.Collections;
3432
import java.util.Date;
@@ -53,14 +51,13 @@
5351
import java.security.interfaces.DSAPublicKey;
5452
import java.security.spec.DSAPublicKeySpec;
5553

56-
import sun.security.util.AnchorCertificates;
5754
import sun.security.util.ConstraintsParameters;
5855
import sun.security.util.Debug;
5956
import sun.security.util.DisabledAlgorithmConstraints;
6057
import sun.security.validator.Validator;
58+
import sun.security.x509.AlgorithmId;
6159
import sun.security.x509.X509CertImpl;
6260
import sun.security.x509.X509CRLImpl;
63-
import sun.security.x509.AlgorithmId;
6461

6562
/**
6663
* A {@code PKIXCertPathChecker} implementation to check whether a
@@ -78,10 +75,10 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
7875

7976
private final AlgorithmConstraints constraints;
8077
private final PublicKey trustedPubKey;
81-
private final Date pkixdate;
78+
private final Date date;
8279
private PublicKey prevPubKey;
83-
private final Timestamp jarTimestamp;
8480
private final String variant;
81+
private TrustAnchor anchor;
8582

8683
private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
8784
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
@@ -94,95 +91,70 @@ public final class AlgorithmChecker extends PKIXCertPathChecker {
9491
CryptoPrimitive.KEY_AGREEMENT));
9592

9693
private static final DisabledAlgorithmConstraints
97-
certPathDefaultConstraints = new DisabledAlgorithmConstraints(
98-
DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
99-
100-
// If there is no "cacerts" keyword, then disable anchor checking
101-
private static final boolean publicCALimits =
102-
certPathDefaultConstraints.checkProperty("jdkCA");
103-
104-
// If anchor checking enabled, this will be true if the trust anchor
105-
// has a match in the cacerts file
106-
private boolean trustedMatch = false;
94+
certPathDefaultConstraints =
95+
DisabledAlgorithmConstraints.certPathConstraints();
10796

10897
/**
109-
* Create a new {@code AlgorithmChecker} with the given algorithm
110-
* given {@code TrustAnchor} and {@code String} variant.
98+
* Create a new {@code AlgorithmChecker} with the given
99+
* {@code TrustAnchor} and {@code String} variant.
111100
*
112101
* @param anchor the trust anchor selected to validate the target
113102
* certificate
114-
* @param variant is the Validator variants of the operation. A null value
103+
* @param variant the Validator variant of the operation. A null value
115104
* passed will set it to Validator.GENERIC.
116105
*/
117106
public AlgorithmChecker(TrustAnchor anchor, String variant) {
118-
this(anchor, certPathDefaultConstraints, null, null, variant);
107+
this(anchor, certPathDefaultConstraints, null, variant);
119108
}
120109

121110
/**
122111
* Create a new {@code AlgorithmChecker} with the given
123-
* {@code AlgorithmConstraints}, {@code Timestamp}, and {@code String}
124-
* variant.
112+
* {@code AlgorithmConstraints} and {@code String} variant.
125113
*
126114
* Note that this constructor can initialize a variation of situations where
127-
* the AlgorithmConstraints, Timestamp, or Variant maybe known.
115+
* the AlgorithmConstraints or Variant maybe known.
128116
*
129117
* @param constraints the algorithm constraints (or null)
130-
* @param jarTimestamp Timestamp passed for JAR timestamp constraint
131-
* checking. Set to null if not applicable.
132-
* @param variant is the Validator variants of the operation. A null value
118+
* @param variant the Validator variant of the operation. A null value
133119
* passed will set it to Validator.GENERIC.
134120
*/
135-
public AlgorithmChecker(AlgorithmConstraints constraints,
136-
Timestamp jarTimestamp, String variant) {
137-
this(null, constraints, null, jarTimestamp, variant);
121+
public AlgorithmChecker(AlgorithmConstraints constraints, String variant) {
122+
this(null, constraints, null, variant);
138123
}
139124

140125
/**
141126
* Create a new {@code AlgorithmChecker} with the
142-
* given {@code TrustAnchor}, {@code AlgorithmConstraints},
143-
* {@code Timestamp}, and {@code String} variant.
127+
* given {@code TrustAnchor}, {@code AlgorithmConstraints}, {@code Date},
128+
* and {@code String} variant.
144129
*
145130
* @param anchor the trust anchor selected to validate the target
146131
* certificate
147132
* @param constraints the algorithm constraints (or null)
148-
* @param pkixdate The date specified by the PKIXParameters date. If the
149-
* PKIXParameters is null, the current date is used. This
150-
* should be null when jar files are being checked.
151-
* @param jarTimestamp Timestamp passed for JAR timestamp constraint
152-
* checking. Set to null if not applicable.
153-
* @param variant is the Validator variants of the operation. A null value
133+
* @param date the date specified by the PKIXParameters date, or the
134+
* JAR timestamp if jar files are being validated and the
135+
* JAR is timestamped. May be null if no timestamp or
136+
* PKIXParameter date is set.
137+
* @param variant the Validator variant of the operation. A null value
154138
* passed will set it to Validator.GENERIC.
155139
*/
156140
public AlgorithmChecker(TrustAnchor anchor,
157-
AlgorithmConstraints constraints, Date pkixdate,
158-
Timestamp jarTimestamp, String variant) {
141+
AlgorithmConstraints constraints, Date date, String variant) {
159142

160143
if (anchor != null) {
161144
if (anchor.getTrustedCert() != null) {
162145
this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
163-
// Check for anchor certificate restrictions
164-
trustedMatch = checkFingerprint(anchor.getTrustedCert());
165-
if (trustedMatch && debug != null) {
166-
debug.println("trustedMatch = true");
167-
}
168146
} else {
169147
this.trustedPubKey = anchor.getCAPublicKey();
170148
}
149+
this.anchor = anchor;
171150
} else {
172151
this.trustedPubKey = null;
173-
if (debug != null) {
174-
debug.println("TrustAnchor is null, trustedMatch is false.");
175-
}
176152
}
177153

178154
this.prevPubKey = this.trustedPubKey;
179155
this.constraints = (constraints == null ? certPathDefaultConstraints :
180156
constraints);
181-
// If we are checking jar files, set pkixdate the same as the timestamp
182-
// for certificate checking
183-
this.pkixdate = (jarTimestamp != null ? jarTimestamp.getTimestamp() :
184-
pkixdate);
185-
this.jarTimestamp = jarTimestamp;
157+
this.date = date;
186158
this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
187159
}
188160

@@ -194,24 +166,11 @@ public AlgorithmChecker(TrustAnchor anchor,
194166
* certificate
195167
* @param pkixdate Date the constraints are checked against. The value is
196168
* either the PKIXParameters date or null for the current date.
197-
* @param variant is the Validator variants of the operation. A null value
169+
* @param variant the Validator variant of the operation. A null value
198170
* passed will set it to Validator.GENERIC.
199171
*/
200172
public AlgorithmChecker(TrustAnchor anchor, Date pkixdate, String variant) {
201-
this(anchor, certPathDefaultConstraints, pkixdate, null, variant);
202-
}
203-
204-
// Check this 'cert' for restrictions in the AnchorCertificates
205-
// trusted certificates list
206-
private static boolean checkFingerprint(X509Certificate cert) {
207-
if (!publicCALimits) {
208-
return false;
209-
}
210-
211-
if (debug != null) {
212-
debug.println("AlgorithmChecker.contains: " + cert.getSigAlgName());
213-
}
214-
return AnchorCertificates.contains(cert);
173+
this(anchor, certPathDefaultConstraints, pkixdate, variant);
215174
}
216175

217176
@Override
@@ -318,18 +277,19 @@ public void check(Certificate cert,
318277
}
319278

320279
ConstraintsParameters cp =
321-
new ConstraintsParameters((X509Certificate)cert,
322-
trustedMatch, pkixdate, jarTimestamp, variant);
280+
new CertPathConstraintsParameters(x509Cert, variant,
281+
anchor, date);
323282

324283
// Check against local constraints if it is DisabledAlgorithmConstraints
325284
if (constraints instanceof DisabledAlgorithmConstraints) {
326-
((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, cp);
285+
((DisabledAlgorithmConstraints)constraints).permits(currSigAlg,
286+
currSigAlgParams, cp);
327287
// DisabledAlgorithmsConstraints does not check primitives, so key
328288
// additional key check.
329289

330290
} else {
331291
// Perform the default constraints checking anyway.
332-
certPathDefaultConstraints.permits(currSigAlg, cp);
292+
certPathDefaultConstraints.permits(currSigAlg, currSigAlgParams, cp);
333293
// Call locally set constraints to check key with primitives.
334294
if (!constraints.permits(primitives, currPubKey)) {
335295
throw new CertPathValidatorException(
@@ -408,14 +368,10 @@ void trySetTrustAnchor(TrustAnchor anchor) {
408368
// Don't bother to change the trustedPubKey.
409369
if (anchor.getTrustedCert() != null) {
410370
prevPubKey = anchor.getTrustedCert().getPublicKey();
411-
// Check for anchor certificate restrictions
412-
trustedMatch = checkFingerprint(anchor.getTrustedCert());
413-
if (trustedMatch && debug != null) {
414-
debug.println("trustedMatch = true");
415-
}
416371
} else {
417372
prevPubKey = anchor.getCAPublicKey();
418373
}
374+
this.anchor = anchor;
419375
}
420376
}
421377

@@ -424,11 +380,12 @@ void trySetTrustAnchor(TrustAnchor anchor) {
424380
*
425381
* @param key the public key to verify the CRL signature
426382
* @param crl the target CRL
427-
* @param variant is the Validator variants of the operation. A null value
383+
* @param variant the Validator variant of the operation. A null value
428384
* passed will set it to Validator.GENERIC.
385+
* @param anchor the trust anchor selected to validate the CRL issuer
429386
*/
430-
static void check(PublicKey key, X509CRL crl, String variant)
431-
throws CertPathValidatorException {
387+
static void check(PublicKey key, X509CRL crl, String variant,
388+
TrustAnchor anchor) throws CertPathValidatorException {
432389

433390
X509CRLImpl x509CRLImpl = null;
434391
try {
@@ -438,24 +395,24 @@ static void check(PublicKey key, X509CRL crl, String variant)
438395
}
439396

440397
AlgorithmId algorithmId = x509CRLImpl.getSigAlgId();
441-
check(key, algorithmId, variant);
398+
check(key, algorithmId, variant, anchor);
442399
}
443400

444401
/**
445402
* Check the signature algorithm with the specified public key.
446403
*
447404
* @param key the public key to verify the CRL signature
448405
* @param algorithmId signature algorithm Algorithm ID
449-
* @param variant is the Validator variants of the operation. A null value
450-
* passed will set it to Validator.GENERIC.
406+
* @param variant the Validator variant of the operation. A null
407+
* value passed will set it to Validator.GENERIC.
408+
* @param anchor the trust anchor selected to validate the public key
451409
*/
452-
static void check(PublicKey key, AlgorithmId algorithmId, String variant)
453-
throws CertPathValidatorException {
454-
String sigAlgName = algorithmId.getName();
455-
AlgorithmParameters sigAlgParams = algorithmId.getParameters();
410+
static void check(PublicKey key, AlgorithmId algorithmId, String variant,
411+
TrustAnchor anchor) throws CertPathValidatorException {
456412

457-
certPathDefaultConstraints.permits(new ConstraintsParameters(
458-
sigAlgName, sigAlgParams, key, variant));
413+
certPathDefaultConstraints.permits(algorithmId.getName(),
414+
algorithmId.getParameters(),
415+
new CertPathConstraintsParameters(key, variant, anchor));
459416
}
460417
}
461418

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package sun.security.provider.certpath;
27+
28+
import java.security.Key;
29+
import java.security.cert.TrustAnchor;
30+
import java.security.cert.X509Certificate;
31+
import java.util.Date;
32+
import java.util.Set;
33+
34+
import sun.security.util.ConstraintsParameters;
35+
import sun.security.validator.Validator;
36+
37+
/**
38+
* This class contains parameters for checking certificates against
39+
* constraints specified in the jdk.certpath.disabledAlgorithms security
40+
* property.
41+
*/
42+
class CertPathConstraintsParameters implements ConstraintsParameters {
43+
// The public key of the certificate
44+
private final Key key;
45+
// The certificate's trust anchor which will be checked against the
46+
// jdkCA constraint, if specified.
47+
private final TrustAnchor anchor;
48+
// The PKIXParameter validity date or the timestamp of the signed JAR
49+
// file, if this chain is associated with a timestamped signed JAR.
50+
private final Date date;
51+
// The variant or usage of this certificate
52+
private final String variant;
53+
// The certificate being checked (may be null if a CRL or OCSPResponse is
54+
// being checked)
55+
private final X509Certificate cert;
56+
57+
public CertPathConstraintsParameters(X509Certificate cert,
58+
String variant, TrustAnchor anchor, Date date) {
59+
this(cert.getPublicKey(), variant, anchor, date, cert);
60+
}
61+
62+
public CertPathConstraintsParameters(Key key, String variant,
63+
TrustAnchor anchor) {
64+
this(key, variant, anchor, null, null);
65+
}
66+
67+
private CertPathConstraintsParameters(Key key, String variant,
68+
TrustAnchor anchor, Date date, X509Certificate cert) {
69+
this.key = key;
70+
this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
71+
this.anchor = anchor;
72+
this.date = date;
73+
this.cert = cert;
74+
}
75+
76+
@Override
77+
public boolean anchorIsJdkCA() {
78+
return CertPathHelper.isJdkCA(anchor);
79+
}
80+
81+
@Override
82+
public Set<Key> getKeys() {
83+
return (key == null) ? Set.of() : Set.of(key);
84+
}
85+
86+
@Override
87+
public Date getDate() {
88+
return date;
89+
}
90+
91+
@Override
92+
public String getVariant() {
93+
return variant;
94+
}
95+
96+
@Override
97+
public String extendedExceptionMsg() {
98+
return (cert == null ? "."
99+
: " used with certificate: " +
100+
cert.getSubjectX500Principal());
101+
}
102+
103+
@Override
104+
public String toString() {
105+
StringBuilder sb = new StringBuilder("[\n");
106+
sb.append("\n Variant: ").append(variant);
107+
if (anchor != null) {
108+
sb.append("\n Anchor: ").append(anchor);
109+
}
110+
if (cert != null) {
111+
sb.append("\n Cert Issuer: ")
112+
.append(cert.getIssuerX500Principal());
113+
sb.append("\n Cert Subject: ")
114+
.append(cert.getSubjectX500Principal());
115+
}
116+
if (key != null) {
117+
sb.append("\n Key: ").append(key.getAlgorithm());
118+
}
119+
if (date != null) {
120+
sb.append("\n Date: ").append(date);
121+
}
122+
sb.append("\n]");
123+
return sb.toString();
124+
}
125+
}

‎src/java.base/share/classes/sun/security/provider/certpath/CertPathHelper.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,13 +28,14 @@
2828
import java.util.Date;
2929
import java.util.Set;
3030

31+
import java.security.cert.TrustAnchor;
3132
import java.security.cert.X509CertSelector;
3233
import java.security.cert.X509CRLSelector;
3334

3435
import sun.security.x509.GeneralNameInterface;
3536

3637
/**
37-
* Helper class that allows access to Sun specific known-public methods in the
38+
* Helper class that allows access to JDK specific known-public methods in the
3839
* java.security.cert package. It relies on a subclass in the
3940
* java.security.cert packages that is initialized before any of these methods
4041
* are called (achieved via static initializers).
@@ -59,6 +60,8 @@ protected abstract void implSetPathToNames(X509CertSelector sel,
5960

6061
protected abstract void implSetDateAndTime(X509CRLSelector sel, Date date, long skew);
6162

63+
protected abstract boolean implIsJdkCA(TrustAnchor anchor);
64+
6265
static void setPathToNames(X509CertSelector sel,
6366
Set<GeneralNameInterface> names) {
6467
instance.implSetPathToNames(sel, names);
@@ -67,4 +70,8 @@ static void setPathToNames(X509CertSelector sel,
6770
public static void setDateAndTime(X509CRLSelector sel, Date date, long skew) {
6871
instance.implSetDateAndTime(sel, date, skew);
6972
}
73+
74+
public static boolean isJdkCA(TrustAnchor anchor) {
75+
return (anchor == null) ? false : instance.implIsJdkCA(anchor);
76+
}
7077
}

‎src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java

+17-8
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
7474
throws CertStoreException
7575
{
7676
return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
77-
reasonsMask, trustAnchors, validity, variant);
77+
reasonsMask, trustAnchors, validity, variant, null);
7878
}
7979
/**
8080
* Return the X509CRLs matching this selector. The selector must be
@@ -91,8 +91,14 @@ public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
9191
Date validity)
9292
throws CertStoreException
9393
{
94+
if (trustAnchors.isEmpty()) {
95+
throw new CertStoreException(
96+
"at least one TrustAnchor must be specified");
97+
}
98+
TrustAnchor anchor = trustAnchors.iterator().next();
9499
return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
95-
reasonsMask, trustAnchors, validity, Validator.VAR_GENERIC);
100+
reasonsMask, trustAnchors, validity,
101+
Validator.VAR_PLUGIN_CODE_SIGNING, anchor);
96102
}
97103

98104
/**
@@ -108,7 +114,8 @@ public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
108114
boolean[] reasonsMask,
109115
Set<TrustAnchor> trustAnchors,
110116
Date validity,
111-
String variant)
117+
String variant,
118+
TrustAnchor anchor)
112119
throws CertStoreException
113120
{
114121
X509Certificate cert = selector.getCertificateChecking();
@@ -137,7 +144,7 @@ public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
137144
DistributionPoint point = t.next();
138145
Collection<X509CRL> crls = getCRLs(selector, certImpl,
139146
point, reasonsMask, signFlag, prevKey, prevCert, provider,
140-
certStores, trustAnchors, validity, variant);
147+
certStores, trustAnchors, validity, variant, anchor);
141148
results.addAll(crls);
142149
}
143150
if (debug != null) {
@@ -162,7 +169,8 @@ private static Collection<X509CRL> getCRLs(X509CRLSelector selector,
162169
X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
163170
boolean signFlag, PublicKey prevKey, X509Certificate prevCert,
164171
String provider, List<CertStore> certStores,
165-
Set<TrustAnchor> trustAnchors, Date validity, String variant)
172+
Set<TrustAnchor> trustAnchors, Date validity, String variant,
173+
TrustAnchor anchor)
166174
throws CertStoreException {
167175

168176
// check for full name
@@ -225,7 +233,7 @@ private static Collection<X509CRL> getCRLs(X509CRLSelector selector,
225233
selector.setIssuerNames(null);
226234
if (selector.match(crl) && verifyCRL(certImpl, point, crl,
227235
reasonsMask, signFlag, prevKey, prevCert, provider,
228-
trustAnchors, certStores, validity, variant)) {
236+
trustAnchors, certStores, validity, variant, anchor)) {
229237
crls.add(crl);
230238
}
231239
} catch (IOException | CRLException e) {
@@ -335,7 +343,8 @@ static boolean verifyCRL(X509CertImpl certImpl, DistributionPoint point,
335343
X509CRL crl, boolean[] reasonsMask, boolean signFlag,
336344
PublicKey prevKey, X509Certificate prevCert, String provider,
337345
Set<TrustAnchor> trustAnchors, List<CertStore> certStores,
338-
Date validity, String variant) throws CRLException, IOException {
346+
Date validity, String variant, TrustAnchor anchor)
347+
throws CRLException, IOException {
339348

340349
if (debug != null) {
341350
debug.println("DistributionPointFetcher.verifyCRL: " +
@@ -682,7 +691,7 @@ static boolean verifyCRL(X509CertImpl certImpl, DistributionPoint point,
682691

683692
// check the crl signature algorithm
684693
try {
685-
AlgorithmChecker.check(prevKey, crl, variant);
694+
AlgorithmChecker.check(prevKey, crl, variant, anchor);
686695
} catch (CertPathValidatorException cpve) {
687696
if (debug != null) {
688697
debug.println("CRL signature algorithm check failed: " + cpve);

‎src/java.base/share/classes/sun/security/provider/certpath/OCSP.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ public static RevocationStatus check(X509Certificate cert,
123123
throws IOException, CertPathValidatorException
124124
{
125125
return check(cert, issuerCert, responderURI, responderCert, date,
126-
Collections.<Extension>emptyList(), Validator.VAR_GENERIC);
126+
Collections.<Extension>emptyList(),
127+
Validator.VAR_PLUGIN_CODE_SIGNING);
127128
}
128129

129130

‎src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,8 @@ void verify(List<CertId> certIds, IssuerInfo issuerInfo,
566566
if (signerCert != null) {
567567
// Check algorithm constraints specified in security property
568568
// "jdk.certpath.disabledAlgorithms".
569-
AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId, variant);
569+
AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId, variant,
570+
issuerInfo.getAnchor());
570571

571572
if (!verifySignature(signerCert)) {
572573
throw new CertPathValidatorException(

‎src/java.base/share/classes/sun/security/provider/certpath/PKIX.java

+14-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
3333
import javax.security.auth.x500.X500Principal;
3434

3535
import sun.security.util.Debug;
36+
import sun.security.validator.Validator;
3637

3738
/**
3839
* Common utility methods and classes used by the PKIX CertPathValidator and
@@ -87,7 +88,7 @@ static class ValidatorParams {
8788
private Set<TrustAnchor> anchors;
8889
private List<X509Certificate> certs;
8990
private Timestamp timestamp;
90-
private String variant;
91+
private String variant = Validator.VAR_GENERIC;
9192

9293
ValidatorParams(CertPath cp, PKIXParameters params)
9394
throws InvalidAlgorithmParameterException
@@ -155,9 +156,17 @@ List<CertStore> certStores() {
155156
}
156157
Date date() {
157158
if (!gotDate) {
158-
date = params.getDate();
159-
if (date == null)
160-
date = new Date();
159+
// use timestamp if checking signed code that is
160+
// timestamped, otherwise use date parameter
161+
if (timestamp != null &&
162+
(variant.equals(Validator.VAR_CODE_SIGNING) ||
163+
variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING))) {
164+
date = timestamp.getTimestamp();
165+
} else {
166+
date = params.getDate();
167+
if (date == null)
168+
date = new Date();
169+
}
161170
gotDate = true;
162171
}
163172
return date;
@@ -198,10 +207,6 @@ PKIXParameters getPKIXParameters() {
198207
return params;
199208
}
200209

201-
Timestamp timestamp() {
202-
return timestamp;
203-
}
204-
205210
String variant() {
206211
return variant;
207212
}

‎src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java

+3-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@
3434
import jdk.internal.event.X509ValidationEvent;
3535
import jdk.internal.event.EventHelper;
3636
import sun.security.provider.certpath.PKIX.ValidatorParams;
37-
import sun.security.validator.Validator;
3837
import sun.security.x509.X509CertImpl;
3938
import sun.security.util.Debug;
4039

@@ -178,7 +177,7 @@ private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
178177
// add standard checkers that we will be using
179178
certPathCheckers.add(untrustedChecker);
180179
certPathCheckers.add(new AlgorithmChecker(anchor, null, params.date(),
181-
params.timestamp(), params.variant()));
180+
params.variant()));
182181
certPathCheckers.add(new KeyChecker(certPathLen,
183182
params.targetCertConstraints()));
184183
certPathCheckers.add(new ConstraintsChecker(certPathLen));
@@ -195,19 +194,7 @@ private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
195194
rootNode);
196195
certPathCheckers.add(pc);
197196

198-
// the time that the certificate validity period should be
199-
// checked against
200-
Date timeToCheck = null;
201-
// use timestamp if checking signed code that is timestamped, otherwise
202-
// use date parameter from PKIXParameters
203-
if ((params.variant() == Validator.VAR_CODE_SIGNING ||
204-
params.variant() == Validator.VAR_PLUGIN_CODE_SIGNING) &&
205-
params.timestamp() != null) {
206-
timeToCheck = params.timestamp().getTimestamp();
207-
} else {
208-
timeToCheck = params.date();
209-
}
210-
BasicChecker bc = new BasicChecker(anchor, timeToCheck,
197+
BasicChecker bc = new BasicChecker(anchor, params.date(),
211198
params.sigProvider(), false);
212199
certPathCheckers.add(bc);
213200

‎src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,8 @@ private void checkCRLs(X509Certificate cert, PublicKey prevKey,
585585
approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
586586
sel, signFlag, prevKey, prevCert,
587587
params.sigProvider(), certStores,
588-
reasonsMask, anchors, null, params.variant()));
588+
reasonsMask, anchors, null,
589+
params.variant(), anchor));
589590
}
590591
} catch (CertStoreException e) {
591592
if (e instanceof CertStoreTypeException) {
@@ -893,7 +894,7 @@ private Collection<X509CRL> verifyPossibleCRLs(Set<X509CRL> crls,
893894
if (DistributionPointFetcher.verifyCRL(
894895
certImpl, point, crl, reasonsMask, signFlag,
895896
prevKey, null, params.sigProvider(), anchors,
896-
certStores, params.date(), params.variant()))
897+
certStores, params.date(), params.variant(), anchor))
897898
{
898899
results.add(crl);
899900
}

‎src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ private void checkAlgorithmConstraints(X509Certificate[] chain,
15581558
// A forward checker, need to check from trust to target
15591559
if (checkedLength >= 0) {
15601560
AlgorithmChecker checker =
1561-
new AlgorithmChecker(constraints, null,
1561+
new AlgorithmChecker(constraints,
15621562
(checkClientTrusted ? Validator.VAR_TLS_CLIENT :
15631563
Validator.VAR_TLS_SERVER));
15641564
checker.init(false);

‎src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -838,8 +838,7 @@ private static boolean conformsToAlgorithmConstraints(
838838
AlgorithmConstraints constraints, Certificate[] chain,
839839
String variant) {
840840

841-
AlgorithmChecker checker =
842-
new AlgorithmChecker(constraints, null, variant);
841+
AlgorithmChecker checker = new AlgorithmChecker(constraints, variant);
843842
try {
844843
checker.init(false);
845844
} catch (CertPathValidatorException cpve) {

‎src/java.base/share/classes/sun/security/util/AnchorCertificates.java

+18-5
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.HashSet;
3737
import java.util.Set;
3838

39+
import javax.security.auth.x500.X500Principal;
3940
import sun.security.x509.X509CertImpl;
4041

4142
/**
@@ -47,9 +48,10 @@ public class AnchorCertificates {
4748
private static final Debug debug = Debug.getInstance("certpath");
4849
private static final String HASH = "SHA-256";
4950
private static Set<String> certs = Collections.emptySet();
51+
private static Set<X500Principal> certIssuers = Collections.emptySet();
5052

5153
static {
52-
AccessController.doPrivileged(new PrivilegedAction<Void>() {
54+
AccessController.doPrivileged(new PrivilegedAction<>() {
5355
@Override
5456
public Void run() {
5557
File f = new File(FilePaths.cacerts());
@@ -59,15 +61,16 @@ public Void run() {
5961
try (FileInputStream fis = new FileInputStream(f)) {
6062
cacerts.load(fis, null);
6163
certs = new HashSet<>();
64+
certIssuers = new HashSet<>();
6265
Enumeration<String> list = cacerts.aliases();
63-
String alias;
6466
while (list.hasMoreElements()) {
65-
alias = list.nextElement();
67+
String alias = list.nextElement();
6668
// Check if this cert is labeled a trust anchor.
6769
if (alias.contains(" [jdk")) {
6870
X509Certificate cert = (X509Certificate) cacerts
6971
.getCertificate(alias);
7072
certs.add(X509CertImpl.getFingerprint(HASH, cert));
73+
certIssuers.add(cert.getSubjectX500Principal());
7174
}
7275
}
7376
}
@@ -83,10 +86,10 @@ public Void run() {
8386
}
8487

8588
/**
86-
* Checks if a certificate is a trust anchor.
89+
* Checks if a certificate is a JDK trust anchor.
8790
*
8891
* @param cert the certificate to check
89-
* @return true if the certificate is trusted.
92+
* @return true if the certificate is a JDK trust anchor
9093
*/
9194
public static boolean contains(X509Certificate cert) {
9295
String key = X509CertImpl.getFingerprint(HASH, cert);
@@ -98,5 +101,15 @@ public static boolean contains(X509Certificate cert) {
98101
return result;
99102
}
100103

104+
/**
105+
* Checks if a JDK trust anchor is the issuer of a certificate.
106+
*
107+
* @param cert the certificate to check
108+
* @return true if the certificate is issued by a trust anchor
109+
*/
110+
public static boolean issuerOf(X509Certificate cert) {
111+
return certIssuers.contains(cert.getIssuerX500Principal());
112+
}
113+
101114
private AnchorCertificates() {}
102115
}

‎src/java.base/share/classes/sun/security/util/ConstraintsParameters.java

+27-152
Original file line numberDiff line numberDiff line change
@@ -25,167 +25,42 @@
2525

2626
package sun.security.util;
2727

28-
import sun.security.validator.Validator;
29-
30-
import java.security.AlgorithmParameters;
3128
import java.security.Key;
32-
import java.security.Timestamp;
33-
import java.security.cert.X509Certificate;
34-
import java.security.interfaces.ECKey;
35-
import java.security.interfaces.XECKey;
36-
import java.security.spec.NamedParameterSpec;
3729
import java.util.Date;
30+
import java.util.Set;
3831

3932
/**
40-
* This class contains parameters for checking against constraints that extend
41-
* past the publicly available parameters in java.security.AlgorithmConstraints.
42-
*
43-
* This is currently passed between PKIX, AlgorithmChecker,
44-
* and DisabledAlgorithmConstraints.
33+
* This interface contains parameters for checking against constraints that
34+
* extend past the publicly available parameters in
35+
* java.security.AlgorithmConstraints.
4536
*/
46-
public class ConstraintsParameters {
47-
/*
48-
* The below 3 values are used the same as the permit() methods
49-
* published in java.security.AlgorithmConstraints.
50-
*/
51-
// Algorithm string to be checked against constraints
52-
private final String algorithm;
53-
// AlgorithmParameters to the algorithm being checked
54-
private final AlgorithmParameters algParams;
55-
// Key being checked against constraints
56-
private final Key key;
37+
public interface ConstraintsParameters {
5738

58-
/*
59-
* New values that are checked against constraints that the current public
60-
* API does not support.
39+
/**
40+
* Returns true if a certificate chains back to a trusted JDK root CA.
6141
*/
62-
// A certificate being passed to check against constraints.
63-
private final X509Certificate cert;
64-
// This is true if the trust anchor in the certificate chain matches a cert
65-
// in AnchorCertificates
66-
private final boolean trustedMatch;
67-
// PKIXParameter date
68-
private final Date pkixDate;
69-
// Timestamp of the signed JAR file
70-
private final Timestamp jarTimestamp;
71-
private final String variant;
72-
// Named Curve
73-
private final String[] curveStr;
74-
private static final String[] EMPTYLIST = new String[0];
75-
76-
public ConstraintsParameters(X509Certificate c, boolean match,
77-
Date pkixdate, Timestamp jarTime, String variant) {
78-
cert = c;
79-
trustedMatch = match;
80-
pkixDate = pkixdate;
81-
jarTimestamp = jarTime;
82-
this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
83-
algorithm = null;
84-
algParams = null;
85-
key = null;
86-
if (c != null) {
87-
curveStr = getNamedCurveFromKey(c.getPublicKey());
88-
} else {
89-
curveStr = EMPTYLIST;
90-
}
91-
}
92-
93-
public ConstraintsParameters(String algorithm, AlgorithmParameters params,
94-
Key key, String variant) {
95-
this.algorithm = algorithm;
96-
algParams = params;
97-
this.key = key;
98-
curveStr = getNamedCurveFromKey(key);
99-
cert = null;
100-
trustedMatch = false;
101-
pkixDate = null;
102-
jarTimestamp = null;
103-
this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
104-
}
105-
106-
107-
public ConstraintsParameters(X509Certificate c) {
108-
this(c, false, null, null,
109-
Validator.VAR_GENERIC);
110-
}
111-
112-
public ConstraintsParameters(Timestamp jarTime) {
113-
this(null, false, null, jarTime, Validator.VAR_GENERIC);
114-
}
115-
116-
public String getAlgorithm() {
117-
return algorithm;
118-
}
119-
120-
public AlgorithmParameters getAlgParams() {
121-
return algParams;
122-
}
42+
boolean anchorIsJdkCA();
12343

124-
public Key getKey() {
125-
return key;
126-
}
127-
128-
// Returns if the trust anchor has a match if anchor checking is enabled.
129-
public boolean isTrustedMatch() {
130-
return trustedMatch;
131-
}
132-
133-
public X509Certificate getCertificate() {
134-
return cert;
135-
}
136-
137-
public Date getPKIXParamDate() {
138-
return pkixDate;
139-
}
140-
141-
public Timestamp getJARTimestamp() {
142-
return jarTimestamp;
143-
}
144-
145-
public String getVariant() {
146-
return variant;
147-
}
148-
149-
public String[] getNamedCurve() {
150-
return curveStr;
151-
}
44+
/**
45+
* Returns the set of keys that should be checked against the
46+
* constraints, or an empty set if there are no keys to be checked.
47+
*/
48+
Set<Key> getKeys();
15249

153-
public static String[] getNamedCurveFromKey(Key key) {
154-
if (key instanceof ECKey) {
155-
NamedCurve nc = CurveDB.lookup(((ECKey)key).getParams());
156-
return (nc == null ? EMPTYLIST : nc.getNameAndAliases());
157-
} else if (key instanceof XECKey) {
158-
String[] s = {
159-
((NamedParameterSpec)((XECKey)key).getParams()).getName()
160-
};
161-
return s;
162-
} else {
163-
return EMPTYLIST;
164-
}
165-
}
50+
/**
51+
* Returns the date that should be checked against the constraints, or
52+
* null if not set.
53+
*/
54+
Date getDate();
16655

167-
public String toString() {
168-
StringBuilder s = new StringBuilder();
169-
s.append("Cert: ");
170-
if (cert != null) {
171-
s.append(cert.toString());
172-
s.append("\nSigAlgo: ");
173-
s.append(cert.getSigAlgName());
174-
} else {
175-
s.append("None");
176-
}
177-
s.append("\nAlgParams: ");
178-
if (getAlgParams() != null) {
179-
getAlgParams().toString();
180-
} else {
181-
s.append("None");
182-
}
183-
s.append("\nNamedCurves: ");
184-
for (String c : getNamedCurve()) {
185-
s.append(c + " ");
186-
}
187-
s.append("\nVariant: " + getVariant());
188-
return s.toString();
189-
}
56+
/**
57+
* Returns the Validator variant.
58+
*/
59+
String getVariant();
19060

61+
/**
62+
* Returns an extended message used in exceptions. See
63+
* DisabledAlgorithmConstraints for usage.
64+
*/
65+
String extendedExceptionMsg();
19166
}

‎src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java

+128-94
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package sun.security.util;
27+
28+
import java.security.CodeSigner;
29+
import java.security.Key;
30+
import java.security.Timestamp;
31+
import java.security.cert.CertPath;
32+
import java.security.cert.X509Certificate;
33+
import java.util.Date;
34+
import java.util.HashSet;
35+
import java.util.List;
36+
import java.util.Set;
37+
import sun.security.util.AnchorCertificates;
38+
import sun.security.util.ConstraintsParameters;
39+
import sun.security.validator.Validator;
40+
41+
/**
42+
* This class contains parameters for checking signed JARs against
43+
* constraints specified in the jdk.jar.disabledAlgorithms security
44+
* property.
45+
*/
46+
public class JarConstraintsParameters implements ConstraintsParameters {
47+
48+
// true if chain is anchored by a JDK root CA
49+
private boolean anchorIsJdkCA;
50+
private boolean anchorIsJdkCASet;
51+
// The timestamp of the signed JAR file, if timestamped
52+
private Date timestamp;
53+
// The keys of the signers
54+
private final Set<Key> keys;
55+
// The certs in the signers' chains that are issued by the trust anchor
56+
private final Set<X509Certificate> certsIssuedByAnchor;
57+
// The extended exception message
58+
private String message;
59+
60+
/**
61+
* Create a JarConstraintsParameters.
62+
*
63+
* @param signers the CodeSigners that signed the JAR
64+
*/
65+
public JarConstraintsParameters(CodeSigner[] signers) {
66+
this.keys = new HashSet<>();
67+
this.certsIssuedByAnchor = new HashSet<>();
68+
Date latestTimestamp = null;
69+
boolean skipTimestamp = false;
70+
71+
// Iterate over the signers and extract the keys, the latest
72+
// timestamp, and the last certificate of each chain which can be
73+
// used for checking if the signer's certificate chains back to a
74+
// JDK root CA
75+
for (CodeSigner signer : signers) {
76+
init(signer.getSignerCertPath());
77+
Timestamp timestamp = signer.getTimestamp();
78+
if (timestamp == null) {
79+
// this means one of the signers doesn't have a timestamp
80+
// and the JAR should be treated as if it isn't timestamped
81+
latestTimestamp = null;
82+
skipTimestamp = true;
83+
} else {
84+
// add the key and last cert of TSA too
85+
init(timestamp.getSignerCertPath());
86+
if (!skipTimestamp) {
87+
Date timestampDate = timestamp.getTimestamp();
88+
if (latestTimestamp == null) {
89+
latestTimestamp = timestampDate;
90+
} else {
91+
if (latestTimestamp.before(timestampDate)) {
92+
latestTimestamp = timestampDate;
93+
}
94+
}
95+
}
96+
}
97+
}
98+
this.timestamp = latestTimestamp;
99+
}
100+
101+
// extract last certificate and key from chain
102+
private void init(CertPath cp) {
103+
@SuppressWarnings("unchecked")
104+
List<X509Certificate> chain =
105+
(List<X509Certificate>)cp.getCertificates();
106+
if (!chain.isEmpty()) {
107+
this.certsIssuedByAnchor.add(chain.get(chain.size() - 1));
108+
this.keys.add(chain.get(0).getPublicKey());
109+
}
110+
}
111+
112+
@Override
113+
public String getVariant() {
114+
return Validator.VAR_GENERIC;
115+
}
116+
117+
/**
118+
* Since loading the cacerts keystore can be an expensive operation,
119+
* this is only performed if this method is called during a "jdkCA"
120+
* constraints check of a disabled algorithm, and the result is cached.
121+
*
122+
* @return true if at least one of the certificates are issued by a
123+
* JDK root CA
124+
*/
125+
@Override
126+
public boolean anchorIsJdkCA() {
127+
if (anchorIsJdkCASet) {
128+
return anchorIsJdkCA;
129+
}
130+
for (X509Certificate cert : certsIssuedByAnchor) {
131+
if (AnchorCertificates.issuerOf(cert)) {
132+
anchorIsJdkCA = true;
133+
break;
134+
}
135+
}
136+
anchorIsJdkCASet = true;
137+
return anchorIsJdkCA;
138+
}
139+
140+
@Override
141+
public Date getDate() {
142+
return timestamp;
143+
}
144+
145+
@Override
146+
public Set<Key> getKeys() {
147+
return keys;
148+
}
149+
150+
/**
151+
* Sets the extended error message. Note: this should be used
152+
* carefully as it is specific to the attribute/entry/file being checked.
153+
*
154+
* @param file the name of the signature related file being verified
155+
* @param target the attribute containing the algorithm that is being
156+
* checked
157+
*/
158+
public void setExtendedExceptionMsg(String file, String target) {
159+
message = " used" + (target != null ? " with " + target : "") +
160+
" in " + file + " file.";
161+
}
162+
163+
@Override
164+
public String extendedExceptionMsg() {
165+
return message;
166+
}
167+
168+
@Override
169+
public String toString() {
170+
StringBuilder sb = new StringBuilder("[\n");
171+
sb.append("\n Variant: ").append(getVariant());
172+
sb.append("\n Certs Issued by Anchor:");
173+
for (X509Certificate cert : certsIssuedByAnchor) {
174+
sb.append("\n Cert Issuer: ")
175+
.append(cert.getIssuerX500Principal());
176+
sb.append("\n Cert Subject: ")
177+
.append(cert.getSubjectX500Principal());
178+
}
179+
for (Key key : keys) {
180+
sb.append("\n Key: ").append(key.getAlgorithm());
181+
}
182+
if (timestamp != null) {
183+
sb.append("\n Timestamp: ").append(timestamp);
184+
}
185+
sb.append("\n]");
186+
return sb.toString();
187+
}
188+
}

‎src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java

+54-5
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@
2727

2828
import java.security.*;
2929
import java.io.*;
30-
import java.security.CodeSigner;
3130
import java.util.*;
3231
import java.util.jar.*;
3332

34-
import java.util.Base64;
35-
3633
import sun.security.jca.Providers;
34+
import sun.security.util.DisabledAlgorithmConstraints;
35+
import sun.security.util.JarConstraintsParameters;
3736

3837
/**
3938
* This class is used to verify each entry in a jar file with its
@@ -202,12 +201,29 @@ public CodeSigner[] verify(Hashtable<String, CodeSigner[]> verifiedSigners,
202201
throw new SecurityException("digest missing for " + name);
203202
}
204203

205-
if (signers != null)
204+
if (signers != null) {
206205
return signers;
206+
}
207+
208+
JarConstraintsParameters params =
209+
getParams(verifiedSigners, sigFileSigners);
207210

208211
for (int i=0; i < digests.size(); i++) {
209212

210-
MessageDigest digest = digests.get(i);
213+
MessageDigest digest = digests.get(i);
214+
if (params != null) {
215+
try {
216+
params.setExtendedExceptionMsg(JarFile.MANIFEST_NAME,
217+
name + " entry");
218+
DisabledAlgorithmConstraints.jarConstraints()
219+
.permits(digest.getAlgorithm(), params);
220+
} catch (GeneralSecurityException e) {
221+
if (debug != null) {
222+
debug.println("Digest algorithm is restricted: " + e);
223+
}
224+
return null;
225+
}
226+
}
211227
byte [] manHash = manifestHashes.get(i);
212228
byte [] theHash = digest.digest();
213229

@@ -231,4 +247,37 @@ public CodeSigner[] verify(Hashtable<String, CodeSigner[]> verifiedSigners,
231247
}
232248
return signers;
233249
}
250+
251+
/**
252+
* Get constraints parameters for JAR. The constraints should be
253+
* checked against all code signers. Returns the parameters,
254+
* or null if the signers for this entry have already been checked.
255+
*/
256+
private JarConstraintsParameters getParams(
257+
Map<String, CodeSigner[]> verifiedSigners,
258+
Map<String, CodeSigner[]> sigFileSigners) {
259+
260+
// verifiedSigners is usually preloaded with the Manifest's signers.
261+
// If verifiedSigners contains the Manifest, then it will have all of
262+
// the signers of the JAR. But if it doesn't then we need to fallback
263+
// and check verifiedSigners to see if the signers of this entry have
264+
// been checked already.
265+
if (verifiedSigners.containsKey(JarFile.MANIFEST_NAME)) {
266+
if (verifiedSigners.size() > 1) {
267+
// this means we already checked it previously
268+
return null;
269+
} else {
270+
return new JarConstraintsParameters(
271+
verifiedSigners.get(JarFile.MANIFEST_NAME));
272+
}
273+
} else {
274+
CodeSigner[] signers = sigFileSigners.get(name);
275+
if (verifiedSigners.containsValue(signers)) {
276+
return null;
277+
} else {
278+
return new JarConstraintsParameters(signers);
279+
}
280+
}
281+
}
234282
}
283+

‎src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java

+24-42
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import java.security.NoSuchAlgorithmException;
3434
import java.security.PrivateKey;
3535
import java.security.SignatureException;
36-
import java.security.Timestamp;
3736
import java.security.cert.CertPath;
3837
import java.security.cert.X509Certificate;
3938
import java.security.cert.CertificateException;
@@ -47,6 +46,7 @@
4746
import java.util.List;
4847
import java.util.Locale;
4948
import java.util.Map;
49+
import java.util.Set;
5050
import java.util.jar.Attributes;
5151
import java.util.jar.JarException;
5252
import java.util.jar.JarFile;
@@ -61,16 +61,6 @@ public class SignatureFileVerifier {
6161
/* Are we debugging ? */
6262
private static final Debug debug = Debug.getInstance("jar");
6363

64-
/**
65-
* Holder class to delay initialization of DisabledAlgorithmConstraints
66-
* until needed.
67-
*/
68-
private static class ConfigurationHolder {
69-
static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
70-
new DisabledAlgorithmConstraints(
71-
DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
72-
}
73-
7464
private ArrayList<CodeSigner[]> signerCache;
7565

7666
private static final String ATTR_DIGEST =
@@ -99,13 +89,13 @@ private static class ConfigurationHolder {
9989
/* for generating certpath objects */
10090
private CertificateFactory certificateFactory = null;
10191

102-
/** Algorithms that have been checked if they are weak. */
103-
private Map<String, Boolean> permittedAlgs= new HashMap<>();
104-
105-
/** TSA timestamp of signed jar. The newest timestamp is used. If there
106-
* was no TSA timestamp used when signed, current time is used ("null").
92+
/** Algorithms that have been previously checked against disabled
93+
* constraints.
10794
*/
108-
private Timestamp timestamp = null;
95+
private Map<String, Boolean> permittedAlgs = new HashMap<>();
96+
97+
/** ConstraintsParameters for checking disabled algorithms */
98+
private JarConstraintsParameters params;
10999

110100
/**
111101
* Create the named SignatureFileVerifier.
@@ -320,32 +310,23 @@ private void processImpl(Hashtable<String, CodeSigner[]> signers,
320310
name);
321311
}
322312

323-
324313
CodeSigner[] newSigners = getSigners(infos, block);
325314

326315
// make sure we have something to do all this work for...
327-
if (newSigners == null)
316+
if (newSigners == null) {
328317
return;
318+
}
329319

330-
/*
331-
* Look for the latest timestamp in the signature block. If an entry
332-
* has no timestamp, use current time (aka null).
333-
*/
334-
for (CodeSigner s: newSigners) {
335-
if (debug != null) {
336-
debug.println("Gathering timestamp for: " + s.toString());
337-
}
338-
if (s.getTimestamp() == null) {
339-
timestamp = null;
340-
break;
341-
} else if (timestamp == null) {
342-
timestamp = s.getTimestamp();
343-
} else {
344-
if (timestamp.getTimestamp().before(
345-
s.getTimestamp().getTimestamp())) {
346-
timestamp = s.getTimestamp();
347-
}
348-
}
320+
// check if any of the algorithms used to verify the SignerInfos
321+
// are disabled
322+
params = new JarConstraintsParameters(newSigners);
323+
Set<String> notDisabledAlgorithms =
324+
SignerInfo.verifyAlgorithms(infos, params, name + " PKCS7");
325+
326+
// add the SignerInfo algorithms that are ok to the permittedAlgs map
327+
// so they are not checked again
328+
for (String algorithm : notDisabledAlgorithms) {
329+
permittedAlgs.put(algorithm, Boolean.TRUE);
349330
}
350331

351332
Iterator<Map.Entry<String,Attributes>> entries =
@@ -396,13 +377,14 @@ private void processImpl(Hashtable<String, CodeSigner[]> signers,
396377
* store the result. If the algorithm is in the map use that result.
397378
* False is returned for weak algorithm, true for good algorithms.
398379
*/
399-
boolean permittedCheck(String key, String algorithm) {
380+
private boolean permittedCheck(String key, String algorithm) {
400381
Boolean permitted = permittedAlgs.get(algorithm);
401382
if (permitted == null) {
402383
try {
403-
ConfigurationHolder.JAR_DISABLED_CHECK.permits(algorithm,
404-
new ConstraintsParameters(timestamp));
405-
} catch(GeneralSecurityException e) {
384+
params.setExtendedExceptionMsg(name + ".SF", key + " attribute");
385+
DisabledAlgorithmConstraints
386+
.jarConstraints().permits(algorithm, params);
387+
} catch (GeneralSecurityException e) {
406388
permittedAlgs.put(algorithm, Boolean.FALSE);
407389
permittedAlgs.put(key.toUpperCase(), Boolean.FALSE);
408390
if (debug != null) {

‎src/java.base/share/classes/sun/security/validator/PKIXValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ X509Certificate[] engineValidate(X509Certificate[] chain,
224224
// add new algorithm constraints checker
225225
if (constraints != null) {
226226
pkixParameters.addCertPathChecker(
227-
new AlgorithmChecker(constraints, null, variant));
227+
new AlgorithmChecker(constraints, variant));
228228
}
229229

230230
// attach it to the PKIXBuilderParameters.

‎src/java.base/share/classes/sun/security/validator/SimpleValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ X509Certificate[] engineValidate(X509Certificate[] chain,
167167
AlgorithmChecker appAlgChecker = null;
168168
if (constraints != null) {
169169
appAlgChecker = new AlgorithmChecker(anchor, constraints, null,
170-
null, variant);
170+
variant);
171171
}
172172

173173
// verify top down, starting at the certificate issued by

‎test/jdk/sun/security/tools/jarsigner/TimestampCheck.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,14 @@ public static void main(String[] args) throws Throwable {
318318
sign("tsdisabled", "-digestalg", "MD5",
319319
"-sigalg", "MD5withRSA", "-tsadigestalg", "MD5")
320320
.shouldHaveExitValue(68)
321-
.shouldContain("The timestamp is invalid. Without a valid timestamp")
321+
.shouldContain("TSA certificate chain is invalid")
322322
.shouldMatch("MD5.*-digestalg.*is disabled")
323323
.shouldMatch("MD5.*-tsadigestalg.*is disabled")
324324
.shouldMatch("MD5withRSA.*-sigalg.*is disabled");
325325
checkDisabled("tsdisabled.jar");
326326

327327
signVerbose("tsdisabled", "unsigned.jar", "tsdisabled2.jar", "signer")
328328
.shouldHaveExitValue(64)
329-
.shouldContain("The timestamp is invalid. Without a valid timestamp")
330329
.shouldContain("TSA certificate chain is invalid");
331330

332331
// Disabled timestamp is an error and jar treated unsigned
@@ -658,7 +657,7 @@ static void checkDisabled(String file) throws Exception {
658657
.shouldMatch("Timestamp signature algorithm: .*key.*(disabled)");
659658
verify(file, "-J-Djava.security.debug=jar")
660659
.shouldHaveExitValue(16)
661-
.shouldMatch("SignatureException:.*disabled");
660+
.shouldMatch("SignatureException:.*keysize");
662661

663662
// For 8171319: keytool should print out warnings when reading or
664663
// generating cert/cert req using disabled algorithms.

0 commit comments

Comments
 (0)
Please sign in to comment.