use of com.android.apksig.internal.util.Pair in project apksig by venshine.
the class V2SchemeSigner method generateSignerBlock.
private static byte[] generateSignerBlock(SignerConfig signerConfig, Map<ContentDigestAlgorithm, byte[]> contentDigests, boolean v3SigningEnabled) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
if (signerConfig.certificates.isEmpty()) {
throw new SignatureException("No certificates configured for signer");
}
PublicKey publicKey = signerConfig.certificates.get(0).getPublicKey();
byte[] encodedPublicKey = encodePublicKey(publicKey);
V2SignatureSchemeBlock.SignedData signedData = new V2SignatureSchemeBlock.SignedData();
try {
signedData.certificates = encodeCertificates(signerConfig.certificates);
} catch (CertificateEncodingException e) {
throw new SignatureException("Failed to encode certificates", e);
}
List<Pair<Integer, byte[]>> digests = new ArrayList<>(signerConfig.signatureAlgorithms.size());
for (SignatureAlgorithm signatureAlgorithm : signerConfig.signatureAlgorithms) {
ContentDigestAlgorithm contentDigestAlgorithm = signatureAlgorithm.getContentDigestAlgorithm();
byte[] contentDigest = contentDigests.get(contentDigestAlgorithm);
if (contentDigest == null) {
throw new RuntimeException(contentDigestAlgorithm + " content digest for " + signatureAlgorithm + " not computed");
}
digests.add(Pair.of(signatureAlgorithm.getId(), contentDigest));
}
signedData.digests = digests;
signedData.additionalAttributes = generateAdditionalAttributes(v3SigningEnabled);
V2SignatureSchemeBlock.Signer signer = new V2SignatureSchemeBlock.Signer();
// FORMAT:
// * length-prefixed sequence of length-prefixed digests:
// * uint32: signature algorithm ID
// * length-prefixed bytes: digest of contents
// * length-prefixed sequence of certificates:
// * length-prefixed bytes: X.509 certificate (ASN.1 DER encoded).
// * length-prefixed sequence of length-prefixed additional attributes:
// * uint32: ID
// * (length - 4) bytes: value
signer.signedData = encodeAsSequenceOfLengthPrefixedElements(new byte[][] { encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes(signedData.digests), encodeAsSequenceOfLengthPrefixedElements(signedData.certificates), signedData.additionalAttributes, new byte[0] });
signer.publicKey = encodedPublicKey;
signer.signatures = new ArrayList<>();
signer.signatures = ApkSigningBlockUtils.generateSignaturesOverData(signerConfig, signer.signedData);
// * length-prefixed bytes: public key (X.509 SubjectPublicKeyInfo, ASN.1 DER encoded)
return encodeAsSequenceOfLengthPrefixedElements(new byte[][] { signer.signedData, encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes(signer.signatures), signer.publicKey });
}
use of com.android.apksig.internal.util.Pair in project apksig by venshine.
the class ApkSigningBlockUtils method generateSignaturesOverData.
/**
* uses the SignatureAlgorithms in the provided signerConfig to sign the provided data
*
* @return list of signature algorithm IDs and their corresponding signatures over the data.
*/
public static List<Pair<Integer, byte[]>> generateSignaturesOverData(SignerConfig signerConfig, byte[] data) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
List<Pair<Integer, byte[]>> signatures = new ArrayList<>(signerConfig.signatureAlgorithms.size());
PublicKey publicKey = signerConfig.certificates.get(0).getPublicKey();
for (SignatureAlgorithm signatureAlgorithm : signerConfig.signatureAlgorithms) {
Pair<String, ? extends AlgorithmParameterSpec> sigAlgAndParams = signatureAlgorithm.getJcaSignatureAlgorithmAndParams();
String jcaSignatureAlgorithm = sigAlgAndParams.getFirst();
AlgorithmParameterSpec jcaSignatureAlgorithmParams = sigAlgAndParams.getSecond();
byte[] signatureBytes;
try {
Signature signature = Signature.getInstance(jcaSignatureAlgorithm);
signature.initSign(signerConfig.privateKey);
if (jcaSignatureAlgorithmParams != null) {
signature.setParameter(jcaSignatureAlgorithmParams);
}
signature.update(data);
signatureBytes = signature.sign();
} catch (InvalidKeyException e) {
throw new InvalidKeyException("Failed to sign using " + jcaSignatureAlgorithm, e);
} catch (InvalidAlgorithmParameterException | SignatureException e) {
throw new SignatureException("Failed to sign using " + jcaSignatureAlgorithm, e);
}
try {
Signature signature = Signature.getInstance(jcaSignatureAlgorithm);
signature.initVerify(publicKey);
if (jcaSignatureAlgorithmParams != null) {
signature.setParameter(jcaSignatureAlgorithmParams);
}
signature.update(data);
if (!signature.verify(signatureBytes)) {
throw new SignatureException("Failed to verify generated " + jcaSignatureAlgorithm + " signature using public key from certificate");
}
} catch (InvalidKeyException e) {
throw new InvalidKeyException("Failed to verify generated " + jcaSignatureAlgorithm + " signature using" + " public key from certificate", e);
} catch (InvalidAlgorithmParameterException | SignatureException e) {
throw new SignatureException("Failed to verify generated " + jcaSignatureAlgorithm + " signature using" + " public key from certificate", e);
}
signatures.add(Pair.of(signatureAlgorithm.getId(), signatureBytes));
}
return signatures;
}
use of com.android.apksig.internal.util.Pair in project apksig by venshine.
the class SigningCertificateLineage method spawnDescendant.
/**
* Add a new signing certificate to the lineage. This effectively creates a signing certificate
* rotation event, forcing APKs which include this lineage to be signed by the new signer.
*
* @param parent current signing certificate of the containing APK
* @param child new signing certificate which will sign the APK contents
* @param childCapabilities flags
*/
public SigningCertificateLineage spawnDescendant(SignerConfig parent, SignerConfig child, SignerCapabilities childCapabilities) throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException, SignatureException {
if (parent == null) {
throw new NullPointerException("parent == null");
}
if (child == null) {
throw new NullPointerException("child == null");
}
if (childCapabilities == null) {
throw new NullPointerException("childCapabilities == null");
}
if (mSigningLineage.isEmpty()) {
throw new IllegalArgumentException("Cannot spawn descendant signing certificate on an" + " empty SigningCertificateLineage: no parent node");
}
// make sure that the parent matches our newest generation (leaf node/sink)
SigningCertificateNode currentGeneration = mSigningLineage.get(mSigningLineage.size() - 1);
if (!Arrays.equals(currentGeneration.signingCert.getEncoded(), parent.getCertificate().getEncoded())) {
throw new IllegalArgumentException("SignerConfig Certificate containing private key" + " to sign the new SigningCertificateLineage record does not match the" + " existing most recent record");
}
// create data to be signed, including the algorithm we're going to use
SignatureAlgorithm signatureAlgorithm = getSignatureAlgorithm(parent);
ByteBuffer prefixedSignedData = ByteBuffer.wrap(V3SigningCertificateLineage.encodeSignedData(child.getCertificate(), signatureAlgorithm.getId()));
prefixedSignedData.position(4);
ByteBuffer signedDataBuffer = ByteBuffer.allocate(prefixedSignedData.remaining());
signedDataBuffer.put(prefixedSignedData);
byte[] signedData = signedDataBuffer.array();
// create SignerConfig to do the signing
List<X509Certificate> certificates = new ArrayList<>(1);
certificates.add(parent.getCertificate());
ApkSigningBlockUtils.SignerConfig newSignerConfig = new ApkSigningBlockUtils.SignerConfig();
newSignerConfig.privateKey = parent.getPrivateKey();
newSignerConfig.certificates = certificates;
newSignerConfig.signatureAlgorithms = Collections.singletonList(signatureAlgorithm);
// sign it
List<Pair<Integer, byte[]>> signatures = ApkSigningBlockUtils.generateSignaturesOverData(newSignerConfig, signedData);
// finally, add it to our lineage
SignatureAlgorithm sigAlgorithm = SignatureAlgorithm.findById(signatures.get(0).getFirst());
byte[] signature = signatures.get(0).getSecond();
currentGeneration.sigAlgorithm = sigAlgorithm;
SigningCertificateNode childNode = new SigningCertificateNode(child.getCertificate(), sigAlgorithm, null, signature, childCapabilities.getFlags());
List<SigningCertificateNode> lineageCopy = new ArrayList<>(mSigningLineage);
lineageCopy.add(childNode);
return new SigningCertificateLineage(mMinSdkVersion, lineageCopy);
}
use of com.android.apksig.internal.util.Pair in project apksig by venshine.
the class V1SourceStampSigner method generateSourceStampBlock.
public static Pair<byte[], Integer> generateSourceStampBlock(SignerConfig sourceStampSignerConfig, Map<ContentDigestAlgorithm, byte[]> digestInfo) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
if (sourceStampSignerConfig.certificates.isEmpty()) {
throw new SignatureException("No certificates configured for signer");
}
List<Pair<Integer, byte[]>> digests = new ArrayList<>();
for (Map.Entry<ContentDigestAlgorithm, byte[]> digest : digestInfo.entrySet()) {
digests.add(Pair.of(digest.getKey().getId(), digest.getValue()));
}
Collections.sort(digests, Comparator.comparing(Pair::getFirst));
SourceStampBlock sourceStampBlock = new SourceStampBlock();
try {
sourceStampBlock.stampCertificate = sourceStampSignerConfig.certificates.get(0).getEncoded();
} catch (CertificateEncodingException e) {
throw new SignatureException("Retrieving the encoded form of the stamp certificate failed", e);
}
byte[] digestBytes = encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes(digests);
sourceStampBlock.signedDigests = ApkSigningBlockUtils.generateSignaturesOverData(sourceStampSignerConfig, digestBytes);
// FORMAT:
// * length-prefixed bytes: X.509 certificate (ASN.1 DER encoded)
// * length-prefixed sequence of length-prefixed signatures:
// * uint32: signature algorithm ID
// * length-prefixed bytes: signature of signed data
byte[] sourceStampSignerBlock = encodeAsSequenceOfLengthPrefixedElements(new byte[][] { sourceStampBlock.stampCertificate, encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes(sourceStampBlock.signedDigests) });
// * length-prefixed stamp block.
return Pair.of(encodeAsLengthPrefixedElement(sourceStampSignerBlock), SourceStampConstants.V1_SOURCE_STAMP_BLOCK_ID);
}
use of com.android.apksig.internal.util.Pair in project apksig by venshine.
the class V1SchemeSigner method signManifest.
/**
* Signs the provided APK using JAR signing (aka v1 signature scheme) and returns the list of
* JAR entries which need to be added to the APK as part of the signature.
*
* @param signerConfigs signer configurations, one for each signer. At least one signer config
* must be provided.
*
* @throws InvalidKeyException if a signing key is not suitable for this signature scheme or
* cannot be used in general
* @throws SignatureException if an error occurs when computing digests of generating
* signatures
*/
public static List<Pair<String, byte[]>> signManifest(List<SignerConfig> signerConfigs, DigestAlgorithm digestAlgorithm, List<Integer> apkSigningSchemeIds, String createdBy, OutputManifestFile manifest) throws NoSuchAlgorithmException, InvalidKeyException, CertificateException, SignatureException {
if (signerConfigs.isEmpty()) {
throw new IllegalArgumentException("At least one signer config must be provided");
}
// For each signer output .SF and .(RSA|DSA|EC) file, then output MANIFEST.MF.
List<Pair<String, byte[]>> signatureJarEntries = new ArrayList<>(2 * signerConfigs.size() + 1);
byte[] sfBytes = generateSignatureFile(apkSigningSchemeIds, digestAlgorithm, createdBy, manifest);
for (SignerConfig signerConfig : signerConfigs) {
String signerName = signerConfig.name;
byte[] signatureBlock;
try {
signatureBlock = generateSignatureBlock(signerConfig, sfBytes);
} catch (InvalidKeyException e) {
throw new InvalidKeyException("Failed to sign using signer \"" + signerName + "\"", e);
} catch (CertificateException e) {
throw new CertificateException("Failed to sign using signer \"" + signerName + "\"", e);
} catch (SignatureException e) {
throw new SignatureException("Failed to sign using signer \"" + signerName + "\"", e);
}
signatureJarEntries.add(Pair.of("META-INF/" + signerName + ".SF", sfBytes));
PublicKey publicKey = signerConfig.certificates.get(0).getPublicKey();
String signatureBlockFileName = "META-INF/" + signerName + "." + publicKey.getAlgorithm().toUpperCase(Locale.US);
signatureJarEntries.add(Pair.of(signatureBlockFileName, signatureBlock));
}
signatureJarEntries.add(Pair.of(V1SchemeConstants.MANIFEST_ENTRY_NAME, manifest.contents));
return signatureJarEntries;
}
Aggregations