Android 4.4系统HTTPS证书校验

Android系统在建立HTTPS三次握手后会进行证书校验,接下来根据android 4.4系统代码来看一下证书校验流程

org.conscrypt.TrustManagerImpl开始介绍

1、证书校验入口函数 

 @Override 
public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        checkTrusted(chain, authType, null, false);
}

2、下一个调用函数

private List<X509Certificate> checkTrusted(X509Certificate[] chain, String authType,
                                               String host, boolean clientAuth)
            throws CertificateException {
        if (chain == null || chain.length == 0 || authType == null || authType.length() == 0) {
            throw new IllegalArgumentException("null or zero-length parameter");
        }
        if (err != null) {
            throw new CertificateException(err);
        }
 
        // get the cleaned up chain and trust anchor
        Set<TrustAnchor> trustAnchor = new HashSet<TrustAnchor>(); // there can only be one!
        X509Certificate[] newChain = cleanupCertChainAndFindTrustAnchors(chain, trustAnchor);
 
        // add the first trust anchor to the chain, which may be an intermediate
        List<X509Certificate> wholeChain = new ArrayList<X509Certificate>();
        wholeChain.addAll(Arrays.asList(newChain));
        // trustAnchor is actually just a single element
        for (TrustAnchor trust : trustAnchor) {
            wholeChain.add(trust.getTrustedCert());
        }
 
        // add all the cached certificates from the cert index, avoiding loops
        // this gives us a full chain from leaf to root, which we use for cert pinning and pass
        // back out to callers when we return.
        X509Certificate last = wholeChain.get(wholeChain.size() - 1);
        while (true) {
            TrustAnchor cachedTrust = trustedCertificateIndex.findByIssuerAndSignature(last);
            // the cachedTrust can be null if there isn't anything in the index or if a user has
            // trusted a non-self-signed cert.
            if (cachedTrust == null) {
                break;
            }
 
            // at this point we have a cached trust anchor, but don't know if its one we got from
            // the server. Extract the cert, compare it to the last element in the chain, and add it
            // if we haven't seen it before.
            X509Certificate next = cachedTrust.getTrustedCert();
            if (next != last) {
                wholeChain.add(next);
                last = next;
            } else {
                // if next == last then we found a self-signed cert and the chain is done
                break;
            }
        }
 
        // build the cert path from the array of certs sans trust anchors
        CertPath certPath = factory.generateCertPath(Arrays.asList(newChain));
 
        if (host != null) {
            boolean chainIsNotPinned = true;
            try {
                chainIsNotPinned = pinManager.chainIsNotPinned(host, wholeChain);
            } catch (PinManagerException e) {
                throw new CertificateException(e);
            }
            if (chainIsNotPinned) {
                throw new CertificateException(new CertPathValidatorException(
                        "Certificate path is not properly pinned.", null, certPath, -1));
            }
        }
 
        if (newChain.length == 0) {
            // chain was entirely trusted, skip the validator
            return wholeChain;
        }
 
        if (trustAnchor.isEmpty()) {
            throw new CertificateException(new CertPathValidatorException(
                    "Trust anchor for certification path not found.", null, certPath, -1));
        }
 
        // There's no point in checking trust anchors here, and it will throw off the MD5 check,
        // so we just hand it the chain without anchors
        ChainStrengthAnalyzer.check(newChain);
 
        try {
            PKIXParameters params = new PKIXParameters(trustAnchor);
            params.setRevocationEnabled(false);
            params.addCertPathChecker(new ExtendedKeyUsagePKIXCertPathChecker(clientAuth,
                                                                              newChain[0]));
            validator.validate(certPath, params);
            // Add intermediate CAs to the index to tolerate sites
            // that assume that the browser will have cached these.
            // The server certificate is skipped by skipping the
            // zeroth element of new chain and note that the root CA
            // will have been removed in
            // cleanupCertChainAndFindTrustAnchors.  http://b/3404902
            for (int i = 1; i < newChain.length; i++) {
                trustedCertificateIndex.index(newChain[i]);
            }
        } catch (InvalidAlgorithmParameterException e) {
            throw new CertificateException(e);
        } catch (CertPathValidatorException e) {
            throw new CertificateException(e);
        }
 
        return wholeChain;
}

