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