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; 18 19 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.getLengthPrefixedSlice; 20 21 import com.android.apksig.apk.ApkFormatException; 22 import com.android.apksig.apk.ApkUtils; 23 import com.android.apksig.internal.apk.ApkSigningBlockUtils; 24 import com.android.apksig.internal.apk.SignatureAlgorithm; 25 import com.android.apksig.internal.apk.SignatureInfo; 26 import com.android.apksig.internal.apk.v3.V3SchemeConstants; 27 import com.android.apksig.internal.apk.v3.V3SchemeSigner; 28 import com.android.apksig.internal.apk.v3.V3SigningCertificateLineage; 29 import com.android.apksig.internal.apk.v3.V3SigningCertificateLineage.SigningCertificateNode; 30 import com.android.apksig.internal.util.AndroidSdkVersion; 31 import com.android.apksig.internal.util.ByteBufferUtils; 32 import com.android.apksig.internal.util.Pair; 33 import com.android.apksig.internal.util.RandomAccessFileDataSink; 34 import com.android.apksig.util.DataSink; 35 import com.android.apksig.util.DataSource; 36 import com.android.apksig.util.DataSources; 37 import com.android.apksig.zip.ZipFormatException; 38 39 import java.io.File; 40 import java.io.IOException; 41 import java.io.RandomAccessFile; 42 import java.nio.ByteBuffer; 43 import java.nio.ByteOrder; 44 import java.security.InvalidKeyException; 45 import java.security.NoSuchAlgorithmException; 46 import java.security.PrivateKey; 47 import java.security.PublicKey; 48 import java.security.SignatureException; 49 import java.security.cert.CertificateEncodingException; 50 import java.security.cert.X509Certificate; 51 import java.util.ArrayList; 52 import java.util.Arrays; 53 import java.util.Collections; 54 import java.util.List; 55 56 /** 57 * APK Signer Lineage. 58 * 59 * <p>The signer lineage contains a history of signing certificates with each ancestor attesting to 60 * the validity of its descendant. Each additional descendant represents a new identity that can be 61 * used to sign an APK, and each generation has accompanying attributes which represent how the 62 * APK would like to view the older signing certificates, specifically how they should be trusted in 63 * certain situations. 64 * 65 * <p> Its primary use is to enable APK Signing Certificate Rotation. The Android platform verifies 66 * the APK Signer Lineage, and if the current signing certificate for the APK is in the Signer 67 * Lineage, and the Lineage contains the certificate the platform associates with the APK, it will 68 * allow upgrades to the new certificate. 69 * 70 * @see <a href="https://source.android.com/security/apksigning/index.html">Application Signing</a> 71 */ 72 public class SigningCertificateLineage { 73 74 public final static int MAGIC = 0x3eff39d1; 75 76 private final static int FIRST_VERSION = 1; 77 78 private static final int CURRENT_VERSION = FIRST_VERSION; 79 80 /** accept data from already installed pkg with this cert */ 81 private static final int PAST_CERT_INSTALLED_DATA = 1; 82 83 /** accept sharedUserId with pkg with this cert */ 84 private static final int PAST_CERT_SHARED_USER_ID = 2; 85 86 /** grant SIGNATURE permissions to pkgs with this cert */ 87 private static final int PAST_CERT_PERMISSION = 4; 88 89 /** 90 * Enable updates back to this certificate. WARNING: this effectively removes any benefit of 91 * signing certificate changes, since a compromised key could retake control of an app even 92 * after change, and should only be used if there is a problem encountered when trying to ditch 93 * an older cert. 94 */ 95 private static final int PAST_CERT_ROLLBACK = 8; 96 97 /** 98 * Preserve authenticator module-based access in AccountManager gated by signing certificate. 99 */ 100 private static final int PAST_CERT_AUTH = 16; 101 102 private final int mMinSdkVersion; 103 104 /** 105 * The signing lineage is just a list of nodes, with the first being the original signing 106 * certificate and the most recent being the one with which the APK is to actually be signed. 107 */ 108 private final List<SigningCertificateNode> mSigningLineage; 109 SigningCertificateLineage(int minSdkVersion, List<SigningCertificateNode> list)110 private SigningCertificateLineage(int minSdkVersion, List<SigningCertificateNode> list) { 111 mMinSdkVersion = minSdkVersion; 112 mSigningLineage = list; 113 } 114 115 /** 116 * Creates a {@code SigningCertificateLineage} with a single signer in the lineage. 117 */ createSigningLineage(int minSdkVersion, SignerConfig signer, SignerCapabilities capabilities)118 private static SigningCertificateLineage createSigningLineage(int minSdkVersion, 119 SignerConfig signer, SignerCapabilities capabilities) { 120 SigningCertificateLineage signingCertificateLineage = new SigningCertificateLineage( 121 minSdkVersion, new ArrayList<>()); 122 return signingCertificateLineage.spawnFirstDescendant(signer, capabilities); 123 } 124 createSigningLineage( int minSdkVersion, SignerConfig parent, SignerCapabilities parentCapabilities, SignerConfig child, SignerCapabilities childCapabilities)125 private static SigningCertificateLineage createSigningLineage( 126 int minSdkVersion, SignerConfig parent, SignerCapabilities parentCapabilities, 127 SignerConfig child, SignerCapabilities childCapabilities) 128 throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException, 129 SignatureException { 130 SigningCertificateLineage signingCertificateLineage = 131 new SigningCertificateLineage(minSdkVersion, new ArrayList<>()); 132 signingCertificateLineage = 133 signingCertificateLineage.spawnFirstDescendant(parent, parentCapabilities); 134 return signingCertificateLineage.spawnDescendant(parent, child, childCapabilities); 135 } 136 readFromBytes(byte[] lineageBytes)137 public static SigningCertificateLineage readFromBytes(byte[] lineageBytes) 138 throws IOException { 139 return readFromDataSource(DataSources.asDataSource(ByteBuffer.wrap(lineageBytes))); 140 } 141 readFromFile(File file)142 public static SigningCertificateLineage readFromFile(File file) 143 throws IOException { 144 if (file == null) { 145 throw new NullPointerException("file == null"); 146 } 147 RandomAccessFile inputFile = new RandomAccessFile(file, "r"); 148 return readFromDataSource(DataSources.asDataSource(inputFile)); 149 } 150 readFromDataSource(DataSource dataSource)151 public static SigningCertificateLineage readFromDataSource(DataSource dataSource) 152 throws IOException { 153 if (dataSource == null) { 154 throw new NullPointerException("dataSource == null"); 155 } 156 ByteBuffer inBuff = dataSource.getByteBuffer(0, (int) dataSource.size()); 157 inBuff.order(ByteOrder.LITTLE_ENDIAN); 158 return read(inBuff); 159 } 160 161 /** 162 * Extracts a Signing Certificate Lineage from a v3 signer proof-of-rotation attribute. 163 * 164 * <note> 165 * this may not give a complete representation of an APK's signing certificate history, 166 * since the APK may have multiple signers corresponding to different platform versions. 167 * Use <code> readFromApkFile</code> to handle this case. 168 * </note> 169 * @param attrValue 170 */ readFromV3AttributeValue(byte[] attrValue)171 public static SigningCertificateLineage readFromV3AttributeValue(byte[] attrValue) 172 throws IOException { 173 List<SigningCertificateNode> parsedLineage = 174 V3SigningCertificateLineage.readSigningCertificateLineage(ByteBuffer.wrap( 175 attrValue).order(ByteOrder.LITTLE_ENDIAN)); 176 int minSdkVersion = calculateMinSdkVersion(parsedLineage); 177 return new SigningCertificateLineage(minSdkVersion, parsedLineage); 178 } 179 180 /** 181 * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3 182 * signature block of the provided APK File. 183 * 184 * @throws IllegalArgumentException if the provided APK does not contain a V3 signature block, 185 * or if the V3 signature block does not contain a valid lineage. 186 */ readFromApkFile(File apkFile)187 public static SigningCertificateLineage readFromApkFile(File apkFile) 188 throws IOException, ApkFormatException { 189 try (RandomAccessFile f = new RandomAccessFile(apkFile, "r")) { 190 DataSource apk = DataSources.asDataSource(f, 0, f.length()); 191 return readFromApkDataSource(apk); 192 } 193 } 194 195 /** 196 * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3 and 197 * V3.1 signature blocks of the provided APK DataSource. 198 * 199 * @throws IllegalArgumentException if the provided APK does not contain a V3 nor V3.1 200 * signature block, or if the V3 and V3.1 signature blocks do not contain a valid lineage. 201 */ 202 readFromApkDataSource(DataSource apk)203 public static SigningCertificateLineage readFromApkDataSource(DataSource apk) 204 throws IOException, ApkFormatException { 205 return readFromApkDataSource(apk, /* readV31Lineage= */ true, /* readV3Lineage= */true); 206 } 207 208 /** 209 * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3.1 210 * signature blocks of the provided APK DataSource. 211 * 212 * @throws IllegalArgumentException if the provided APK does not contain a V3.1 signature block, 213 * or if the V3.1 signature block does not contain a valid lineage. 214 */ 215 readV31FromApkDataSource(DataSource apk)216 public static SigningCertificateLineage readV31FromApkDataSource(DataSource apk) 217 throws IOException, ApkFormatException { 218 return readFromApkDataSource(apk, /* readV31Lineage= */ true, 219 /* readV3Lineage= */ false); 220 } 221 readFromApkDataSource( DataSource apk, boolean readV31Lineage, boolean readV3Lineage)222 private static SigningCertificateLineage readFromApkDataSource( 223 DataSource apk, 224 boolean readV31Lineage, 225 boolean readV3Lineage) 226 throws IOException, ApkFormatException { 227 ApkUtils.ZipSections zipSections; 228 try { 229 zipSections = ApkUtils.findZipSections(apk); 230 } catch (ZipFormatException e) { 231 throw new ApkFormatException(e.getMessage()); 232 } 233 234 List<SignatureInfo> signatureInfoList = new ArrayList<>(); 235 if (readV31Lineage) { 236 try { 237 ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result( 238 ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V31); 239 signatureInfoList.add( 240 ApkSigningBlockUtils.findSignature(apk, zipSections, 241 V3SchemeConstants.APK_SIGNATURE_SCHEME_V31_BLOCK_ID, result)); 242 } catch (ApkSigningBlockUtils.SignatureNotFoundException ignored) { 243 // This could be expected if there's only a V3 signature block. 244 } 245 } 246 if (readV3Lineage) { 247 try { 248 ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result( 249 ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3); 250 signatureInfoList.add( 251 ApkSigningBlockUtils.findSignature(apk, zipSections, 252 V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID, result)); 253 } catch (ApkSigningBlockUtils.SignatureNotFoundException ignored) { 254 // This could be expected if the provided APK is not signed with the V3 signature 255 // scheme 256 } 257 } 258 if (signatureInfoList.isEmpty()) { 259 String message; 260 if (readV31Lineage && readV3Lineage) { 261 message = "The provided APK does not contain a valid V3 nor V3.1 signature block."; 262 } else if (readV31Lineage) { 263 message = "The provided APK does not contain a valid V3.1 signature block."; 264 } else if (readV3Lineage) { 265 message = "The provided APK does not contain a valid V3 signature block."; 266 } else { 267 message = "No signature blocks were requested."; 268 } 269 throw new IllegalArgumentException(message); 270 } 271 272 List<SigningCertificateLineage> lineages = new ArrayList<>(1); 273 for (SignatureInfo signatureInfo : signatureInfoList) { 274 // FORMAT: 275 // * length-prefixed sequence of length-prefixed signers: 276 // * length-prefixed signed data 277 // * minSDK 278 // * maxSDK 279 // * length-prefixed sequence of length-prefixed signatures 280 // * length-prefixed public key 281 ByteBuffer signers = getLengthPrefixedSlice(signatureInfo.signatureBlock); 282 while (signers.hasRemaining()) { 283 ByteBuffer signer = getLengthPrefixedSlice(signers); 284 ByteBuffer signedData = getLengthPrefixedSlice(signer); 285 try { 286 SigningCertificateLineage lineage = readFromSignedData(signedData); 287 lineages.add(lineage); 288 } catch (IllegalArgumentException ignored) { 289 // The current signer block does not contain a valid lineage, but it is possible 290 // another block will. 291 } 292 } 293 } 294 295 SigningCertificateLineage result; 296 if (lineages.isEmpty()) { 297 throw new IllegalArgumentException( 298 "The provided APK does not contain a valid lineage."); 299 } else if (lineages.size() > 1) { 300 result = consolidateLineages(lineages); 301 } else { 302 result = lineages.get(0); 303 } 304 return result; 305 } 306 307 /** 308 * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the provided 309 * signed data portion of a signer in a V3 signature block. 310 * 311 * @throws IllegalArgumentException if the provided signed data does not contain a valid 312 * lineage. 313 */ readFromSignedData(ByteBuffer signedData)314 public static SigningCertificateLineage readFromSignedData(ByteBuffer signedData) 315 throws IOException, ApkFormatException { 316 // FORMAT: 317 // * length-prefixed sequence of length-prefixed digests: 318 // * length-prefixed sequence of certificates: 319 // * length-prefixed bytes: X.509 certificate (ASN.1 DER encoded). 320 // * uint-32: minSdkVersion 321 // * uint-32: maxSdkVersion 322 // * length-prefixed sequence of length-prefixed additional attributes: 323 // * uint32: ID 324 // * (length - 4) bytes: value 325 // * uint32: Proof-of-rotation ID: 0x3ba06f8c 326 // * length-prefixed proof-of-rotation structure 327 // consume the digests through the maxSdkVersion to reach the lineage in the attributes 328 getLengthPrefixedSlice(signedData); 329 getLengthPrefixedSlice(signedData); 330 signedData.getInt(); 331 signedData.getInt(); 332 // iterate over the additional attributes adding any lineages to the List 333 ByteBuffer additionalAttributes = getLengthPrefixedSlice(signedData); 334 List<SigningCertificateLineage> lineages = new ArrayList<>(1); 335 while (additionalAttributes.hasRemaining()) { 336 ByteBuffer attribute = getLengthPrefixedSlice(additionalAttributes); 337 int id = attribute.getInt(); 338 if (id == V3SchemeConstants.PROOF_OF_ROTATION_ATTR_ID) { 339 byte[] value = ByteBufferUtils.toByteArray(attribute); 340 SigningCertificateLineage lineage = readFromV3AttributeValue(value); 341 lineages.add(lineage); 342 } 343 } 344 SigningCertificateLineage result; 345 // There should only be a single attribute with the lineage, but if there are multiple then 346 // attempt to consolidate the lineages. 347 if (lineages.isEmpty()) { 348 throw new IllegalArgumentException("The signed data does not contain a valid lineage."); 349 } else if (lineages.size() > 1) { 350 result = consolidateLineages(lineages); 351 } else { 352 result = lineages.get(0); 353 } 354 return result; 355 } 356 getBytes()357 public byte[] getBytes() { 358 return write().array(); 359 } 360 writeToFile(File file)361 public void writeToFile(File file) throws IOException { 362 if (file == null) { 363 throw new NullPointerException("file == null"); 364 } 365 RandomAccessFile outputFile = new RandomAccessFile(file, "rw"); 366 writeToDataSink(new RandomAccessFileDataSink(outputFile)); 367 } 368 writeToDataSink(DataSink dataSink)369 public void writeToDataSink(DataSink dataSink) throws IOException { 370 if (dataSink == null) { 371 throw new NullPointerException("dataSink == null"); 372 } 373 dataSink.consume(write()); 374 } 375 376 /** 377 * Add a new signing certificate to the lineage. This effectively creates a signing certificate 378 * rotation event, forcing APKs which include this lineage to be signed by the new signer. The 379 * flags associated with the new signer are set to a default value. 380 * 381 * @param parent current signing certificate of the containing APK 382 * @param child new signing certificate which will sign the APK contents 383 */ spawnDescendant(SignerConfig parent, SignerConfig child)384 public SigningCertificateLineage spawnDescendant(SignerConfig parent, SignerConfig child) 385 throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException, 386 SignatureException { 387 if (parent == null || child == null) { 388 throw new NullPointerException("can't add new descendant to lineage with null inputs"); 389 } 390 SignerCapabilities signerCapabilities = new SignerCapabilities.Builder().build(); 391 return spawnDescendant(parent, child, signerCapabilities); 392 } 393 394 /** 395 * Add a new signing certificate to the lineage. This effectively creates a signing certificate 396 * rotation event, forcing APKs which include this lineage to be signed by the new signer. 397 * 398 * @param parent current signing certificate of the containing APK 399 * @param child new signing certificate which will sign the APK contents 400 * @param childCapabilities flags 401 */ spawnDescendant( SignerConfig parent, SignerConfig child, SignerCapabilities childCapabilities)402 public SigningCertificateLineage spawnDescendant( 403 SignerConfig parent, SignerConfig child, SignerCapabilities childCapabilities) 404 throws CertificateEncodingException, InvalidKeyException, 405 NoSuchAlgorithmException, SignatureException { 406 if (parent == null) { 407 throw new NullPointerException("parent == null"); 408 } 409 if (child == null) { 410 throw new NullPointerException("child == null"); 411 } 412 if (childCapabilities == null) { 413 throw new NullPointerException("childCapabilities == null"); 414 } 415 if (mSigningLineage.isEmpty()) { 416 throw new IllegalArgumentException("Cannot spawn descendant signing certificate on an" 417 + " empty SigningCertificateLineage: no parent node"); 418 } 419 420 // make sure that the parent matches our newest generation (leaf node/sink) 421 SigningCertificateNode currentGeneration = mSigningLineage.get(mSigningLineage.size() - 1); 422 if (!Arrays.equals(currentGeneration.signingCert.getEncoded(), 423 parent.getCertificate().getEncoded())) { 424 throw new IllegalArgumentException("SignerConfig Certificate containing private key" 425 + " to sign the new SigningCertificateLineage record does not match the" 426 + " existing most recent record"); 427 } 428 429 // create data to be signed, including the algorithm we're going to use 430 SignatureAlgorithm signatureAlgorithm = getSignatureAlgorithm(parent); 431 ByteBuffer prefixedSignedData = ByteBuffer.wrap( 432 V3SigningCertificateLineage.encodeSignedData( 433 child.getCertificate(), signatureAlgorithm.getId())); 434 prefixedSignedData.position(4); 435 ByteBuffer signedDataBuffer = ByteBuffer.allocate(prefixedSignedData.remaining()); 436 signedDataBuffer.put(prefixedSignedData); 437 byte[] signedData = signedDataBuffer.array(); 438 439 // create SignerConfig to do the signing 440 List<X509Certificate> certificates = new ArrayList<>(1); 441 certificates.add(parent.getCertificate()); 442 ApkSigningBlockUtils.SignerConfig newSignerConfig = 443 new ApkSigningBlockUtils.SignerConfig(); 444 newSignerConfig.keyConfig = parent.getKeyConfig(); 445 newSignerConfig.certificates = certificates; 446 newSignerConfig.signatureAlgorithms = Collections.singletonList(signatureAlgorithm); 447 448 // sign it 449 List<Pair<Integer, byte[]>> signatures = 450 ApkSigningBlockUtils.generateSignaturesOverData(newSignerConfig, signedData); 451 452 // finally, add it to our lineage 453 SignatureAlgorithm sigAlgorithm = SignatureAlgorithm.findById(signatures.get(0).getFirst()); 454 byte[] signature = signatures.get(0).getSecond(); 455 currentGeneration.sigAlgorithm = sigAlgorithm; 456 SigningCertificateNode childNode = 457 new SigningCertificateNode( 458 child.getCertificate(), sigAlgorithm, null, 459 signature, childCapabilities.getFlags()); 460 List<SigningCertificateNode> lineageCopy = new ArrayList<>(mSigningLineage); 461 lineageCopy.add(childNode); 462 return new SigningCertificateLineage(mMinSdkVersion, lineageCopy); 463 } 464 465 /** 466 * The number of signing certificates in the lineage, including the current signer, which means 467 * this value can also be used to V2determine the number of signing certificate rotations by 468 * subtracting 1. 469 */ size()470 public int size() { 471 return mSigningLineage.size(); 472 } 473 getSignatureAlgorithm(SignerConfig parent)474 private SignatureAlgorithm getSignatureAlgorithm(SignerConfig parent) 475 throws InvalidKeyException { 476 PublicKey publicKey = parent.getCertificate().getPublicKey(); 477 478 // TODO switch to one signature algorithm selection, or add support for multiple algorithms 479 List<SignatureAlgorithm> algorithms = V3SchemeSigner.getSuggestedSignatureAlgorithms( 480 publicKey, mMinSdkVersion, false /* verityEnabled */, 481 false /* deterministicDsaSigning */); 482 return algorithms.get(0); 483 } 484 spawnFirstDescendant( SignerConfig parent, SignerCapabilities signerCapabilities)485 private SigningCertificateLineage spawnFirstDescendant( 486 SignerConfig parent, SignerCapabilities signerCapabilities) { 487 if (!mSigningLineage.isEmpty()) { 488 throw new IllegalStateException("SigningCertificateLineage already has its first node"); 489 } 490 491 // check to make sure that the public key for the first node is acceptable for our minSdk 492 try { 493 getSignatureAlgorithm(parent); 494 } catch (InvalidKeyException e) { 495 throw new IllegalArgumentException("Algorithm associated with first signing certificate" 496 + " invalid on desired platform versions", e); 497 } 498 499 // create "fake" signed data (there will be no signature over it, since there is no parent 500 SigningCertificateNode firstNode = new SigningCertificateNode( 501 parent.getCertificate(), null, null, new byte[0], signerCapabilities.getFlags()); 502 return new SigningCertificateLineage(mMinSdkVersion, Collections.singletonList(firstNode)); 503 } 504 read(ByteBuffer inputByteBuffer)505 private static SigningCertificateLineage read(ByteBuffer inputByteBuffer) 506 throws IOException { 507 ApkSigningBlockUtils.checkByteOrderLittleEndian(inputByteBuffer); 508 if (inputByteBuffer.remaining() < 8) { 509 throw new IllegalArgumentException( 510 "Improper SigningCertificateLineage format: insufficient data for header."); 511 } 512 513 if (inputByteBuffer.getInt() != MAGIC) { 514 throw new IllegalArgumentException( 515 "Improper SigningCertificateLineage format: MAGIC header mismatch."); 516 } 517 return read(inputByteBuffer, inputByteBuffer.getInt()); 518 } 519 read(ByteBuffer inputByteBuffer, int version)520 private static SigningCertificateLineage read(ByteBuffer inputByteBuffer, int version) 521 throws IOException { 522 switch (version) { 523 case FIRST_VERSION: 524 try { 525 List<SigningCertificateNode> nodes = 526 V3SigningCertificateLineage.readSigningCertificateLineage( 527 getLengthPrefixedSlice(inputByteBuffer)); 528 int minSdkVersion = calculateMinSdkVersion(nodes); 529 return new SigningCertificateLineage(minSdkVersion, nodes); 530 } catch (ApkFormatException e) { 531 // unable to get a proper length-prefixed lineage slice 532 throw new IOException("Unable to read list of signing certificate nodes in " 533 + "SigningCertificateLineage", e); 534 } 535 default: 536 throw new IllegalArgumentException( 537 "Improper SigningCertificateLineage format: unrecognized version."); 538 } 539 } 540 calculateMinSdkVersion(List<SigningCertificateNode> nodes)541 private static int calculateMinSdkVersion(List<SigningCertificateNode> nodes) { 542 if (nodes == null) { 543 throw new IllegalArgumentException("Can't calculate minimum SDK version of null nodes"); 544 } 545 int minSdkVersion = AndroidSdkVersion.P; // lineage introduced in P 546 for (SigningCertificateNode node : nodes) { 547 if (node.sigAlgorithm != null) { 548 int nodeMinSdkVersion = node.sigAlgorithm.getMinSdkVersion(); 549 if (nodeMinSdkVersion > minSdkVersion) { 550 minSdkVersion = nodeMinSdkVersion; 551 } 552 } 553 } 554 return minSdkVersion; 555 } 556 write()557 private ByteBuffer write() { 558 byte[] encodedLineage = 559 V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage); 560 int payloadSize = 4 + 4 + 4 + encodedLineage.length; 561 ByteBuffer result = ByteBuffer.allocate(payloadSize); 562 result.order(ByteOrder.LITTLE_ENDIAN); 563 result.putInt(MAGIC); 564 result.putInt(CURRENT_VERSION); 565 result.putInt(encodedLineage.length); 566 result.put(encodedLineage); 567 result.flip(); 568 return result; 569 } 570 encodeSigningCertificateLineage()571 public byte[] encodeSigningCertificateLineage() { 572 return V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage); 573 } 574 sortSignerConfigs( List<DefaultApkSignerEngine.SignerConfig> signerConfigs)575 public List<DefaultApkSignerEngine.SignerConfig> sortSignerConfigs( 576 List<DefaultApkSignerEngine.SignerConfig> signerConfigs) { 577 if (signerConfigs == null) { 578 throw new NullPointerException("signerConfigs == null"); 579 } 580 581 // not the most elegant sort, but we expect signerConfigs to be quite small (1 or 2 signers 582 // in most cases) and likely already sorted, so not worth the overhead of doing anything 583 // fancier 584 List<DefaultApkSignerEngine.SignerConfig> sortedSignerConfigs = 585 new ArrayList<>(signerConfigs.size()); 586 for (int i = 0; i < mSigningLineage.size(); i++) { 587 for (int j = 0; j < signerConfigs.size(); j++) { 588 DefaultApkSignerEngine.SignerConfig config = signerConfigs.get(j); 589 if (mSigningLineage.get(i).signingCert.equals(config.getCertificates().get(0))) { 590 sortedSignerConfigs.add(config); 591 break; 592 } 593 } 594 } 595 if (sortedSignerConfigs.size() != signerConfigs.size()) { 596 throw new IllegalArgumentException("SignerConfigs supplied which are not present in the" 597 + " SigningCertificateLineage"); 598 } 599 return sortedSignerConfigs; 600 } 601 602 /** 603 * Returns the SignerCapabilities for the signer in the lineage that matches the provided 604 * config. 605 */ getSignerCapabilities(SignerConfig config)606 public SignerCapabilities getSignerCapabilities(SignerConfig config) { 607 if (config == null) { 608 throw new NullPointerException("config == null"); 609 } 610 611 X509Certificate cert = config.getCertificate(); 612 return getSignerCapabilities(cert); 613 } 614 615 /** 616 * Returns the SignerCapabilities for the signer in the lineage that matches the provided 617 * certificate. 618 */ getSignerCapabilities(X509Certificate cert)619 public SignerCapabilities getSignerCapabilities(X509Certificate cert) { 620 if (cert == null) { 621 throw new NullPointerException("cert == null"); 622 } 623 624 for (int i = 0; i < mSigningLineage.size(); i++) { 625 SigningCertificateNode lineageNode = mSigningLineage.get(i); 626 if (lineageNode.signingCert.equals(cert)) { 627 int flags = lineageNode.flags; 628 return new SignerCapabilities.Builder(flags).build(); 629 } 630 } 631 632 // the provided signer certificate was not found in the lineage 633 throw new IllegalArgumentException("Certificate (" + cert.getSubjectDN() 634 + ") not found in the SigningCertificateLineage"); 635 } 636 637 /** 638 * Updates the SignerCapabilities for the signer in the lineage that matches the provided 639 * config. Only those capabilities that have been modified through the setXX methods will be 640 * updated for the signer to prevent unset default values from being applied. 641 */ updateSignerCapabilities(SignerConfig config, SignerCapabilities capabilities)642 public void updateSignerCapabilities(SignerConfig config, SignerCapabilities capabilities) { 643 if (config == null) { 644 throw new NullPointerException("config == null"); 645 } 646 updateSignerCapabilities(config.getCertificate(), capabilities); 647 } 648 649 /** 650 * Updates the {@code capabilities} for the signer with the provided {@code certificate} in the 651 * lineage. Only those capabilities that have been modified through the setXX methods will be 652 * updated for the signer to prevent unset default values from being applied. 653 */ updateSignerCapabilities(X509Certificate certificate, SignerCapabilities capabilities)654 public void updateSignerCapabilities(X509Certificate certificate, 655 SignerCapabilities capabilities) { 656 if (certificate == null) { 657 throw new NullPointerException("config == null"); 658 } 659 660 for (int i = 0; i < mSigningLineage.size(); i++) { 661 SigningCertificateNode lineageNode = mSigningLineage.get(i); 662 if (lineageNode.signingCert.equals(certificate)) { 663 int flags = lineageNode.flags; 664 SignerCapabilities newCapabilities = new SignerCapabilities.Builder( 665 flags).setCallerConfiguredCapabilities(capabilities).build(); 666 lineageNode.flags = newCapabilities.getFlags(); 667 return; 668 } 669 } 670 671 // the provided signer config was not found in the lineage 672 throw new IllegalArgumentException("Certificate (" + certificate.getSubjectDN() 673 + ") not found in the SigningCertificateLineage"); 674 } 675 676 /** 677 * Returns a list containing all of the certificates in the lineage. 678 */ getCertificatesInLineage()679 public List<X509Certificate> getCertificatesInLineage() { 680 List<X509Certificate> certs = new ArrayList<>(); 681 for (int i = 0; i < mSigningLineage.size(); i++) { 682 X509Certificate cert = mSigningLineage.get(i).signingCert; 683 certs.add(cert); 684 } 685 return certs; 686 } 687 688 /** 689 * Returns {@code true} if the specified config is in the lineage. 690 */ isSignerInLineage(SignerConfig config)691 public boolean isSignerInLineage(SignerConfig config) { 692 if (config == null) { 693 throw new NullPointerException("config == null"); 694 } 695 696 X509Certificate cert = config.getCertificate(); 697 return isCertificateInLineage(cert); 698 } 699 700 /** 701 * Returns {@code true} if the specified certificate is in the lineage. 702 */ isCertificateInLineage(X509Certificate cert)703 public boolean isCertificateInLineage(X509Certificate cert) { 704 if (cert == null) { 705 throw new NullPointerException("cert == null"); 706 } 707 708 for (int i = 0; i < mSigningLineage.size(); i++) { 709 if (mSigningLineage.get(i).signingCert.equals(cert)) { 710 return true; 711 } 712 } 713 return false; 714 } 715 716 /** 717 * Returns whether the provided {@code cert} is the latest signing certificate in the lineage. 718 * 719 * <p>This method will only compare the provided {@code cert} against the latest signing 720 * certificate in the lineage; if a certificate that is not in the lineage is provided, this 721 * method will return false. 722 */ isCertificateLatestInLineage(X509Certificate cert)723 public boolean isCertificateLatestInLineage(X509Certificate cert) { 724 if (cert == null) { 725 throw new NullPointerException("cert == null"); 726 } 727 728 return mSigningLineage.get(mSigningLineage.size() - 1).signingCert.equals(cert); 729 } 730 calculateDefaultFlags()731 private static int calculateDefaultFlags() { 732 return PAST_CERT_INSTALLED_DATA | PAST_CERT_PERMISSION 733 | PAST_CERT_SHARED_USER_ID | PAST_CERT_AUTH; 734 } 735 736 /** 737 * Returns a new SigningCertificateLineage which terminates at the node corresponding to the 738 * given certificate. This is useful in the event of rotating to a new signing algorithm that 739 * is only supported on some platform versions. It enables a v3 signature to be generated using 740 * this signing certificate and the shortened proof-of-rotation record from this sub lineage in 741 * conjunction with the appropriate SDK version values. 742 * 743 * @param x509Certificate the signing certificate for which to search 744 * @return A new SigningCertificateLineage if the given certificate is present. 745 * 746 * @throws IllegalArgumentException if the provided certificate is not in the lineage. 747 */ getSubLineage(X509Certificate x509Certificate)748 public SigningCertificateLineage getSubLineage(X509Certificate x509Certificate) { 749 if (x509Certificate == null) { 750 throw new NullPointerException("x509Certificate == null"); 751 } 752 for (int i = 0; i < mSigningLineage.size(); i++) { 753 if (mSigningLineage.get(i).signingCert.equals(x509Certificate)) { 754 return new SigningCertificateLineage( 755 mMinSdkVersion, new ArrayList<>(mSigningLineage.subList(0, i + 1))); 756 } 757 } 758 759 // looks like we didn't find the cert, 760 throw new IllegalArgumentException("Certificate not found in SigningCertificateLineage"); 761 } 762 763 /** 764 * Consolidates all of the lineages found in an APK into one lineage. In so doing, it also 765 * checks that all of the lineages are contained in one common lineage. 766 * 767 * An APK may contain multiple lineages, one for each signer, which correspond to different 768 * supported platform versions. In this event, the lineage(s) from the earlier platform 769 * version(s) should be present in the most recent, either directly or via a sublineage 770 * that would allow the earlier lineages to merge with the most recent. 771 * 772 * <note> This does not verify that the largest lineage corresponds to the most recent supported 773 * platform version. That check is performed during v3 verification. </note> 774 */ consolidateLineages( List<SigningCertificateLineage> lineages)775 public static SigningCertificateLineage consolidateLineages( 776 List<SigningCertificateLineage> lineages) { 777 if (lineages == null || lineages.isEmpty()) { 778 return null; 779 } 780 SigningCertificateLineage consolidatedLineage = lineages.get(0); 781 for (int i = 1; i < lineages.size(); i++) { 782 consolidatedLineage = consolidatedLineage.mergeLineageWith(lineages.get(i)); 783 } 784 return consolidatedLineage; 785 } 786 787 /** 788 * Merges this lineage with the provided {@code otherLineage}. 789 * 790 * <p>The merged lineage does not currently handle merging capabilities of common signers and 791 * should only be used to determine the full signing history of a collection of lineages. 792 */ mergeLineageWith(SigningCertificateLineage otherLineage)793 public SigningCertificateLineage mergeLineageWith(SigningCertificateLineage otherLineage) { 794 // Determine the ancestor and descendant lineages; if the original signer is in the other 795 // lineage, then it is considered a descendant. 796 SigningCertificateLineage ancestorLineage; 797 SigningCertificateLineage descendantLineage; 798 X509Certificate signerCert = mSigningLineage.get(0).signingCert; 799 if (otherLineage.isCertificateInLineage(signerCert)) { 800 descendantLineage = this; 801 ancestorLineage = otherLineage; 802 } else { 803 descendantLineage = otherLineage; 804 ancestorLineage = this; 805 } 806 807 int ancestorIndex = 0; 808 int descendantIndex = 0; 809 SigningCertificateNode ancestorNode; 810 SigningCertificateNode descendantNode = descendantLineage.mSigningLineage.get( 811 descendantIndex++); 812 List<SigningCertificateNode> mergedLineage = new ArrayList<>(); 813 // Iterate through the ancestor lineage and add the current node to the resulting lineage 814 // until the first node of the descendant is found. 815 while (ancestorIndex < ancestorLineage.size()) { 816 ancestorNode = ancestorLineage.mSigningLineage.get(ancestorIndex++); 817 if (ancestorNode.signingCert.equals(descendantNode.signingCert)) { 818 break; 819 } 820 mergedLineage.add(ancestorNode); 821 } 822 // If all of the nodes in the ancestor lineage have been added to the merged lineage, then 823 // there is no overlap between this and the provided lineage. 824 if (ancestorIndex == mergedLineage.size()) { 825 throw new IllegalArgumentException( 826 "The provided lineage is not a descendant or an ancestor of this lineage"); 827 } 828 // The descendant lineage's first node was in the ancestor's lineage above; add it to the 829 // merged lineage. 830 mergedLineage.add(descendantNode); 831 while (ancestorIndex < ancestorLineage.size() 832 && descendantIndex < descendantLineage.size()) { 833 ancestorNode = ancestorLineage.mSigningLineage.get(ancestorIndex++); 834 descendantNode = descendantLineage.mSigningLineage.get(descendantIndex++); 835 if (!ancestorNode.signingCert.equals(descendantNode.signingCert)) { 836 throw new IllegalArgumentException( 837 "The provided lineage diverges from this lineage"); 838 } 839 mergedLineage.add(descendantNode); 840 } 841 // At this point, one or both of the lineages have been exhausted and all signers to this 842 // point were a match between the two lineages; add any remaining elements from either 843 // lineage to the merged lineage. 844 while (ancestorIndex < ancestorLineage.size()) { 845 mergedLineage.add(ancestorLineage.mSigningLineage.get(ancestorIndex++)); 846 } 847 while (descendantIndex < descendantLineage.size()) { 848 mergedLineage.add(descendantLineage.mSigningLineage.get(descendantIndex++)); 849 } 850 return new SigningCertificateLineage(Math.min(mMinSdkVersion, otherLineage.mMinSdkVersion), 851 mergedLineage); 852 } 853 854 /** 855 * Checks whether given lineages are compatible. Returns {@code true} if an installed APK with 856 * the oldLineage could be updated with an APK with the newLineage. 857 */ checkLineagesCompatibility( SigningCertificateLineage oldLineage, SigningCertificateLineage newLineage)858 public static boolean checkLineagesCompatibility( 859 SigningCertificateLineage oldLineage, SigningCertificateLineage newLineage) { 860 861 final ArrayList<X509Certificate> oldCertificates = oldLineage == null ? 862 new ArrayList<X509Certificate>() 863 : new ArrayList(oldLineage.getCertificatesInLineage()); 864 final ArrayList<X509Certificate> newCertificates = newLineage == null ? 865 new ArrayList<X509Certificate>() 866 : new ArrayList(newLineage.getCertificatesInLineage()); 867 868 if (oldCertificates.isEmpty()) { 869 return true; 870 } 871 if (newCertificates.isEmpty()) { 872 return false; 873 } 874 875 // Both lineages contain exactly the same certificates or the new lineage extends 876 // the old one. The capabilities of particular certificates may have changed though but it 877 // does not matter in terms of current compatibility. 878 if (newCertificates.size() >= oldCertificates.size() 879 && newCertificates.subList(0, oldCertificates.size()).equals(oldCertificates)) { 880 return true; 881 } 882 883 ArrayList<X509Certificate> newCertificatesArray = new ArrayList(newCertificates); 884 ArrayList<X509Certificate> oldCertificatesArray = new ArrayList(oldCertificates); 885 886 int lastOldCertIndexInNew = newCertificatesArray.lastIndexOf( 887 oldCertificatesArray.get(oldCertificatesArray.size()-1)); 888 889 // The new lineage trims some nodes from the beginning of the old lineage and possibly 890 // extends it at the end. The new lineage must contain the old signing certificate and 891 // the nodes up until the node with signing certificate must be in the same order. 892 // Good example 1: 893 // old: A -> B -> C 894 // new: B -> C -> D 895 // Good example 2: 896 // old: A -> B -> C 897 // new: C 898 // Bad example 1: 899 // old: A -> B -> C 900 // new: A -> C 901 // Bad example 1: 902 // old: A -> B 903 // new: C -> B 904 if (lastOldCertIndexInNew >= 0) { 905 return newCertificatesArray.subList(0, lastOldCertIndexInNew+1).equals( 906 oldCertificatesArray.subList( 907 oldCertificates.size()-1-lastOldCertIndexInNew, 908 oldCertificatesArray.size())); 909 } 910 911 912 // The new lineage can be shorter than the old one only if the last certificate of the new 913 // lineage exists in the old lineage and has a rollback capability there. 914 // Good example: 915 // old: A -> B_withRollbackCapability -> C 916 // new: A -> B 917 // Bad example 1: 918 // old: A -> B -> C 919 // new: A -> B 920 // Bad example 2: 921 // old: A -> B_withRollbackCapability -> C 922 // new: A -> B -> D 923 return oldCertificates.subList(0, newCertificates.size()).equals(newCertificates) 924 && oldLineage.getSignerCapabilities( 925 oldCertificates.get(newCertificates.size()-1)).hasRollback(); 926 } 927 928 /** 929 * Representation of the capabilities the APK would like to grant to its old signing 930 * certificates. The {@code SigningCertificateLineage} provides two conceptual data structures. 931 * 1) proof of rotation - Evidence that other parties can trust an APK's current signing 932 * certificate if they trust an older one in this lineage 933 * 2) self-trust - certain capabilities may have been granted by an APK to other parties based 934 * on its own signing certificate. When it changes its signing certificate it may want to 935 * allow the other parties to retain those capabilities. 936 * {@code SignerCapabilties} provides a representation of the second structure. 937 * 938 * <p>Use {@link Builder} to obtain configuration instances. 939 */ 940 public static class SignerCapabilities { 941 private final int mFlags; 942 943 private final int mCallerConfiguredFlags; 944 SignerCapabilities(int flags, int callerConfiguredFlags)945 private SignerCapabilities(int flags, int callerConfiguredFlags) { 946 mFlags = flags; 947 mCallerConfiguredFlags = callerConfiguredFlags; 948 } 949 getFlags()950 private int getFlags() { 951 return mFlags; 952 } 953 954 /** 955 * Returns {@code true} if the capabilities of this object match those of the provided 956 * object. 957 */ 958 @Override equals(Object other)959 public boolean equals(Object other) { 960 if (this == other) return true; 961 if (!(other instanceof SignerCapabilities)) return false; 962 963 return this.mFlags == ((SignerCapabilities) other).mFlags; 964 } 965 966 @Override hashCode()967 public int hashCode() { 968 return 31 * mFlags; 969 } 970 971 /** 972 * Returns {@code true} if this object has the installed data capability. 973 */ hasInstalledData()974 public boolean hasInstalledData() { 975 return (mFlags & PAST_CERT_INSTALLED_DATA) != 0; 976 } 977 978 /** 979 * Returns {@code true} if this object has the shared UID capability. 980 */ hasSharedUid()981 public boolean hasSharedUid() { 982 return (mFlags & PAST_CERT_SHARED_USER_ID) != 0; 983 } 984 985 /** 986 * Returns {@code true} if this object has the permission capability. 987 */ hasPermission()988 public boolean hasPermission() { 989 return (mFlags & PAST_CERT_PERMISSION) != 0; 990 } 991 992 /** 993 * Returns {@code true} if this object has the rollback capability. 994 */ hasRollback()995 public boolean hasRollback() { 996 return (mFlags & PAST_CERT_ROLLBACK) != 0; 997 } 998 999 /** 1000 * Returns {@code true} if this object has the auth capability. 1001 */ hasAuth()1002 public boolean hasAuth() { 1003 return (mFlags & PAST_CERT_AUTH) != 0; 1004 } 1005 1006 /** 1007 * Builder of {@link SignerCapabilities} instances. 1008 */ 1009 public static class Builder { 1010 private int mFlags; 1011 1012 private int mCallerConfiguredFlags; 1013 1014 /** 1015 * Constructs a new {@code Builder}. 1016 */ Builder()1017 public Builder() { 1018 mFlags = calculateDefaultFlags(); 1019 } 1020 1021 /** 1022 * Constructs a new {@code Builder} with the initial capabilities set to the provided 1023 * flags. 1024 */ Builder(int flags)1025 public Builder(int flags) { 1026 mFlags = flags; 1027 } 1028 1029 /** 1030 * Set the {@code PAST_CERT_INSTALLED_DATA} flag in this capabilities object. This flag 1031 * is used by the platform to determine if installed data associated with previous 1032 * signing certificate should be trusted. In particular, this capability is required to 1033 * perform signing certificate rotation during an upgrade on-device. Without it, the 1034 * platform will not permit the app data from the old signing certificate to 1035 * propagate to the new version. Typically, this flag should be set to enable signing 1036 * certificate rotation, and may be unset later when the app developer is satisfied that 1037 * their install base is as migrated as it will be. 1038 */ setInstalledData(boolean enabled)1039 public Builder setInstalledData(boolean enabled) { 1040 mCallerConfiguredFlags |= PAST_CERT_INSTALLED_DATA; 1041 if (enabled) { 1042 mFlags |= PAST_CERT_INSTALLED_DATA; 1043 } else { 1044 mFlags &= ~PAST_CERT_INSTALLED_DATA; 1045 } 1046 return this; 1047 } 1048 1049 /** 1050 * Set the {@code PAST_CERT_SHARED_USER_ID} flag in this capabilities object. This flag 1051 * is used by the platform to determine if this app is willing to be sharedUid with 1052 * other apps which are still signed with the associated signing certificate. This is 1053 * useful in situations where sharedUserId apps would like to change their signing 1054 * certificate, but can't guarantee the order of updates to those apps. 1055 */ setSharedUid(boolean enabled)1056 public Builder setSharedUid(boolean enabled) { 1057 mCallerConfiguredFlags |= PAST_CERT_SHARED_USER_ID; 1058 if (enabled) { 1059 mFlags |= PAST_CERT_SHARED_USER_ID; 1060 } else { 1061 mFlags &= ~PAST_CERT_SHARED_USER_ID; 1062 } 1063 return this; 1064 } 1065 1066 /** 1067 * Set the {@code PAST_CERT_PERMISSION} flag in this capabilities object. This flag 1068 * is used by the platform to determine if this app is willing to grant SIGNATURE 1069 * permissions to apps signed with the associated signing certificate. Without this 1070 * capability, an application signed with the older certificate will not be granted the 1071 * SIGNATURE permissions defined by this app. In addition, if multiple apps define the 1072 * same SIGNATURE permission, the second one the platform sees will not be installable 1073 * if this capability is not set and the signing certificates differ. 1074 */ setPermission(boolean enabled)1075 public Builder setPermission(boolean enabled) { 1076 mCallerConfiguredFlags |= PAST_CERT_PERMISSION; 1077 if (enabled) { 1078 mFlags |= PAST_CERT_PERMISSION; 1079 } else { 1080 mFlags &= ~PAST_CERT_PERMISSION; 1081 } 1082 return this; 1083 } 1084 1085 /** 1086 * Set the {@code PAST_CERT_ROLLBACK} flag in this capabilities object. This flag 1087 * is used by the platform to determine if this app is willing to upgrade to a new 1088 * version that is signed by one of its past signing certificates. 1089 * 1090 * <note> WARNING: this effectively removes any benefit of signing certificate changes, 1091 * since a compromised key could retake control of an app even after change, and should 1092 * only be used if there is a problem encountered when trying to ditch an older cert 1093 * </note> 1094 */ setRollback(boolean enabled)1095 public Builder setRollback(boolean enabled) { 1096 mCallerConfiguredFlags |= PAST_CERT_ROLLBACK; 1097 if (enabled) { 1098 mFlags |= PAST_CERT_ROLLBACK; 1099 } else { 1100 mFlags &= ~PAST_CERT_ROLLBACK; 1101 } 1102 return this; 1103 } 1104 1105 /** 1106 * Set the {@code PAST_CERT_AUTH} flag in this capabilities object. This flag 1107 * is used by the platform to determine whether or not privileged access based on 1108 * authenticator module signing certificates should be granted. 1109 */ setAuth(boolean enabled)1110 public Builder setAuth(boolean enabled) { 1111 mCallerConfiguredFlags |= PAST_CERT_AUTH; 1112 if (enabled) { 1113 mFlags |= PAST_CERT_AUTH; 1114 } else { 1115 mFlags &= ~PAST_CERT_AUTH; 1116 } 1117 return this; 1118 } 1119 1120 /** 1121 * Applies the capabilities that were explicitly set in the provided capabilities object 1122 * to this builder. Any values that were not set will not be applied to this builder 1123 * to prevent unintentinoally setting a capability back to a default value. 1124 */ setCallerConfiguredCapabilities(SignerCapabilities capabilities)1125 public Builder setCallerConfiguredCapabilities(SignerCapabilities capabilities) { 1126 // The mCallerConfiguredFlags should have a bit set for each capability that was 1127 // set by a caller. If a capability was explicitly set then the corresponding bit 1128 // in mCallerConfiguredFlags should be set. This allows the provided capabilities 1129 // to take effect for those set by the caller while those that were not set will 1130 // be cleared by the bitwise and and the initial value for the builder will remain. 1131 mFlags = (mFlags & ~capabilities.mCallerConfiguredFlags) | 1132 (capabilities.mFlags & capabilities.mCallerConfiguredFlags); 1133 return this; 1134 } 1135 1136 /** 1137 * Returns a new {@code SignerConfig} instance configured based on the configuration of 1138 * this builder. 1139 */ build()1140 public SignerCapabilities build() { 1141 return new SignerCapabilities(mFlags, mCallerConfiguredFlags); 1142 } 1143 } 1144 } 1145 1146 /** 1147 * Configuration of a signer. Used to add a new entry to the {@link SigningCertificateLineage} 1148 * 1149 * <p>Use {@link Builder} to obtain configuration instances. 1150 */ 1151 public static class SignerConfig { 1152 private final KeyConfig mKeyConfig; 1153 private final X509Certificate mCertificate; 1154 SignerConfig(KeyConfig keyConfig, X509Certificate certificate)1155 private SignerConfig(KeyConfig keyConfig, X509Certificate certificate) { 1156 mKeyConfig = keyConfig; 1157 mCertificate = certificate; 1158 } 1159 1160 /** 1161 * Returns the signing key of this signer. 1162 * 1163 * @deprecated Use {@link #getKeyConfig()} instead of accessing a {@link PrivateKey} 1164 * directly. If the user of ApkSigner is signing with a KMS instead of JCA, this method 1165 * will return null. 1166 */ 1167 @Deprecated getPrivateKey()1168 public PrivateKey getPrivateKey() { 1169 return mKeyConfig.match(jca -> jca.privateKey, kms -> null); 1170 } 1171 getKeyConfig()1172 public KeyConfig getKeyConfig() { 1173 return mKeyConfig; 1174 } 1175 1176 /** 1177 * Returns the certificate(s) of this signer. The first certificate's public key corresponds 1178 * to this signer's private key. 1179 */ getCertificate()1180 public X509Certificate getCertificate() { 1181 return mCertificate; 1182 } 1183 1184 /** 1185 * Builder of {@link SignerConfig} instances. 1186 */ 1187 public static class Builder { 1188 private final KeyConfig mKeyConfig; 1189 private final X509Certificate mCertificate; 1190 1191 /** 1192 * Constructs a new {@code Builder}. 1193 * 1194 * @deprecated use {@link #Builder(KeyConfig, X509Certificate)} instead 1195 * @param privateKey signing key 1196 * @param certificate the X.509 certificate with a subject public key of the {@code 1197 * privateKey}. 1198 */ 1199 @Deprecated Builder(PrivateKey privateKey, X509Certificate certificate)1200 public Builder(PrivateKey privateKey, X509Certificate certificate) { 1201 mKeyConfig = new KeyConfig.Jca(privateKey); 1202 mCertificate = certificate; 1203 } 1204 1205 /** 1206 * Constructs a new {@code Builder}. 1207 * 1208 * @param keyConfig signing key configuration 1209 * @param certificate the X.509 certificate with a subject public key of the {@code 1210 * privateKey}. 1211 */ Builder(KeyConfig keyConfig, X509Certificate certificate)1212 public Builder(KeyConfig keyConfig, X509Certificate certificate) { 1213 mKeyConfig = keyConfig; 1214 mCertificate = certificate; 1215 } 1216 1217 /** 1218 * Returns a new {@code SignerConfig} instance configured based on the configuration of 1219 * this builder. 1220 */ build()1221 public SignerConfig build() { 1222 return new SignerConfig(mKeyConfig, mCertificate); 1223 } 1224 } 1225 } 1226 1227 /** 1228 * Builder of {@link SigningCertificateLineage} instances. 1229 */ 1230 public static class Builder { 1231 private final SignerConfig mOriginalSignerConfig; 1232 private final SignerConfig mNewSignerConfig; 1233 private SignerCapabilities mOriginalCapabilities; 1234 private SignerCapabilities mNewCapabilities; 1235 private int mMinSdkVersion; 1236 /** 1237 * Constructs a new {@code Builder}. 1238 * 1239 * @param originalSignerConfig first signer in this lineage, parent of the next 1240 * @param newSignerConfig new signer in the lineage; the new signing key that the APK will 1241 * use 1242 */ Builder( SignerConfig originalSignerConfig, SignerConfig newSignerConfig)1243 public Builder( 1244 SignerConfig originalSignerConfig, 1245 SignerConfig newSignerConfig) { 1246 if (originalSignerConfig == null || newSignerConfig == null) { 1247 throw new NullPointerException("Can't pass null SignerConfigs when constructing a " 1248 + "new SigningCertificateLineage"); 1249 } 1250 mOriginalSignerConfig = originalSignerConfig; 1251 mNewSignerConfig = newSignerConfig; 1252 } 1253 1254 /** 1255 * Constructs a new {@code Builder} that is intended to create a {@code 1256 * SigningCertificateLineage} with a single signer in the signing history. 1257 * 1258 * @param originalSignerConfig first signer in this lineage 1259 */ Builder(SignerConfig originalSignerConfig)1260 public Builder(SignerConfig originalSignerConfig) { 1261 if (originalSignerConfig == null) { 1262 throw new NullPointerException("Can't pass null SignerConfigs when constructing a " 1263 + "new SigningCertificateLineage"); 1264 } 1265 mOriginalSignerConfig = originalSignerConfig; 1266 mNewSignerConfig = null; 1267 } 1268 1269 /** 1270 * Sets the minimum Android platform version (API Level) on which this lineage is expected 1271 * to validate. It is possible that newer signers in the lineage may not be recognized on 1272 * the given platform, but as long as an older signer is, the lineage can still be used to 1273 * sign an APK for the given platform. 1274 * 1275 * <note> By default, this value is set to the value for the 1276 * P release, since this structure was created for that release, and will also be set to 1277 * that value if a smaller one is specified. </note> 1278 */ setMinSdkVersion(int minSdkVersion)1279 public Builder setMinSdkVersion(int minSdkVersion) { 1280 mMinSdkVersion = minSdkVersion; 1281 return this; 1282 } 1283 1284 /** 1285 * Sets capabilities to give {@code mOriginalSignerConfig}. These capabilities allow an 1286 * older signing certificate to still be used in some situations on the platform even though 1287 * the APK is now being signed by a newer signing certificate. 1288 */ setOriginalCapabilities(SignerCapabilities signerCapabilities)1289 public Builder setOriginalCapabilities(SignerCapabilities signerCapabilities) { 1290 if (signerCapabilities == null) { 1291 throw new NullPointerException("signerCapabilities == null"); 1292 } 1293 mOriginalCapabilities = signerCapabilities; 1294 return this; 1295 } 1296 1297 /** 1298 * Sets capabilities to give {@code mNewSignerConfig}. These capabilities allow an 1299 * older signing certificate to still be used in some situations on the platform even though 1300 * the APK is now being signed by a newer signing certificate. By default, the new signer 1301 * will have all capabilities, so when first switching to a new signing certificate, these 1302 * capabilities have no effect, but they will act as the default level of trust when moving 1303 * to a new signing certificate. 1304 */ setNewCapabilities(SignerCapabilities signerCapabilities)1305 public Builder setNewCapabilities(SignerCapabilities signerCapabilities) { 1306 if (signerCapabilities == null) { 1307 throw new NullPointerException("signerCapabilities == null"); 1308 } 1309 mNewCapabilities = signerCapabilities; 1310 return this; 1311 } 1312 build()1313 public SigningCertificateLineage build() 1314 throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException, 1315 SignatureException { 1316 if (mMinSdkVersion < AndroidSdkVersion.P) { 1317 mMinSdkVersion = AndroidSdkVersion.P; 1318 } 1319 1320 if (mOriginalCapabilities == null) { 1321 mOriginalCapabilities = new SignerCapabilities.Builder().build(); 1322 } 1323 1324 if (mNewSignerConfig == null) { 1325 return createSigningLineage(mMinSdkVersion, mOriginalSignerConfig, 1326 mOriginalCapabilities); 1327 } 1328 1329 if (mNewCapabilities == null) { 1330 mNewCapabilities = new SignerCapabilities.Builder().build(); 1331 } 1332 1333 return createSigningLineage( 1334 mMinSdkVersion, mOriginalSignerConfig, mOriginalCapabilities, 1335 mNewSignerConfig, mNewCapabilities); 1336 } 1337 } 1338 } 1339