这个函数里面主要内容是:

扫描二维码关注公众号,回复: 1830546 查看本文章

1、整理证书链,调用函数是cleanupCertChainAndFindTrustAnchors

private X509Certificate[] cleanupCertChainAndFindTrustAnchors(X509Certificate[] chain,
                                                                  Set<TrustAnchor> trustAnchors) {
        X509Certificate[] original = chain;
 
        // 1. Clean the received certificates chain.
        int currIndex;
        // Start with the first certificate in the chain, assuming it
        // is the leaf certificate (server or client cert).
        for (currIndex = 0; currIndex < chain.length; currIndex++) {
            // Walk the chain to find a "subject" matching
            // the "issuer" of the current certificate. In a properly
            // ordered chain this should be the next cert and be fast.
            // If not, we reorder things to be as the validator will
            // expect.
            boolean foundNext = false;
            for (int nextIndex = currIndex + 1; nextIndex < chain.length; nextIndex++) {
                if (chain[currIndex].getIssuerDN().equals(chain[nextIndex].getSubjectDN())) {
                    foundNext = true;
                    // Exchange certificates so that 0 through currIndex + 1 are in proper order
                    if (nextIndex != currIndex + 1) {
                        // don't mutuate original chain, which may be directly from an SSLSession
                        if (chain == original) {
                            chain = original.clone();
                        }
                        X509Certificate tempCertificate = chain[nextIndex];
                        chain[nextIndex] = chain[currIndex + 1];
                        chain[currIndex + 1] = tempCertificate;
                    }
                    break;
                }
            }
            // If we can't find the next in the chain, just give up
            // and use what we found so far. This drops unrelated
            // certificates that have nothing to do with the cert
            // chain.
            if (!foundNext) {
                break;
            }
        }
 
        // 2. Find the trust anchor in the chain, if any
        int anchorIndex;
        for (anchorIndex = 0; anchorIndex <= currIndex; anchorIndex++) {
            // If the current cert is a TrustAnchor, we can ignore the rest of the chain.
            // This avoids including "bridge" CA certs that added for legacy compatibility.
            TrustAnchor trustAnchor = findTrustAnchorBySubjectAndPublicKey(chain[anchorIndex]);
            if (trustAnchor != null) {
                trustAnchors.add(trustAnchor);
                break;
            }
        }
 
        // 3. If the chain is now shorter, copy to an appropriately sized array.
        int chainLength = anchorIndex;
        X509Certificate[] newChain = ((chainLength == chain.length)
                                      ? chain
                                      : Arrays.copyOf(chain, chainLength));
 
        // 4. If we didn't find a trust anchor earlier, look for one now
        if (trustAnchors.isEmpty()) {
            TrustAnchor trustAnchor = findTrustAnchorByIssuerAndSignature(newChain[anchorIndex-1]);
            if (trustAnchor != null) {
                trustAnchors.add(trustAnchor);
            }
        }
        return newChain;
 }

该函数主要功能是将传进来的证书链的证书按subjectissuer确立父子关系,调整好顺序,删除不相关的证书,然后从证书链第一个证书开始寻找系统中与它subjectpublic key相同的证书作为信任证书,如果找到的话就会返回新的证书链,这个证书链根证书就是第一个找到系统对应证书的那个证书

备注:如果证书链中只有一个证书,那么只会校验该证书的subject和public key是否和系统中的某一个证书一样,并不会像校验证书链那样用public key去校验证书签名,之所以这样,我的理解是因为https是公钥加密私钥解密的非对称加密,所以私钥不一样公钥肯定也不一样,所以即使你把公钥改成和系统证书一样,那你拿到数据后你没有对应的私钥也解不出来,所以只要校验公钥是否一样就足够了。

2、整理好证书链以及获取到系统的一个证书后开始进行校验,校验函数是validator.validate(certPath, params);先来看一下validator这个变量哪来的

