Path: blob/master/src/java.base/share/classes/sun/security/provider/certpath/BasicChecker.java
41161 views
/*1* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider.certpath;2627import java.math.BigInteger;28import java.util.Collection;29import java.util.Date;30import java.util.Set;31import java.security.GeneralSecurityException;32import java.security.KeyFactory;33import java.security.PublicKey;34import java.security.SignatureException;35import java.security.cert.Certificate;36import java.security.cert.CertificateExpiredException;37import java.security.cert.CertificateNotYetValidException;38import java.security.cert.CertPathValidatorException;39import java.security.cert.CertPathValidatorException.BasicReason;40import java.security.cert.X509Certificate;41import java.security.cert.PKIXCertPathChecker;42import java.security.cert.PKIXReason;43import java.security.cert.TrustAnchor;44import java.security.interfaces.DSAParams;45import java.security.interfaces.DSAPublicKey;46import java.security.spec.DSAPublicKeySpec;47import javax.security.auth.x500.X500Principal;48import sun.security.x509.X500Name;49import sun.security.util.Debug;5051/**52* BasicChecker is a PKIXCertPathChecker that checks the basic information53* on a PKIX certificate, namely the signature, validity, and subject/issuer54* name chaining.55*56* @since 1.457* @author Yassir Elley58*/59class BasicChecker extends PKIXCertPathChecker {6061private static final Debug debug = Debug.getInstance("certpath");62private final PublicKey trustedPubKey;63private final X500Principal caName;64private final Date date;65private final String sigProvider;66private final boolean sigOnly;67private X500Principal prevSubject;68private PublicKey prevPubKey;6970/**71* Constructor that initializes the input parameters.72*73* @param anchor the anchor selected to validate the target certificate74* @param date the time for which the validity of the certificate75* should be determined76* @param sigProvider the name of the signature provider77* @param sigOnly true if only signature checking is to be done;78* if false, all checks are done79*/80BasicChecker(TrustAnchor anchor, Date date, String sigProvider,81boolean sigOnly) {82if (anchor.getTrustedCert() != null) {83this.trustedPubKey = anchor.getTrustedCert().getPublicKey();84this.caName = anchor.getTrustedCert().getSubjectX500Principal();85} else {86this.trustedPubKey = anchor.getCAPublicKey();87this.caName = anchor.getCA();88}89this.date = date;90this.sigProvider = sigProvider;91this.sigOnly = sigOnly;92this.prevPubKey = trustedPubKey;93}9495/**96* Initializes the internal state of the checker from parameters97* specified in the constructor.98*/99@Override100public void init(boolean forward) throws CertPathValidatorException {101if (!forward) {102prevPubKey = trustedPubKey;103if (PKIX.isDSAPublicKeyWithoutParams(prevPubKey)) {104// If TrustAnchor is a DSA public key and it has no params, it105// cannot be used to verify the signature of the first cert,106// so throw exception107throw new CertPathValidatorException("Key parameters missing");108}109prevSubject = caName;110} else {111throw new112CertPathValidatorException("forward checking not supported");113}114}115116@Override117public boolean isForwardCheckingSupported() {118return false;119}120121@Override122public Set<String> getSupportedExtensions() {123return null;124}125126/**127* Performs the signature, validity, and subject/issuer name chaining128* checks on the certificate using its internal state. This method does129* not remove any critical extensions from the Collection.130*131* @param cert the Certificate132* @param unresolvedCritExts a Collection of the unresolved critical133* extensions134* @throws CertPathValidatorException if certificate does not verify135*/136@Override137public void check(Certificate cert, Collection<String> unresolvedCritExts)138throws CertPathValidatorException139{140X509Certificate currCert = (X509Certificate)cert;141142if (!sigOnly) {143verifyValidity(currCert);144verifyNameChaining(currCert);145}146verifySignature(currCert);147148updateState(currCert);149}150151/**152* Verifies the signature on the certificate using the previous public key.153*154* @param cert the X509Certificate155* @throws CertPathValidatorException if certificate does not verify156*/157private void verifySignature(X509Certificate cert)158throws CertPathValidatorException159{160String msg = "signature";161if (debug != null)162debug.println("---checking " + msg + "...");163164try {165cert.verify(prevPubKey, sigProvider);166} catch (SignatureException e) {167throw new CertPathValidatorException168(msg + " check failed", e, null, -1,169BasicReason.INVALID_SIGNATURE);170} catch (GeneralSecurityException e) {171throw new CertPathValidatorException(msg + " check failed", e);172}173174if (debug != null)175debug.println(msg + " verified.");176}177178/**179* Internal method to verify the validity on a certificate180*/181private void verifyValidity(X509Certificate cert)182throws CertPathValidatorException183{184String msg = "validity";185if (debug != null)186debug.println("---checking " + msg + ":" + date.toString() + "...");187188try {189cert.checkValidity(date);190} catch (CertificateExpiredException e) {191throw new CertPathValidatorException192(msg + " check failed", e, null, -1, BasicReason.EXPIRED);193} catch (CertificateNotYetValidException e) {194throw new CertPathValidatorException195(msg + " check failed", e, null, -1, BasicReason.NOT_YET_VALID);196}197198if (debug != null)199debug.println(msg + " verified.");200}201202/**203* Internal method to check that cert has a valid DN to be next in a chain204*/205private void verifyNameChaining(X509Certificate cert)206throws CertPathValidatorException207{208if (prevSubject != null) {209210String msg = "subject/issuer name chaining";211if (debug != null)212debug.println("---checking " + msg + "...");213214X500Principal currIssuer = cert.getIssuerX500Principal();215216// reject null or empty issuer DNs217if (X500Name.asX500Name(currIssuer).isEmpty()) {218throw new CertPathValidatorException219(msg + " check failed: " +220"empty/null issuer DN in certificate is invalid", null,221null, -1, PKIXReason.NAME_CHAINING);222}223224if (!(currIssuer.equals(prevSubject))) {225throw new CertPathValidatorException226(msg + " check failed", null, null, -1,227PKIXReason.NAME_CHAINING);228}229230if (debug != null)231debug.println(msg + " verified.");232}233}234235/**236* Internal method to manage state information at each iteration237*/238private void updateState(X509Certificate currCert)239throws CertPathValidatorException240{241PublicKey cKey = currCert.getPublicKey();242if (debug != null) {243debug.println("BasicChecker.updateState issuer: " +244currCert.getIssuerX500Principal().toString() + "; subject: " +245currCert.getSubjectX500Principal() + "; serial#: " +246currCert.getSerialNumber().toString());247}248if (PKIX.isDSAPublicKeyWithoutParams(cKey)) {249// cKey needs to inherit DSA parameters from prev key250cKey = makeInheritedParamsKey(cKey, prevPubKey);251if (debug != null) debug.println("BasicChecker.updateState Made " +252"key with inherited params");253}254prevPubKey = cKey;255prevSubject = currCert.getSubjectX500Principal();256}257258/**259* Internal method to create a new key with inherited key parameters.260*261* @param keyValueKey key from which to obtain key value262* @param keyParamsKey key from which to obtain key parameters263* @return new public key having value and parameters264* @throws CertPathValidatorException if keys are not appropriate types265* for this operation266*/267static PublicKey makeInheritedParamsKey(PublicKey keyValueKey,268PublicKey keyParamsKey) throws CertPathValidatorException269{270if (!(keyValueKey instanceof DSAPublicKey) ||271!(keyParamsKey instanceof DSAPublicKey))272throw new CertPathValidatorException("Input key is not " +273"appropriate type for " +274"inheriting parameters");275DSAParams params = ((DSAPublicKey)keyParamsKey).getParams();276if (params == null)277throw new CertPathValidatorException("Key parameters missing");278try {279BigInteger y = ((DSAPublicKey)keyValueKey).getY();280KeyFactory kf = KeyFactory.getInstance("DSA");281DSAPublicKeySpec ks = new DSAPublicKeySpec(y,282params.getP(),283params.getQ(),284params.getG());285return kf.generatePublic(ks);286} catch (GeneralSecurityException e) {287throw new CertPathValidatorException("Unable to generate key with" +288" inherited parameters: " +289e.getMessage(), e);290}291}292293/**294* return the public key associated with the last certificate processed295*296* @return PublicKey the last public key processed297*/298PublicKey getPublicKey() {299return prevPubKey;300}301}302303304