|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider.certpath; |
|
|
|
import java.security.AlgorithmConstraints; |
|
import java.security.CryptoPrimitive; |
|
import java.util.Collection; |
|
import java.util.Collections; |
|
import java.util.Date; |
|
import java.util.Set; |
|
import java.util.EnumSet; |
|
import java.math.BigInteger; |
|
import java.security.PublicKey; |
|
import java.security.KeyFactory; |
|
import java.security.AlgorithmParameters; |
|
import java.security.GeneralSecurityException; |
|
import java.security.cert.Certificate; |
|
import java.security.cert.X509CRL; |
|
import java.security.cert.X509Certificate; |
|
import java.security.cert.PKIXCertPathChecker; |
|
import java.security.cert.TrustAnchor; |
|
import java.security.cert.CRLException; |
|
import java.security.cert.CertificateException; |
|
import java.security.cert.CertPathValidatorException; |
|
import java.security.cert.CertPathValidatorException.BasicReason; |
|
import java.security.cert.PKIXReason; |
|
import java.security.interfaces.DSAParams; |
|
import java.security.interfaces.DSAPublicKey; |
|
import java.security.spec.DSAPublicKeySpec; |
|
|
|
import sun.security.util.ConstraintsParameters; |
|
import sun.security.util.Debug; |
|
import sun.security.util.DisabledAlgorithmConstraints; |
|
import sun.security.validator.Validator; |
|
import sun.security.x509.AlgorithmId; |
|
import sun.security.x509.X509CertImpl; |
|
import sun.security.x509.X509CRLImpl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 TrustAnchor anchor; |
|
|
|
private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET = |
|
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); |
|
|
|
private static final Set<CryptoPrimitive> KU_PRIMITIVE_SET = |
|
Collections.unmodifiableSet(EnumSet.of( |
|
CryptoPrimitive.SIGNATURE, |
|
CryptoPrimitive.KEY_ENCAPSULATION, |
|
CryptoPrimitive.PUBLIC_KEY_ENCRYPTION, |
|
CryptoPrimitive.KEY_AGREEMENT)); |
|
|
|
private static final DisabledAlgorithmConstraints |
|
certPathDefaultConstraints = |
|
DisabledAlgorithmConstraints.certPathConstraints(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AlgorithmChecker(TrustAnchor anchor, String variant) { |
|
this(anchor, certPathDefaultConstraints, null, variant); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AlgorithmChecker(AlgorithmConstraints constraints, String variant) { |
|
this(null, constraints, null, variant); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AlgorithmChecker(TrustAnchor anchor, |
|
AlgorithmConstraints constraints, Date date, String variant) { |
|
|
|
if (anchor != null) { |
|
if (anchor.getTrustedCert() != null) { |
|
this.trustedPubKey = anchor.getTrustedCert().getPublicKey(); |
|
} else { |
|
this.trustedPubKey = anchor.getCAPublicKey(); |
|
} |
|
this.anchor = anchor; |
|
} else { |
|
this.trustedPubKey = null; |
|
} |
|
|
|
this.prevPubKey = this.trustedPubKey; |
|
this.constraints = (constraints == null ? certPathDefaultConstraints : |
|
constraints); |
|
this.date = date; |
|
this.variant = (variant == null ? Validator.VAR_GENERIC : variant); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AlgorithmChecker(TrustAnchor anchor, Date pkixdate, String variant) { |
|
this(anchor, certPathDefaultConstraints, pkixdate, variant); |
|
} |
|
|
|
@Override |
|
public void init(boolean forward) throws CertPathValidatorException { |
|
|
|
if (!forward) { |
|
if (trustedPubKey != null) { |
|
prevPubKey = trustedPubKey; |
|
} else { |
|
prevPubKey = null; |
|
} |
|
} else { |
|
throw new |
|
CertPathValidatorException("forward checking not supported"); |
|
} |
|
} |
|
|
|
@Override |
|
public boolean isForwardCheckingSupported() { |
|
// Note that as this class does not support forward mode, the method |
|
|
|
return false; |
|
} |
|
|
|
@Override |
|
public Set<String> getSupportedExtensions() { |
|
return null; |
|
} |
|
|
|
@Override |
|
public void check(Certificate cert, |
|
Collection<String> unresolvedCritExts) |
|
throws CertPathValidatorException { |
|
|
|
if (!(cert instanceof X509Certificate) || constraints == null) { |
|
|
|
return; |
|
} |
|
|
|
|
|
boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage(); |
|
if (keyUsage != null && keyUsage.length < 9) { |
|
throw new CertPathValidatorException( |
|
"incorrect KeyUsage extension", |
|
null, null, -1, PKIXReason.INVALID_KEY_USAGE); |
|
} |
|
|
|
X509CertImpl x509Cert; |
|
AlgorithmId algorithmId; |
|
try { |
|
x509Cert = X509CertImpl.toImpl((X509Certificate)cert); |
|
algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); |
|
} catch (CertificateException ce) { |
|
throw new CertPathValidatorException(ce); |
|
} |
|
|
|
AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); |
|
PublicKey currPubKey = cert.getPublicKey(); |
|
String currSigAlg = x509Cert.getSigAlgName(); |
|
|
|
|
|
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); |
|
} |
|
|
|
|
|
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 |
|
|
|
primitives.add(CryptoPrimitive.SIGNATURE); |
|
} |
|
|
|
if (keyUsage[2]) { |
|
primitives.add(CryptoPrimitive.KEY_ENCAPSULATION); |
|
} |
|
|
|
if (keyUsage[3]) { |
|
primitives.add(CryptoPrimitive.PUBLIC_KEY_ENCRYPTION); |
|
} |
|
|
|
if (keyUsage[4]) { |
|
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); |
|
} |
|
} |
|
|
|
ConstraintsParameters cp = |
|
new CertPathConstraintsParameters(x509Cert, variant, |
|
anchor, date); |
|
|
|
|
|
if (constraints instanceof DisabledAlgorithmConstraints) { |
|
((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, |
|
currSigAlgParams, cp); |
|
// DisabledAlgorithmsConstraints does not check primitives, so key |
|
// additional key check. |
|
|
|
} else { |
|
|
|
certPathDefaultConstraints.permits(currSigAlg, currSigAlgParams, cp); |
|
|
|
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", |
|
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); |
|
} |
|
} |
|
|
|
|
|
if (prevPubKey == null) { |
|
prevPubKey = currPubKey; |
|
return; |
|
} |
|
|
|
|
|
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 (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) { |
|
|
|
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); |
|
} |
|
} |
|
|
|
|
|
prevPubKey = currPubKey; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void trySetTrustAnchor(TrustAnchor anchor) { |
|
// Don't bother if the check has started or trust anchor has already |
|
|
|
if (prevPubKey == null) { |
|
if (anchor == null) { |
|
throw new IllegalArgumentException( |
|
"The trust anchor cannot be null"); |
|
} |
|
|
|
|
|
if (anchor.getTrustedCert() != null) { |
|
prevPubKey = anchor.getTrustedCert().getPublicKey(); |
|
} else { |
|
prevPubKey = anchor.getCAPublicKey(); |
|
} |
|
this.anchor = anchor; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void check(PublicKey key, X509CRL crl, String variant, |
|
TrustAnchor anchor) throws CertPathValidatorException { |
|
|
|
X509CRLImpl x509CRLImpl = null; |
|
try { |
|
x509CRLImpl = X509CRLImpl.toImpl(crl); |
|
} catch (CRLException ce) { |
|
throw new CertPathValidatorException(ce); |
|
} |
|
|
|
AlgorithmId algorithmId = x509CRLImpl.getSigAlgId(); |
|
check(key, algorithmId, variant, anchor); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void check(PublicKey key, AlgorithmId algorithmId, String variant, |
|
TrustAnchor anchor) throws CertPathValidatorException { |
|
|
|
certPathDefaultConstraints.permits(algorithmId.getName(), |
|
algorithmId.getParameters(), |
|
new CertPathConstraintsParameters(key, variant, anchor)); |
|
} |
|
} |
|
|