public TrustManagerImpl(KeyStore keyStore, CertPinManager manager) {
        CertPathValidator validatorLocal = null;
        CertificateFactory factoryLocal = null;
        KeyStore rootKeyStoreLocal = null;
        TrustedCertificateStore trustedCertificateStoreLocal = null;
        TrustedCertificateIndex trustedCertificateIndexLocal = null;
        X509Certificate[] acceptedIssuersLocal = null;
        Exception errLocal = null;
        try {
            validatorLocal = CertPathValidator.getInstance("PKIX");
            factoryLocal = CertificateFactory.getInstance("X509");
 
            // if we have an AndroidCAStore, we will lazily load CAs
            if ("AndroidCAStore".equals(keyStore.getType())) {
                rootKeyStoreLocal = keyStore;
                trustedCertificateStoreLocal = new TrustedCertificateStore();
                acceptedIssuersLocal = null;
                trustedCertificateIndexLocal = new TrustedCertificateIndex();
            } else {
                rootKeyStoreLocal = null;
                trustedCertificateStoreLocal = null;
                acceptedIssuersLocal = acceptedIssuers(keyStore);
                trustedCertificateIndexLocal
                        = new TrustedCertificateIndex(trustAnchors(acceptedIssuersLocal));
            }
 
        } catch (Exception e) {
            errLocal = e;
        }
 
        if (manager != null) {
            this.pinManager = manager;
        } else {
            try {
                pinManager = new CertPinManager(trustedCertificateStoreLocal);
            } catch (PinManagerException e) {
                throw new SecurityException("Could not initialize CertPinManager", e);
            }
        }
 
        this.rootKeyStore = rootKeyStoreLocal;
        this.trustedCertificateStore = trustedCertificateStoreLocal;
        this.validator = validatorLocal;
        this.factory = factoryLocal;
        this.trustedCertificateIndex = trustedCertificateIndexLocal;
        this.acceptedIssuers = acceptedIssuersLocal;
        this.err = errLocal;
}

可以看到这个变量是通过validatorLocal = CertPathValidator.getInstance("PKIX");创建的,返回的实例是security provider中的一个对象,具体路径是

org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi,校验是调用validate函数,这个函数定义在类java.security.cert.CertPathValidator里:

public final CertPathValidatorResult validate(CertPath certPath,
            CertPathParameters params) throws CertPathValidatorException,
            InvalidAlgorithmParameterException {
        return spiImpl.engineValidate(certPath, params);
}
可以看到它调用了它的实现类里面的engineValidate 方法,这个实现类就是上面说的

PKIXCertPathBuilderSpi,接着我们来看一下这个函数具体内容: 

