• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.apksig.internal.x509;
18 
19 import com.android.apksig.internal.asn1.Asn1Class;
20 import com.android.apksig.internal.asn1.Asn1Field;
21 import com.android.apksig.internal.asn1.Asn1OpaqueObject;
22 import com.android.apksig.internal.asn1.Asn1Type;
23 import com.android.apksig.internal.pkcs7.AlgorithmIdentifier;
24 import com.android.apksig.internal.pkcs7.IssuerAndSerialNumber;
25 import com.android.apksig.internal.pkcs7.SignerIdentifier;
26 import com.android.apksig.internal.util.ByteBufferUtils;
27 import com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate;
28 import com.android.apksig.internal.util.X509CertificateUtils;
29 
30 import java.math.BigInteger;
31 import java.nio.ByteBuffer;
32 import java.security.cert.CertificateException;
33 import java.security.cert.X509Certificate;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.List;
38 
39 import javax.security.auth.x500.X500Principal;
40 
41 /**
42  * X509 {@code Certificate} as specified in RFC 5280.
43  */
44 @Asn1Class(type = Asn1Type.SEQUENCE)
45 public class Certificate {
46     @Asn1Field(index = 0, type = Asn1Type.SEQUENCE)
47     public TBSCertificate certificate;
48 
49     @Asn1Field(index = 1, type = Asn1Type.SEQUENCE)
50     public AlgorithmIdentifier signatureAlgorithm;
51 
52     @Asn1Field(index = 2, type = Asn1Type.BIT_STRING)
53     public ByteBuffer signature;
54 
findCertificate( Collection<X509Certificate> certs, SignerIdentifier id)55     public static X509Certificate findCertificate(
56             Collection<X509Certificate> certs, SignerIdentifier id) {
57         for (X509Certificate cert : certs) {
58             if (isMatchingCerticicate(cert, id)) {
59                 return cert;
60             }
61         }
62         return null;
63     }
64 
isMatchingCerticicate(X509Certificate cert, SignerIdentifier id)65     private static boolean isMatchingCerticicate(X509Certificate cert, SignerIdentifier id) {
66         if (id.issuerAndSerialNumber == null) {
67             // Android doesn't support any other means of identifying the signing certificate
68             return false;
69         }
70         IssuerAndSerialNumber issuerAndSerialNumber = id.issuerAndSerialNumber;
71         byte[] encodedIssuer =
72                 ByteBufferUtils.toByteArray(issuerAndSerialNumber.issuer.getEncoded());
73         X500Principal idIssuer = new X500Principal(encodedIssuer);
74         BigInteger idSerialNumber = issuerAndSerialNumber.certificateSerialNumber;
75         return idSerialNumber.equals(cert.getSerialNumber())
76                 && idIssuer.equals(cert.getIssuerX500Principal());
77     }
78 
parseCertificates( List<Asn1OpaqueObject> encodedCertificates)79     public static List<X509Certificate> parseCertificates(
80             List<Asn1OpaqueObject> encodedCertificates) throws CertificateException {
81         if (encodedCertificates.isEmpty()) {
82             return Collections.emptyList();
83         }
84 
85         List<X509Certificate> result = new ArrayList<>(encodedCertificates.size());
86         for (int i = 0; i < encodedCertificates.size(); i++) {
87             Asn1OpaqueObject encodedCertificate = encodedCertificates.get(i);
88             X509Certificate certificate;
89             byte[] encodedForm = ByteBufferUtils.toByteArray(encodedCertificate.getEncoded());
90             try {
91                 certificate = X509CertificateUtils.generateCertificate(encodedForm);
92             } catch (CertificateException e) {
93                 throw new CertificateException("Failed to parse certificate #" + (i + 1), e);
94             }
95             // Wrap the cert so that the result's getEncoded returns exactly the original
96             // encoded form. Without this, getEncoded may return a different form from what was
97             // stored in the signature. This is because some X509Certificate(Factory)
98             // implementations re-encode certificates and/or some implementations of
99             // X509Certificate.getEncoded() re-encode certificates.
100             certificate = new GuaranteedEncodedFormX509Certificate(certificate, encodedForm);
101             result.add(certificate);
102         }
103         return result;
104     }
105 }
106