Search in sources :

Example 1 with Pair

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 });
}
Also used : PublicKey(java.security.PublicKey) ApkSigningBlockUtils.encodePublicKey(com.android.apksig.internal.apk.ApkSigningBlockUtils.encodePublicKey) ArrayList(java.util.ArrayList) CertificateEncodingException(java.security.cert.CertificateEncodingException) SignatureAlgorithm(com.android.apksig.internal.apk.SignatureAlgorithm) SignatureException(java.security.SignatureException) ContentDigestAlgorithm(com.android.apksig.internal.apk.ContentDigestAlgorithm) Pair(com.android.apksig.internal.util.Pair)

Example 2 with Pair

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;
}
Also used : InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) RSAPublicKey(com.android.apksig.internal.x509.RSAPublicKey) PublicKey(java.security.PublicKey) ArrayList(java.util.ArrayList) SignatureException(java.security.SignatureException) InvalidKeyException(java.security.InvalidKeyException) Signature(java.security.Signature) AlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec) Pair(com.android.apksig.internal.util.Pair)

Example 3 with Pair

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);
}
Also used : ArrayList(java.util.ArrayList) SignatureAlgorithm(com.android.apksig.internal.apk.SignatureAlgorithm) ApkSigningBlockUtils(com.android.apksig.internal.apk.ApkSigningBlockUtils) ByteBuffer(java.nio.ByteBuffer) X509Certificate(java.security.cert.X509Certificate) V3SigningCertificateLineage(com.android.apksig.internal.apk.v3.V3SigningCertificateLineage) SigningCertificateNode(com.android.apksig.internal.apk.v3.V3SigningCertificateLineage.SigningCertificateNode) Pair(com.android.apksig.internal.util.Pair)

Example 4 with Pair

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);
}
Also used : ArrayList(java.util.ArrayList) CertificateEncodingException(java.security.cert.CertificateEncodingException) SignatureException(java.security.SignatureException) ContentDigestAlgorithm(com.android.apksig.internal.apk.ContentDigestAlgorithm) Map(java.util.Map) Pair(com.android.apksig.internal.util.Pair)

Example 5 with Pair

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;
}
Also used : PublicKey(java.security.PublicKey) ArrayList(java.util.ArrayList) CertificateException(java.security.cert.CertificateException) SignatureException(java.security.SignatureException) InvalidKeyException(java.security.InvalidKeyException) Pair(com.android.apksig.internal.util.Pair)

Aggregations

Pair (com.android.apksig.internal.util.Pair)14 ArrayList (java.util.ArrayList)11 SignatureException (java.security.SignatureException)8 PublicKey (java.security.PublicKey)5 CertificateEncodingException (java.security.cert.CertificateEncodingException)5 ContentDigestAlgorithm (com.android.apksig.internal.apk.ContentDigestAlgorithm)4 ByteBuffer (java.nio.ByteBuffer)4 SignatureAlgorithm (com.android.apksig.internal.apk.SignatureAlgorithm)3 Map (java.util.Map)3 ApkSigningBlockUtils (com.android.apksig.internal.apk.ApkSigningBlockUtils)2 ApkSigningBlockUtils.encodePublicKey (com.android.apksig.internal.apk.ApkSigningBlockUtils.encodePublicKey)2 DataSource (com.android.apksig.util.DataSource)2 InvalidKeyException (java.security.InvalidKeyException)2 CertificateException (java.security.cert.CertificateException)2 X509Certificate (java.security.cert.X509Certificate)2 HashMap (java.util.HashMap)2 ApkFormatException (com.android.apksig.apk.ApkFormatException)1 ApkUtils (com.android.apksig.apk.ApkUtils)1 V1SchemeSigner (com.android.apksig.internal.apk.v1.V1SchemeSigner)1 V3SigningCertificateLineage (com.android.apksig.internal.apk.v3.V3SigningCertificateLineage)1