public CertPathValidatorResult engineValidate(
            CertPath certPath,
            CertPathParameters params)
            throws CertPathValidatorException,
            InvalidAlgorithmParameterException
    {
        if (!(params instanceof PKIXParameters))
        {
            throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName()
                    + " instance.");
        }
 
        ExtendedPKIXParameters paramsPKIX;
        if (params instanceof ExtendedPKIXParameters)
        {
            paramsPKIX = (ExtendedPKIXParameters)params;
        }
        else
        {
            paramsPKIX = ExtendedPKIXParameters.getInstance((PKIXParameters)params);
        }
        if (paramsPKIX.getTrustAnchors() == null)
        {
            throw new InvalidAlgorithmParameterException(
                    "trustAnchors is null, this is not allowed for certification path validation.");
        }
 
        //
        // 6.1.1 - inputs
        //
 
        //
        // (a)
        //
        List certs = certPath.getCertificates();
        int n = certs.size();
 
        if (certs.isEmpty())
        {
            throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
        }
        // BEGIN android-added
        {
            X509Certificate cert = (X509Certificate) certs.get(0);
 
            if (cert != null) {
                BigInteger serial = cert.getSerialNumber();
                if (blacklist.isSerialNumberBlackListed(serial)) {
                    // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
                    String message = "Certificate revocation of serial 0x" + serial.toString(16);
                    System.out.println(message);
                    AnnotatedException e = new AnnotatedException(message);
                    throw new CertPathValidatorException(e.getMessage(), e, certPath, 0);
                }
            }
        }
        // END android-added
 
        //
        // (b)
        //
        // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
 
        //
        // (c)
        //
        Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
 
        //
        // (d)
        //
        TrustAnchor trust;
        try
        {
            trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
                    paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
        }
        catch (AnnotatedException e)
        {
            throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1);
        }
 
        if (trust == null)
        {
            throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
        }
 
        //
        // (e), (f), (g) are part of the paramsPKIX object.
        //
        Iterator certIter;
        int index = 0;
        int i;
        // Certificate for each interation of the validation loop
        // Signature information for each iteration of the validation loop
        //
        // 6.1.2 - setup
        //
 
        //
        // (a)
        //
        List[] policyNodes = new ArrayList[n + 1];
        for (int j = 0; j < policyNodes.length; j++)
        {
            policyNodes[j] = new ArrayList();
        }
 
        Set policySet = new HashSet();
 
        policySet.add(RFC3280CertPathUtilities.ANY_POLICY);
 
        PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(),
                RFC3280CertPathUtilities.ANY_POLICY, false);
 
        policyNodes[0].add(validPolicyTree);
 
        //
        // (b) and (c)
        //
        PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
 
        // (d)
        //
        int explicitPolicy;
        Set acceptablePolicies = new HashSet();
 
        if (paramsPKIX.isExplicitPolicyRequired())
        {
            explicitPolicy = 0;
        }
        else
        {
            explicitPolicy = n + 1;
        }
 
        //
        // (e)
        //
        int inhibitAnyPolicy;
 
        if (paramsPKIX.isAnyPolicyInhibited())
        {
            inhibitAnyPolicy = 0;
        }
        else
        {
            inhibitAnyPolicy = n + 1;
        }
 
        //
        // (f)
        //
        int policyMapping;
 
        if (paramsPKIX.isPolicyMappingInhibited())
        {
            policyMapping = 0;
        }
        else
        {
            policyMapping = n + 1;
        }
 
        //
        // (g), (h), (i), (j)
        //
        PublicKey workingPublicKey;
        X500Principal workingIssuerName;
 
        X509Certificate sign = trust.getTrustedCert();
        try
        {
            if (sign != null)
            {
                workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
                workingPublicKey = sign.getPublicKey();
            }
            else
            {
                workingIssuerName = new X500Principal(trust.getCAName());
                workingPublicKey = trust.getCAPublicKey();
            }
        }
        catch (IllegalArgumentException ex)
        {
            throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
                    -1);
        }
 
        AlgorithmIdentifier workingAlgId = null;
        try
        {
            workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
        }
        catch (CertPathValidatorException e)
        {
            throw new ExtCertPathValidatorException(
                    "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
        }
        DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
        ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
 
        //
        // (k)
        //
        int maxPathLength = n;
 
        //
        // 6.1.3
        //
 
        if (paramsPKIX.getTargetConstraints() != null
                && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0)))
        {
            throw new ExtCertPathValidatorException(
                    "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
        }
 
        //
        // initialize CertPathChecker's
        //
        List pathCheckers = paramsPKIX.getCertPathCheckers();
        certIter = pathCheckers.iterator();
        while (certIter.hasNext())
        {
            ((PKIXCertPathChecker) certIter.next()).init(false);
        }
 
        X509Certificate cert = null;
 
        for (index = certs.size() - 1; index >= 0; index--)
        {
            // BEGIN android-added
            if (blacklist.isPublicKeyBlackListed(workingPublicKey)) {
                // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
                String message = "Certificate revocation of public key " + workingPublicKey;
                System.out.println(message);
                AnnotatedException e = new AnnotatedException(message);
                throw new CertPathValidatorException(e.getMessage(), e, certPath, index);
            }
            // END android-added
            // try
            // {
            //
            // i as defined in the algorithm description
            //
            i = n - index;
 
            //
            // set certificate to be checked in this round
            // sign and workingPublicKey and workingIssuerName are set
            // at the end of the for loop and initialized the
            // first time from the TrustAnchor
            //
            cert = (X509Certificate) certs.get(index);
            boolean verificationAlreadyPerformed = (index == certs.size() - 1);
 
            //
            // 6.1.3
            //
 
            RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
                verificationAlreadyPerformed, workingIssuerName, sign);
 
            RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
 
            validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies,
                    validPolicyTree, policyNodes, inhibitAnyPolicy);
 
            validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree);
 
            RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy);
 
            //
            // 6.1.4
            //
 
            if (i != n)
            {
                if (cert != null && cert.getVersion() == 1)
                {
                    throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
                            certPath, index);
                }
 
                RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
 
                validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree,
                        policyMapping);
 
                RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator);
 
                // (h)
                explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy);
                policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping);
                inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy);
 
                //
                // (i)
                //
                explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy);
                policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping);
 
                // (j)
                inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
 
                // (k)
                RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
 
                // (l)
                maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
 
                // (m)
                maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength);
 
                // (n)
                RFC3280CertPathUtilities.prepareNextCertN(certPath, index);
 
                Set criticalExtensions = cert.getCriticalExtensionOIDs();
                if (criticalExtensions != null)
                {
                    criticalExtensions = new HashSet(criticalExtensions);
 
                    // these extensions are handled by the algorithm
                    criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
                    criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
                    criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
                    criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
                    criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
                    criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
                    criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
                    criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
                    criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
                    criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
                }
                else
                {
                    criticalExtensions = new HashSet();
                }
 
                // (o)
                RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers);
                
                // set signing certificate for next round
                sign = cert;
 
                // (c)
                workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
 
                // (d)
                try
                {
                    workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index);
                }
                catch (CertPathValidatorException e)
                {
                    throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
                }
 
                workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
                // (f)
                workingPublicKeyAlgorithm = workingAlgId.getObjectId();
                // (e)
                workingPublicKeyParameters = workingAlgId.getParameters();
            }
        }
 
        ...

