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.apk.v3; 18 19 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsLengthPrefixedElement; 20 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsSequenceOfLengthPrefixedElements; 21 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.getLengthPrefixedSlice; 22 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray; 23 24 import com.android.apksig.apk.ApkFormatException; 25 import com.android.apksig.internal.apk.ApkSigningBlockUtils; 26 import com.android.apksig.internal.apk.SignatureAlgorithm; 27 import com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate; 28 import com.android.apksig.internal.util.X509CertificateUtils; 29 30 import java.io.IOException; 31 import java.nio.BufferUnderflowException; 32 import java.nio.ByteBuffer; 33 import java.nio.ByteOrder; 34 import java.security.InvalidAlgorithmParameterException; 35 import java.security.InvalidKeyException; 36 import java.security.NoSuchAlgorithmException; 37 import java.security.PublicKey; 38 import java.security.Signature; 39 import java.security.SignatureException; 40 import java.security.cert.CertificateEncodingException; 41 import java.security.cert.CertificateException; 42 import java.security.cert.X509Certificate; 43 import java.security.spec.AlgorithmParameterSpec; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.HashSet; 47 import java.util.List; 48 49 /** 50 * APK Signer Lineage. 51 * 52 * <p>The signer lineage contains a history of signing certificates with each ancestor attesting to 53 * the validity of its descendant. Each additional descendant represents a new identity that can be 54 * used to sign an APK, and each generation has accompanying attributes which represent how the 55 * APK would like to view the older signing certificates, specifically how they should be trusted in 56 * certain situations. 57 * 58 * <p> Its primary use is to enable APK Signing Certificate Rotation. The Android platform verifies 59 * the APK Signer Lineage, and if the current signing certificate for the APK is in the Signer 60 * Lineage, and the Lineage contains the certificate the platform associates with the APK, it will 61 * allow upgrades to the new certificate. 62 * 63 * @see <a href="https://source.android.com/security/apksigning/index.html">Application Signing</a> 64 */ 65 public class V3SigningCertificateLineage { 66 67 private final static int FIRST_VERSION = 1; 68 private final static int CURRENT_VERSION = FIRST_VERSION; 69 70 /** 71 * Deserializes the binary representation of an {@link V3SigningCertificateLineage}. Also 72 * verifies that the structure is well-formed, e.g. that the signature for each node is from its 73 * parent. 74 */ readSigningCertificateLineage(ByteBuffer inputBytes)75 public static List<SigningCertificateNode> readSigningCertificateLineage(ByteBuffer inputBytes) 76 throws IOException { 77 List<SigningCertificateNode> result = new ArrayList<>(); 78 int nodeCount = 0; 79 if (inputBytes == null || !inputBytes.hasRemaining()) { 80 return null; 81 } 82 83 ApkSigningBlockUtils.checkByteOrderLittleEndian(inputBytes); 84 85 // FORMAT (little endian): 86 // * uint32: version code 87 // * sequence of length-prefixed (uint32): nodes 88 // * length-prefixed bytes: signed data 89 // * length-prefixed bytes: certificate 90 // * uint32: signature algorithm id 91 // * uint32: flags 92 // * uint32: signature algorithm id (used by to sign next cert in lineage) 93 // * length-prefixed bytes: signature over above signed data 94 95 X509Certificate lastCert = null; 96 int lastSigAlgorithmId = 0; 97 98 try { 99 int version = inputBytes.getInt(); 100 if (version != CURRENT_VERSION) { 101 // we only have one version to worry about right now, so just check it 102 throw new IllegalArgumentException("Encoded SigningCertificateLineage has a version" 103 + " different than any of which we are aware"); 104 } 105 HashSet<X509Certificate> certHistorySet = new HashSet<>(); 106 while (inputBytes.hasRemaining()) { 107 nodeCount++; 108 ByteBuffer nodeBytes = getLengthPrefixedSlice(inputBytes); 109 ByteBuffer signedData = getLengthPrefixedSlice(nodeBytes); 110 int flags = nodeBytes.getInt(); 111 int sigAlgorithmId = nodeBytes.getInt(); 112 SignatureAlgorithm sigAlgorithm = SignatureAlgorithm.findById(lastSigAlgorithmId); 113 byte[] signature = readLengthPrefixedByteArray(nodeBytes); 114 115 if (lastCert != null) { 116 // Use previous level cert to verify current level 117 String jcaSignatureAlgorithm = 118 sigAlgorithm.getJcaSignatureAlgorithmAndParams().getFirst(); 119 AlgorithmParameterSpec jcaSignatureAlgorithmParams = 120 sigAlgorithm.getJcaSignatureAlgorithmAndParams().getSecond(); 121 PublicKey publicKey = lastCert.getPublicKey(); 122 Signature sig = Signature.getInstance(jcaSignatureAlgorithm); 123 sig.initVerify(publicKey); 124 if (jcaSignatureAlgorithmParams != null) { 125 sig.setParameter(jcaSignatureAlgorithmParams); 126 } 127 sig.update(signedData); 128 if (!sig.verify(signature)) { 129 throw new SecurityException("Unable to verify signature of certificate #" 130 + nodeCount + " using " + jcaSignatureAlgorithm + " when verifying" 131 + " V3SigningCertificateLineage object"); 132 } 133 } 134 135 signedData.rewind(); 136 byte[] encodedCert = readLengthPrefixedByteArray(signedData); 137 int signedSigAlgorithm = signedData.getInt(); 138 if (lastCert != null && lastSigAlgorithmId != signedSigAlgorithm) { 139 throw new SecurityException("Signing algorithm ID mismatch for certificate #" 140 + nodeBytes + " when verifying V3SigningCertificateLineage object"); 141 } 142 lastCert = X509CertificateUtils.generateCertificate(encodedCert); 143 lastCert = new GuaranteedEncodedFormX509Certificate(lastCert, encodedCert); 144 if (certHistorySet.contains(lastCert)) { 145 throw new SecurityException("Encountered duplicate entries in " 146 + "SigningCertificateLineage at certificate #" + nodeCount + ". All " 147 + "signing certificates should be unique"); 148 } 149 certHistorySet.add(lastCert); 150 lastSigAlgorithmId = sigAlgorithmId; 151 result.add(new SigningCertificateNode( 152 lastCert, SignatureAlgorithm.findById(signedSigAlgorithm), 153 SignatureAlgorithm.findById(sigAlgorithmId), signature, flags)); 154 } 155 } catch(ApkFormatException | BufferUnderflowException e){ 156 throw new IOException("Failed to parse V3SigningCertificateLineage object", e); 157 } catch(NoSuchAlgorithmException | InvalidKeyException 158 | InvalidAlgorithmParameterException | SignatureException e){ 159 throw new SecurityException( 160 "Failed to verify signature over signed data for certificate #" + nodeCount 161 + " when parsing V3SigningCertificateLineage object", e); 162 } catch(CertificateException e){ 163 throw new SecurityException("Failed to decode certificate #" + nodeCount 164 + " when parsing V3SigningCertificateLineage object", e); 165 } 166 return result; 167 } 168 169 /** 170 * encode the in-memory representation of this {@code V3SigningCertificateLineage} 171 */ encodeSigningCertificateLineage( List<SigningCertificateNode> signingCertificateLineage)172 public static byte[] encodeSigningCertificateLineage( 173 List<SigningCertificateNode> signingCertificateLineage) { 174 // FORMAT (little endian): 175 // * version code 176 // * sequence of length-prefixed (uint32): nodes 177 // * length-prefixed bytes: signed data 178 // * length-prefixed bytes: certificate 179 // * uint32: signature algorithm id 180 // * uint32: flags 181 // * uint32: signature algorithm id (used by to sign next cert in lineage) 182 183 List<byte[]> nodes = new ArrayList<>(); 184 for (SigningCertificateNode node : signingCertificateLineage) { 185 nodes.add(encodeSigningCertificateNode(node)); 186 } 187 byte [] encodedSigningCertificateLineage = encodeAsSequenceOfLengthPrefixedElements(nodes); 188 189 // add the version code (uint32) on top of the encoded nodes 190 int payloadSize = 4 + encodedSigningCertificateLineage.length; 191 ByteBuffer encodedWithVersion = ByteBuffer.allocate(payloadSize); 192 encodedWithVersion.order(ByteOrder.LITTLE_ENDIAN); 193 encodedWithVersion.putInt(CURRENT_VERSION); 194 encodedWithVersion.put(encodedSigningCertificateLineage); 195 return encodedWithVersion.array(); 196 } 197 encodeSigningCertificateNode(SigningCertificateNode node)198 public static byte[] encodeSigningCertificateNode(SigningCertificateNode node) { 199 // FORMAT (little endian): 200 // * length-prefixed bytes: signed data 201 // * length-prefixed bytes: certificate 202 // * uint32: signature algorithm id 203 // * uint32: flags 204 // * uint32: signature algorithm id (used by to sign next cert in lineage) 205 // * length-prefixed bytes: signature over signed data 206 int parentSigAlgorithmId = 0; 207 if (node.parentSigAlgorithm != null) { 208 parentSigAlgorithmId = node.parentSigAlgorithm.getId(); 209 } 210 int sigAlgorithmId = 0; 211 if (node.sigAlgorithm != null) { 212 sigAlgorithmId = node.sigAlgorithm.getId(); 213 } 214 byte[] prefixedSignedData = encodeSignedData(node.signingCert, parentSigAlgorithmId); 215 byte[] prefixedSignature = encodeAsLengthPrefixedElement(node.signature); 216 int payloadSize = prefixedSignedData.length + 4 + 4 + prefixedSignature.length; 217 ByteBuffer result = ByteBuffer.allocate(payloadSize); 218 result.order(ByteOrder.LITTLE_ENDIAN); 219 result.put(prefixedSignedData); 220 result.putInt(node.flags); 221 result.putInt(sigAlgorithmId); 222 result.put(prefixedSignature); 223 return result.array(); 224 } 225 encodeSignedData(X509Certificate certificate, int flags)226 public static byte[] encodeSignedData(X509Certificate certificate, int flags) { 227 try { 228 byte[] prefixedCertificate = encodeAsLengthPrefixedElement(certificate.getEncoded()); 229 int payloadSize = 4 + prefixedCertificate.length; 230 ByteBuffer result = ByteBuffer.allocate(payloadSize); 231 result.order(ByteOrder.LITTLE_ENDIAN); 232 result.put(prefixedCertificate); 233 result.putInt(flags); 234 return encodeAsLengthPrefixedElement(result.array()); 235 } catch (CertificateEncodingException e) { 236 throw new RuntimeException( 237 "Failed to encode V3SigningCertificateLineage certificate", e); 238 } 239 } 240 241 /** 242 * Represents one signing certificate in the {@link V3SigningCertificateLineage}, which 243 * generally means it is/was used at some point to sign the same APK of the others in the 244 * lineage. 245 */ 246 public static class SigningCertificateNode { 247 SigningCertificateNode( X509Certificate signingCert, SignatureAlgorithm parentSigAlgorithm, SignatureAlgorithm sigAlgorithm, byte[] signature, int flags)248 public SigningCertificateNode( 249 X509Certificate signingCert, 250 SignatureAlgorithm parentSigAlgorithm, 251 SignatureAlgorithm sigAlgorithm, 252 byte[] signature, 253 int flags) { 254 this.signingCert = signingCert; 255 this.parentSigAlgorithm = parentSigAlgorithm; 256 this.sigAlgorithm = sigAlgorithm; 257 this.signature = signature; 258 this.flags = flags; 259 } 260 261 @Override equals(Object o)262 public boolean equals(Object o) { 263 if (this == o) return true; 264 if (!(o instanceof SigningCertificateNode)) return false; 265 266 SigningCertificateNode that = (SigningCertificateNode) o; 267 if (!signingCert.equals(that.signingCert)) return false; 268 if (parentSigAlgorithm != that.parentSigAlgorithm) return false; 269 if (sigAlgorithm != that.sigAlgorithm) return false; 270 if (!Arrays.equals(signature, that.signature)) return false; 271 if (flags != that.flags) return false; 272 273 // we made it 274 return true; 275 } 276 277 /** 278 * the signing cert for this node. This is part of the data signed by the parent node. 279 */ 280 public final X509Certificate signingCert; 281 282 /** 283 * the algorithm used by the this node's parent to bless this data. Its ID value is part of 284 * the data signed by the parent node. {@code null} for first node. 285 */ 286 public final SignatureAlgorithm parentSigAlgorithm; 287 288 /** 289 * the algorithm used by the this nodeto bless the next node's data. Its ID value is part 290 * of the signed data of the next node. {@code null} for the last node. 291 */ 292 public SignatureAlgorithm sigAlgorithm; 293 294 /** 295 * signature over the signed data (above). The signature is from this node's parent 296 * signing certificate, which should correspond to the signing certificate used to sign an 297 * APK before rotating to this one, and is formed using {@code signatureAlgorithm}. 298 */ 299 public final byte[] signature; 300 301 /** 302 * the flags detailing how the platform should treat this signing cert 303 */ 304 public int flags; 305 } 306 } 307