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)945 private SignerCapabilities(int flags) { 946 this(flags, 0); 947 } 948 SignerCapabilities(int flags, int callerConfiguredFlags)949 private SignerCapabilities(int flags, int callerConfiguredFlags) { 950 mFlags = flags; 951 mCallerConfiguredFlags = callerConfiguredFlags; 952 } 953 getFlags()954 private int getFlags() { 955 return mFlags; 956 } 957 958 /** 959 * Returns {@code true} if the capabilities of this object match those of the provided 960 * object. 961 */ 962 @Override equals(Object other)963 public boolean equals(Object other) { 964 if (this == other) return true; 965 if (!(other instanceof SignerCapabilities)) return false; 966 967 return this.mFlags == ((SignerCapabilities) other).mFlags; 968 } 969 970 @Override hashCode()971 public int hashCode() { 972 return 31 * mFlags; 973 } 974 975 /** 976 * Returns {@code true} if this object has the installed data capability. 977 */ hasInstalledData()978 public boolean hasInstalledData() { 979 return (mFlags & PAST_CERT_INSTALLED_DATA) != 0; 980 } 981 982 /** 983 * Returns {@code true} if this object has the shared UID capability. 984 */ hasSharedUid()985 public boolean hasSharedUid() { 986 return (mFlags & PAST_CERT_SHARED_USER_ID) != 0; 987 } 988 989 /** 990 * Returns {@code true} if this object has the permission capability. 991 */ hasPermission()992 public boolean hasPermission() { 993 return (mFlags & PAST_CERT_PERMISSION) != 0; 994 } 995 996 /** 997 * Returns {@code true} if this object has the rollback capability. 998 */ hasRollback()999 public boolean hasRollback() { 1000 return (mFlags & PAST_CERT_ROLLBACK) != 0; 1001 } 1002 1003 /** 1004 * Returns {@code true} if this object has the auth capability. 1005 */ hasAuth()1006 public boolean hasAuth() { 1007 return (mFlags & PAST_CERT_AUTH) != 0; 1008 } 1009 1010 /** 1011 * Builder of {@link SignerCapabilities} instances. 1012 */ 1013 public static class Builder { 1014 private int mFlags; 1015 1016 private int mCallerConfiguredFlags; 1017 1018 /** 1019 * Constructs a new {@code Builder}. 1020 */ Builder()1021 public Builder() { 1022 mFlags = calculateDefaultFlags(); 1023 } 1024 1025 /** 1026 * Constructs a new {@code Builder} with the initial capabilities set to the provided 1027 * flags. 1028 */ Builder(int flags)1029 public Builder(int flags) { 1030 mFlags = flags; 1031 } 1032 1033 /** 1034 * Set the {@code PAST_CERT_INSTALLED_DATA} flag in this capabilities object. This flag 1035 * is used by the platform to determine if installed data associated with previous 1036 * signing certificate should be trusted. In particular, this capability is required to 1037 * perform signing certificate rotation during an upgrade on-device. Without it, the 1038 * platform will not permit the app data from the old signing certificate to 1039 * propagate to the new version. Typically, this flag should be set to enable signing 1040 * certificate rotation, and may be unset later when the app developer is satisfied that 1041 * their install base is as migrated as it will be. 1042 */ setInstalledData(boolean enabled)1043 public Builder setInstalledData(boolean enabled) { 1044 mCallerConfiguredFlags |= PAST_CERT_INSTALLED_DATA; 1045 if (enabled) { 1046 mFlags |= PAST_CERT_INSTALLED_DATA; 1047 } else { 1048 mFlags &= ~PAST_CERT_INSTALLED_DATA; 1049 } 1050 return this; 1051 } 1052 1053 /** 1054 * Set the {@code PAST_CERT_SHARED_USER_ID} flag in this capabilities object. This flag 1055 * is used by the platform to determine if this app is willing to be sharedUid with 1056 * other apps which are still signed with the associated signing certificate. This is 1057 * useful in situations where sharedUserId apps would like to change their signing 1058 * certificate, but can't guarantee the order of updates to those apps. 1059 */ setSharedUid(boolean enabled)1060 public Builder setSharedUid(boolean enabled) { 1061 mCallerConfiguredFlags |= PAST_CERT_SHARED_USER_ID; 1062 if (enabled) { 1063 mFlags |= PAST_CERT_SHARED_USER_ID; 1064 } else { 1065 mFlags &= ~PAST_CERT_SHARED_USER_ID; 1066 } 1067 return this; 1068 } 1069 1070 /** 1071 * Set the {@code PAST_CERT_PERMISSION} flag in this capabilities object. This flag 1072 * is used by the platform to determine if this app is willing to grant SIGNATURE 1073 * permissions to apps signed with the associated signing certificate. Without this 1074 * capability, an application signed with the older certificate will not be granted the 1075 * SIGNATURE permissions defined by this app. In addition, if multiple apps define the 1076 * same SIGNATURE permission, the second one the platform sees will not be installable 1077 * if this capability is not set and the signing certificates differ. 1078 */ setPermission(boolean enabled)1079 public Builder setPermission(boolean enabled) { 1080 mCallerConfiguredFlags |= PAST_CERT_PERMISSION; 1081 if (enabled) { 1082 mFlags |= PAST_CERT_PERMISSION; 1083 } else { 1084 mFlags &= ~PAST_CERT_PERMISSION; 1085 } 1086 return this; 1087 } 1088 1089 /** 1090 * Set the {@code PAST_CERT_ROLLBACK} flag in this capabilities object. This flag 1091 * is used by the platform to determine if this app is willing to upgrade to a new 1092 * version that is signed by one of its past signing certificates. 1093 * 1094 * <note> WARNING: this effectively removes any benefit of signing certificate changes, 1095 * since a compromised key could retake control of an app even after change, and should 1096 * only be used if there is a problem encountered when trying to ditch an older cert 1097 * </note> 1098 */ setRollback(boolean enabled)1099 public Builder setRollback(boolean enabled) { 1100 mCallerConfiguredFlags |= PAST_CERT_ROLLBACK; 1101 if (enabled) { 1102 mFlags |= PAST_CERT_ROLLBACK; 1103 } else { 1104 mFlags &= ~PAST_CERT_ROLLBACK; 1105 } 1106 return this; 1107 } 1108 1109 /** 1110 * Set the {@code PAST_CERT_AUTH} flag in this capabilities object. This flag 1111 * is used by the platform to determine whether or not privileged access based on 1112 * authenticator module signing certificates should be granted. 1113 */ setAuth(boolean enabled)1114 public Builder setAuth(boolean enabled) { 1115 mCallerConfiguredFlags |= PAST_CERT_AUTH; 1116 if (enabled) { 1117 mFlags |= PAST_CERT_AUTH; 1118 } else { 1119 mFlags &= ~PAST_CERT_AUTH; 1120 } 1121 return this; 1122 } 1123 1124 /** 1125 * Applies the capabilities that were explicitly set in the provided capabilities object 1126 * to this builder. Any values that were not set will not be applied to this builder 1127 * to prevent unintentinoally setting a capability back to a default value. 1128 */ setCallerConfiguredCapabilities(SignerCapabilities capabilities)1129 public Builder setCallerConfiguredCapabilities(SignerCapabilities capabilities) { 1130 // The mCallerConfiguredFlags should have a bit set for each capability that was 1131 // set by a caller. If a capability was explicitly set then the corresponding bit 1132 // in mCallerConfiguredFlags should be set. This allows the provided capabilities 1133 // to take effect for those set by the caller while those that were not set will 1134 // be cleared by the bitwise and and the initial value for the builder will remain. 1135 mFlags = (mFlags & ~capabilities.mCallerConfiguredFlags) | 1136 (capabilities.mFlags & capabilities.mCallerConfiguredFlags); 1137 return this; 1138 } 1139 1140 /** 1141 * Returns a new {@code SignerConfig} instance configured based on the configuration of 1142 * this builder. 1143 */ build()1144 public SignerCapabilities build() { 1145 return new SignerCapabilities(mFlags, mCallerConfiguredFlags); 1146 } 1147 } 1148 } 1149 1150 /** 1151 * Configuration of a signer. Used to add a new entry to the {@link SigningCertificateLineage} 1152 * 1153 * <p>Use {@link Builder} to obtain configuration instances. 1154 */ 1155 public static class SignerConfig { 1156 private final KeyConfig mKeyConfig; 1157 private final X509Certificate mCertificate; 1158 SignerConfig(KeyConfig keyConfig, X509Certificate certificate)1159 private SignerConfig(KeyConfig keyConfig, X509Certificate certificate) { 1160 mKeyConfig = keyConfig; 1161 mCertificate = certificate; 1162 } 1163 1164 /** 1165 * Returns the signing key of this signer. 1166 * 1167 * @deprecated Use {@link #getKeyConfig()} instead of accessing a {@link PrivateKey} 1168 * directly. If the user of ApkSigner is signing with a KMS instead of JCA, this method 1169 * will return null. 1170 */ 1171 @Deprecated getPrivateKey()1172 public PrivateKey getPrivateKey() { 1173 return mKeyConfig.match(jca -> jca.privateKey, kms -> null); 1174 } 1175 getKeyConfig()1176 public KeyConfig getKeyConfig() { 1177 return mKeyConfig; 1178 } 1179 1180 /** 1181 * Returns the certificate(s) of this signer. The first certificate's public key corresponds 1182 * to this signer's private key. 1183 */ getCertificate()1184 public X509Certificate getCertificate() { 1185 return mCertificate; 1186 } 1187 1188 /** 1189 * Builder of {@link SignerConfig} instances. 1190 */ 1191 public static class Builder { 1192 private final KeyConfig mKeyConfig; 1193 private final X509Certificate mCertificate; 1194 1195 /** 1196 * Constructs a new {@code Builder}. 1197 * 1198 * @deprecated use {@link #Builder(KeyConfig, X509Certificate)} instead 1199 * @param privateKey signing key 1200 * @param certificate the X.509 certificate with a subject public key of the {@code 1201 * privateKey}. 1202 */ 1203 @Deprecated Builder(PrivateKey privateKey, X509Certificate certificate)1204 public Builder(PrivateKey privateKey, X509Certificate certificate) { 1205 mKeyConfig = new KeyConfig.Jca(privateKey); 1206 mCertificate = certificate; 1207 } 1208 1209 /** 1210 * Constructs a new {@code Builder}. 1211 * 1212 * @param keyConfig signing key configuration 1213 * @param certificate the X.509 certificate with a subject public key of the {@code 1214 * privateKey}. 1215 */ Builder(KeyConfig keyConfig, X509Certificate certificate)1216 public Builder(KeyConfig keyConfig, X509Certificate certificate) { 1217 mKeyConfig = keyConfig; 1218 mCertificate = certificate; 1219 } 1220 1221 /** 1222 * Returns a new {@code SignerConfig} instance configured based on the configuration of 1223 * this builder. 1224 */ build()1225 public SignerConfig build() { 1226 return new SignerConfig(mKeyConfig, mCertificate); 1227 } 1228 } 1229 } 1230 1231 /** 1232 * Builder of {@link SigningCertificateLineage} instances. 1233 */ 1234 public static class Builder { 1235 private final SignerConfig mOriginalSignerConfig; 1236 private final SignerConfig mNewSignerConfig; 1237 private SignerCapabilities mOriginalCapabilities; 1238 private SignerCapabilities mNewCapabilities; 1239 private int mMinSdkVersion; 1240 /** 1241 * Constructs a new {@code Builder}. 1242 * 1243 * @param originalSignerConfig first signer in this lineage, parent of the next 1244 * @param newSignerConfig new signer in the lineage; the new signing key that the APK will 1245 * use 1246 */ Builder( SignerConfig originalSignerConfig, SignerConfig newSignerConfig)1247 public Builder( 1248 SignerConfig originalSignerConfig, 1249 SignerConfig newSignerConfig) { 1250 if (originalSignerConfig == null || newSignerConfig == null) { 1251 throw new NullPointerException("Can't pass null SignerConfigs when constructing a " 1252 + "new SigningCertificateLineage"); 1253 } 1254 mOriginalSignerConfig = originalSignerConfig; 1255 mNewSignerConfig = newSignerConfig; 1256 } 1257 1258 /** 1259 * Constructs a new {@code Builder} that is intended to create a {@code 1260 * SigningCertificateLineage} with a single signer in the signing history. 1261 * 1262 * @param originalSignerConfig first signer in this lineage 1263 */ Builder(SignerConfig originalSignerConfig)1264 public Builder(SignerConfig originalSignerConfig) { 1265 if (originalSignerConfig == null) { 1266 throw new NullPointerException("Can't pass null SignerConfigs when constructing a " 1267 + "new SigningCertificateLineage"); 1268 } 1269 mOriginalSignerConfig = originalSignerConfig; 1270 mNewSignerConfig = null; 1271 } 1272 1273 /** 1274 * Sets the minimum Android platform version (API Level) on which this lineage is expected 1275 * to validate. It is possible that newer signers in the lineage may not be recognized on 1276 * the given platform, but as long as an older signer is, the lineage can still be used to 1277 * sign an APK for the given platform. 1278 * 1279 * <note> By default, this value is set to the value for the 1280 * P release, since this structure was created for that release, and will also be set to 1281 * that value if a smaller one is specified. </note> 1282 */ setMinSdkVersion(int minSdkVersion)1283 public Builder setMinSdkVersion(int minSdkVersion) { 1284 mMinSdkVersion = minSdkVersion; 1285 return this; 1286 } 1287 1288 /** 1289 * Sets capabilities to give {@code mOriginalSignerConfig}. These capabilities allow an 1290 * older signing certificate to still be used in some situations on the platform even though 1291 * the APK is now being signed by a newer signing certificate. 1292 */ setOriginalCapabilities(SignerCapabilities signerCapabilities)1293 public Builder setOriginalCapabilities(SignerCapabilities signerCapabilities) { 1294 if (signerCapabilities == null) { 1295 throw new NullPointerException("signerCapabilities == null"); 1296 } 1297 mOriginalCapabilities = signerCapabilities; 1298 return this; 1299 } 1300 1301 /** 1302 * Sets capabilities to give {@code mNewSignerConfig}. These capabilities allow an 1303 * older signing certificate to still be used in some situations on the platform even though 1304 * the APK is now being signed by a newer signing certificate. By default, the new signer 1305 * will have all capabilities, so when first switching to a new signing certificate, these 1306 * capabilities have no effect, but they will act as the default level of trust when moving 1307 * to a new signing certificate. 1308 */ setNewCapabilities(SignerCapabilities signerCapabilities)1309 public Builder setNewCapabilities(SignerCapabilities signerCapabilities) { 1310 if (signerCapabilities == null) { 1311 throw new NullPointerException("signerCapabilities == null"); 1312 } 1313 mNewCapabilities = signerCapabilities; 1314 return this; 1315 } 1316 build()1317 public SigningCertificateLineage build() 1318 throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException, 1319 SignatureException { 1320 if (mMinSdkVersion < AndroidSdkVersion.P) { 1321 mMinSdkVersion = AndroidSdkVersion.P; 1322 } 1323 1324 if (mOriginalCapabilities == null) { 1325 mOriginalCapabilities = new SignerCapabilities.Builder().build(); 1326 } 1327 1328 if (mNewSignerConfig == null) { 1329 return createSigningLineage(mMinSdkVersion, mOriginalSignerConfig, 1330 mOriginalCapabilities); 1331 } 1332 1333 if (mNewCapabilities == null) { 1334 mNewCapabilities = new SignerCapabilities.Builder().build(); 1335 } 1336 1337 return createSigningLineage( 1338 mMinSdkVersion, mOriginalSignerConfig, mOriginalCapabilities, 1339 mNewSignerConfig, mNewCapabilities); 1340 } 1341 } 1342 } 1343