这个函数内容比较多,主要截取前面部分,大概流程是

1、找到我们之前整理证书链时找到的那个对应的系统证书

2、用找到的系统证书的public key校验证书链根证书,方法如下:

 protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
                                                String sigProvider)
        throws GeneralSecurityException
    {
        if (sigProvider == null)
        {
            cert.verify(publicKey);
        }
        else
        {
            cert.verify(publicKey, sigProvider);
        }
}

3、开始校验证书链,其中校验签名的函数是processCertA

protected static void processCertA(
        CertPath certPath,
        ExtendedPKIXParameters paramsPKIX,
        int index,
        PublicKey workingPublicKey,
        boolean verificationAlreadyPerformed,
        X500Principal workingIssuerName,
        X509Certificate sign)
        throws ExtCertPathValidatorException
    {
        List certs = certPath.getCertificates();
        X509Certificate cert = (X509Certificate)certs.get(index);
        //
        // (a) verify
        //
        if (!verificationAlreadyPerformed)
        {
            try
            {
                // (a) (1)
                //
                CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
                    paramsPKIX.getSigProvider());
            }
            catch (GeneralSecurityException e)
            {
                throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
            }
        }
 
        try
        {
            // (a) (2)
            //
            cert.checkValidity(CertPathValidatorUtilities
                .getValidCertDateFromValidityModel(paramsPKIX, certPath, index));
        }
        catch (CertificateExpiredException e)
        {
            throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
        }
        catch (CertificateNotYetValidException e)
        {
            throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
        }
        catch (AnnotatedException e)
        {
            throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
        }
 
        //
        // (a) (3)
        //
        if (paramsPKIX.isRevocationEnabled())
        {
            try
            {
                checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX,
                    certPath, index), sign, workingPublicKey, certs);
            }
            catch (AnnotatedException e)
            {
                Throwable cause = e;
                if (null != e.getCause())
                {
                    cause = e.getCause();
                }
                throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index);
            }
        }
 
        //
        // (a) (4) name chaining
        //
        if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
        {
            throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)
                + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
                certPath, index);
        }
}

这个函数同样是用public key校验签名以及校验证书的有效性

4、按照3中的方法从证书链的根证书的下一个证书开始每次拿上一个证书的public key校验下一个证书,直到证书链最底端的证书,任何一步校验错误都会认为证书不合法

5、除了校验签名以外,还有很多校验,具体可以查看

org.bouncycastle.jce.provider.RFC3280CertPathUtilities这个类




猜你喜欢

转载自blog.csdn.net/u012292247/article/details/78076722