New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8243585: AlgorithmChecker::check throws confusing exception when it rejects the signer key #5928
Closed
Closed
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2cf52b3
8243585: AlgorithmChecker::check throws confusing exception when it r…
seanjmullan 2704594
Remove trailing whitespace.
seanjmullan cf5a4d7
- Changed names of AlgorithmDecomposer.canonicalName and decomposeOne…
seanjmullan f203112
- Skip digest alg decomposing check for algorithms that don't contain…
seanjmullan 052c28f
Address Max' comments.
seanjmullan d163b5b
Add setTrustAnchorAndKeys method and change ctor and trySetTrustAncho…
seanjmullan File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,10 +74,10 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { | |
private static final Debug debug = Debug.getInstance("certpath"); | ||
|
||
private final AlgorithmConstraints constraints; | ||
private final PublicKey trustedPubKey; | ||
private final Date date; | ||
private PublicKey prevPubKey; | ||
private final String variant; | ||
private PublicKey trustedPubKey; | ||
private PublicKey prevPubKey; | ||
private TrustAnchor anchor; | ||
|
||
private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET = | ||
|
@@ -90,10 +90,6 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { | |
CryptoPrimitive.PUBLIC_KEY_ENCRYPTION, | ||
CryptoPrimitive.KEY_AGREEMENT)); | ||
|
||
private static final DisabledAlgorithmConstraints | ||
certPathDefaultConstraints = | ||
DisabledAlgorithmConstraints.certPathConstraints(); | ||
|
||
/** | ||
* Create a new {@code AlgorithmChecker} with the given | ||
* {@code TrustAnchor} and {@code String} variant. | ||
|
@@ -104,7 +100,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { | |
* passed will set it to Validator.GENERIC. | ||
*/ | ||
public AlgorithmChecker(TrustAnchor anchor, String variant) { | ||
this(anchor, certPathDefaultConstraints, null, variant); | ||
this(anchor, null, null, variant); | ||
} | ||
|
||
/** | ||
|
@@ -152,8 +148,8 @@ public AlgorithmChecker(TrustAnchor anchor, | |
} | ||
|
||
this.prevPubKey = this.trustedPubKey; | ||
this.constraints = (constraints == null ? certPathDefaultConstraints : | ||
constraints); | ||
this.constraints = constraints == null ? | ||
DisabledAlgorithmConstraints.certPathConstraints() : constraints; | ||
this.date = date; | ||
this.variant = (variant == null ? Validator.VAR_GENERIC : variant); | ||
} | ||
|
@@ -172,18 +168,14 @@ public AlgorithmChecker(TrustAnchor anchor, | |
* passed will set it to Validator.GENERIC. | ||
*/ | ||
public AlgorithmChecker(TrustAnchor anchor, Date date, String variant) { | ||
this(anchor, certPathDefaultConstraints, date, variant); | ||
this(anchor, null, date, variant); | ||
} | ||
|
||
@Override | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. |
||
public void init(boolean forward) throws CertPathValidatorException { | ||
// Note that this class does not support forward mode. | ||
if (!forward) { | ||
if (trustedPubKey != null) { | ||
prevPubKey = trustedPubKey; | ||
} else { | ||
prevPubKey = null; | ||
} | ||
prevPubKey = trustedPubKey; | ||
} else { | ||
throw new | ||
CertPathValidatorException("forward checking not supported"); | ||
|
@@ -207,8 +199,8 @@ public void check(Certificate cert, | |
Collection<String> unresolvedCritExts) | ||
throws CertPathValidatorException { | ||
|
||
if (!(cert instanceof X509Certificate) || constraints == null) { | ||
// ignore the check for non-x.509 certificate or null constraints | ||
if (!(cert instanceof X509Certificate)) { | ||
// ignore the check for non-x.509 certificate | ||
return; | ||
} | ||
|
||
|
@@ -233,115 +225,114 @@ public void check(Certificate cert, | |
PublicKey currPubKey = cert.getPublicKey(); | ||
String currSigAlg = x509Cert.getSigAlgName(); | ||
|
||
// Check the signature algorithm and parameters against constraints. | ||
if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, currSigAlg, | ||
currSigAlgParams)) { | ||
throw new CertPathValidatorException( | ||
"Algorithm constraints check failed on signature " + | ||
"algorithm: " + currSigAlg, null, null, -1, | ||
BasicReason.ALGORITHM_CONSTRAINED); | ||
} | ||
|
||
// Assume all key usage bits are set if key usage is not present | ||
Set<CryptoPrimitive> primitives = KU_PRIMITIVE_SET; | ||
|
||
if (keyUsage != null) { | ||
primitives = EnumSet.noneOf(CryptoPrimitive.class); | ||
|
||
if (keyUsage[0] || keyUsage[1] || keyUsage[5] || keyUsage[6]) { | ||
// keyUsage[0]: KeyUsage.digitalSignature | ||
// keyUsage[1]: KeyUsage.nonRepudiation | ||
// keyUsage[5]: KeyUsage.keyCertSign | ||
// keyUsage[6]: KeyUsage.cRLSign | ||
primitives.add(CryptoPrimitive.SIGNATURE); | ||
} | ||
|
||
if (keyUsage[2]) { // KeyUsage.keyEncipherment | ||
primitives.add(CryptoPrimitive.KEY_ENCAPSULATION); | ||
} | ||
|
||
if (keyUsage[3]) { // KeyUsage.dataEncipherment | ||
primitives.add(CryptoPrimitive.PUBLIC_KEY_ENCRYPTION); | ||
} | ||
|
||
if (keyUsage[4]) { // KeyUsage.keyAgreement | ||
primitives.add(CryptoPrimitive.KEY_AGREEMENT); | ||
} | ||
|
||
// KeyUsage.encipherOnly and KeyUsage.decipherOnly are | ||
// undefined in the absence of the keyAgreement bit. | ||
|
||
if (primitives.isEmpty()) { | ||
throw new CertPathValidatorException( | ||
"incorrect KeyUsage extension bits", | ||
null, null, -1, PKIXReason.INVALID_KEY_USAGE); | ||
if (constraints instanceof DisabledAlgorithmConstraints) { | ||
DisabledAlgorithmConstraints dac = | ||
(DisabledAlgorithmConstraints)constraints; | ||
if (prevPubKey != null && prevPubKey == trustedPubKey) { | ||
// check constraints of trusted public key (make sure | ||
// algorithm and size is not restricted) | ||
CertPathConstraintsParameters cp = | ||
new CertPathConstraintsParameters(trustedPubKey, variant, | ||
anchor, date); | ||
dac.permits(trustedPubKey.getAlgorithm(), cp); | ||
} | ||
} | ||
|
||
ConstraintsParameters cp = | ||
new CertPathConstraintsParameters(x509Cert, variant, | ||
// Check the signature algorithm and parameters against constraints | ||
CertPathConstraintsParameters cp = | ||
new CertPathConstraintsParameters(x509Cert, variant, | ||
anchor, date); | ||
|
||
// Check against local constraints if it is DisabledAlgorithmConstraints | ||
if (constraints instanceof DisabledAlgorithmConstraints) { | ||
((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, | ||
currSigAlgParams, cp); | ||
// DisabledAlgorithmsConstraints does not check primitives, so key | ||
// additional key check. | ||
|
||
dac.permits(currSigAlg, currSigAlgParams, cp); | ||
} else { | ||
// Perform the default constraints checking anyway. | ||
certPathDefaultConstraints.permits(currSigAlg, currSigAlgParams, cp); | ||
// Call locally set constraints to check key with primitives. | ||
if (!constraints.permits(primitives, currPubKey)) { | ||
throw new CertPathValidatorException( | ||
"Algorithm constraints check failed on key " + | ||
currPubKey.getAlgorithm() + " with size of " + | ||
sun.security.util.KeyUtil.getKeySize(currPubKey) + | ||
"bits", | ||
if (prevPubKey != null) { | ||
if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, | ||
currSigAlg, prevPubKey, currSigAlgParams)) { | ||
throw new CertPathValidatorException( | ||
"Algorithm constraints check failed on " + | ||
currSigAlg + "signature and " + | ||
currPubKey.getAlgorithm() + " key with size of " + | ||
sun.security.util.KeyUtil.getKeySize(currPubKey) + | ||
"bits", | ||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
} | ||
} else { | ||
if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, | ||
currSigAlg, currSigAlgParams)) { | ||
throw new CertPathValidatorException( | ||
"Algorithm constraints check failed on " + | ||
"signature algorithm: " + currSigAlg, | ||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
} | ||
} | ||
} | ||
// Assume all key usage bits are set if key usage is not present | ||
Set<CryptoPrimitive> primitives = KU_PRIMITIVE_SET; | ||
|
||
// If there is no previous key, set one and exit | ||
if (prevPubKey == null) { | ||
prevPubKey = currPubKey; | ||
return; | ||
} | ||
|
||
// Check with previous cert for signature algorithm and public key | ||
if (!constraints.permits( | ||
SIGNATURE_PRIMITIVE_SET, | ||
currSigAlg, prevPubKey, currSigAlgParams)) { | ||
throw new CertPathValidatorException( | ||
"Algorithm constraints check failed on " + | ||
"signature algorithm: " + currSigAlg, | ||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
} | ||
if (keyUsage != null) { | ||
primitives = EnumSet.noneOf(CryptoPrimitive.class); | ||
|
||
// Inherit key parameters from previous key | ||
if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) { | ||
// Inherit DSA parameters from previous key | ||
if (!(prevPubKey instanceof DSAPublicKey)) { | ||
throw new CertPathValidatorException("Input key is not " + | ||
"of a appropriate type for inheriting parameters"); | ||
if (keyUsage[0] || keyUsage[1] || keyUsage[5] || keyUsage[6]) { | ||
// keyUsage[0]: KeyUsage.digitalSignature | ||
// keyUsage[1]: KeyUsage.nonRepudiation | ||
// keyUsage[5]: KeyUsage.keyCertSign | ||
// keyUsage[6]: KeyUsage.cRLSign | ||
primitives.add(CryptoPrimitive.SIGNATURE); | ||
} | ||
|
||
if (keyUsage[2]) { // KeyUsage.keyEncipherment | ||
primitives.add(CryptoPrimitive.KEY_ENCAPSULATION); | ||
} | ||
|
||
if (keyUsage[3]) { // KeyUsage.dataEncipherment | ||
primitives.add(CryptoPrimitive.PUBLIC_KEY_ENCRYPTION); | ||
} | ||
|
||
if (keyUsage[4]) { // KeyUsage.keyAgreement | ||
primitives.add(CryptoPrimitive.KEY_AGREEMENT); | ||
} | ||
|
||
// KeyUsage.encipherOnly and KeyUsage.decipherOnly are | ||
// undefined in the absence of the keyAgreement bit. | ||
|
||
if (primitives.isEmpty()) { | ||
throw new CertPathValidatorException( | ||
"incorrect KeyUsage extension bits", | ||
null, null, -1, PKIXReason.INVALID_KEY_USAGE); | ||
} | ||
} | ||
|
||
DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); | ||
if (params == null) { | ||
if (!constraints.permits(primitives, currPubKey)) { | ||
throw new CertPathValidatorException( | ||
"Key parameters missing from public key."); | ||
"Algorithm constraints check failed on " + | ||
currPubKey.getAlgorithm() + " key with size of " + | ||
sun.security.util.KeyUtil.getKeySize(currPubKey) + | ||
"bits", | ||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); | ||
} | ||
} | ||
|
||
try { | ||
BigInteger y = ((DSAPublicKey)currPubKey).getY(); | ||
KeyFactory kf = KeyFactory.getInstance("DSA"); | ||
DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(), | ||
params.getQ(), params.getG()); | ||
currPubKey = kf.generatePublic(ks); | ||
} catch (GeneralSecurityException e) { | ||
throw new CertPathValidatorException("Unable to generate " + | ||
"key with inherited parameters: " + e.getMessage(), e); | ||
if (prevPubKey != null) { | ||
// Inherit key parameters from previous key | ||
if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) { | ||
// Inherit DSA parameters from previous key | ||
if (!(prevPubKey instanceof DSAPublicKey)) { | ||
throw new CertPathValidatorException("Input key is not " + | ||
"of a appropriate type for inheriting parameters"); | ||
} | ||
|
||
DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); | ||
if (params == null) { | ||
throw new CertPathValidatorException( | ||
"Key parameters missing from public key."); | ||
} | ||
|
||
try { | ||
BigInteger y = ((DSAPublicKey)currPubKey).getY(); | ||
KeyFactory kf = KeyFactory.getInstance("DSA"); | ||
DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(), | ||
params.getQ(), params.getG()); | ||
currPubKey = kf.generatePublic(ks); | ||
} catch (GeneralSecurityException e) { | ||
throw new CertPathValidatorException("Unable to generate " + | ||
"key with inherited parameters: " + | ||
e.getMessage(), e); | ||
} | ||
} | ||
} | ||
|
||
|
@@ -360,19 +351,14 @@ public void check(Certificate cert, | |
*/ | ||
void trySetTrustAnchor(TrustAnchor anchor) { | ||
// Don't bother if the check has started or trust anchor has already | ||
// specified. | ||
if (prevPubKey == null) { | ||
if (anchor == null) { | ||
throw new IllegalArgumentException( | ||
"The trust anchor cannot be null"); | ||
} | ||
|
||
// Don't bother to change the trustedPubKey. | ||
// been specified. | ||
if (this.trustedPubKey == null) { | ||
if (anchor.getTrustedCert() != null) { | ||
prevPubKey = anchor.getTrustedCert().getPublicKey(); | ||
this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); | ||
} else { | ||
prevPubKey = anchor.getCAPublicKey(); | ||
this.trustedPubKey = anchor.getCAPublicKey(); | ||
} | ||
this.prevPubKey = this.trustedPubKey; | ||
this.anchor = anchor; | ||
} | ||
} | ||
|
@@ -412,9 +398,9 @@ static void check(PublicKey key, X509CRL crl, String variant, | |
static void check(PublicKey key, AlgorithmId algorithmId, String variant, | ||
TrustAnchor anchor) throws CertPathValidatorException { | ||
|
||
certPathDefaultConstraints.permits(algorithmId.getName(), | ||
algorithmId.getParameters(), | ||
new CertPathConstraintsParameters(key, variant, anchor)); | ||
DisabledAlgorithmConstraints.certPathConstraints().permits( | ||
algorithmId.getName(), algorithmId.getParameters(), | ||
new CertPathConstraintsParameters(key, variant, anchor, null)); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can group fields to final and non-final ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.