Search in sources :

Example 1 with SignatureAlgorithm

use of com.android.apksig.internal.apk.SignatureAlgorithm 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 SignatureAlgorithm

use of com.android.apksig.internal.apk.SignatureAlgorithm 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 3 with SignatureAlgorithm

use of com.android.apksig.internal.apk.SignatureAlgorithm in project apksig by venshine.

the class SigningCertificateLineage method getSignatureAlgorithm.

private SignatureAlgorithm getSignatureAlgorithm(SignerConfig parent) throws InvalidKeyException {
    PublicKey publicKey = parent.getCertificate().getPublicKey();
    // TODO switch to one signature algorithm selection, or add support for multiple algorithms
    List<SignatureAlgorithm> algorithms = V3SchemeSigner.getSuggestedSignatureAlgorithms(publicKey, mMinSdkVersion, false, /* verityEnabled */
    false);
    return algorithms.get(0);
}
Also used : PublicKey(java.security.PublicKey) SignatureAlgorithm(com.android.apksig.internal.apk.SignatureAlgorithm)

Example 4 with SignatureAlgorithm

use of com.android.apksig.internal.apk.SignatureAlgorithm in project apksig by venshine.

the class SourceStampCertificateLineage method readSigningCertificateLineage.

/**
 * Deserializes the binary representation of a SourceStampCertificateLineage. Also
 * verifies that the structure is well-formed, e.g. that the signature for each node is from its
 * parent.
 */
public static List<SigningCertificateNode> readSigningCertificateLineage(ByteBuffer inputBytes) throws IOException {
    List<SigningCertificateNode> result = new ArrayList<>();
    int nodeCount = 0;
    if (inputBytes == null || !inputBytes.hasRemaining()) {
        return null;
    }
    ApkSigningBlockUtilsLite.checkByteOrderLittleEndian(inputBytes);
    CertificateFactory certFactory;
    try {
        certFactory = CertificateFactory.getInstance("X.509");
    } catch (CertificateException e) {
        throw new IllegalStateException("Failed to obtain X.509 CertificateFactory", e);
    }
    // FORMAT (little endian):
    // * uint32: version code
    // * sequence of length-prefixed (uint32): nodes
    // * length-prefixed bytes: signed data
    // * length-prefixed bytes: certificate
    // * uint32: signature algorithm id
    // * uint32: flags
    // * uint32: signature algorithm id (used by to sign next cert in lineage)
    // * length-prefixed bytes: signature over above signed data
    X509Certificate lastCert = null;
    int lastSigAlgorithmId = 0;
    try {
        int version = inputBytes.getInt();
        if (version != CURRENT_VERSION) {
            // we only have one version to worry about right now, so just check it
            throw new IllegalArgumentException("Encoded SigningCertificateLineage has a version" + " different than any of which we are aware");
        }
        HashSet<X509Certificate> certHistorySet = new HashSet<>();
        while (inputBytes.hasRemaining()) {
            nodeCount++;
            ByteBuffer nodeBytes = getLengthPrefixedSlice(inputBytes);
            ByteBuffer signedData = getLengthPrefixedSlice(nodeBytes);
            int flags = nodeBytes.getInt();
            int sigAlgorithmId = nodeBytes.getInt();
            SignatureAlgorithm sigAlgorithm = SignatureAlgorithm.findById(lastSigAlgorithmId);
            byte[] signature = readLengthPrefixedByteArray(nodeBytes);
            if (lastCert != null) {
                // Use previous level cert to verify current level
                String jcaSignatureAlgorithm = sigAlgorithm.getJcaSignatureAlgorithmAndParams().getFirst();
                AlgorithmParameterSpec jcaSignatureAlgorithmParams = sigAlgorithm.getJcaSignatureAlgorithmAndParams().getSecond();
                PublicKey publicKey = lastCert.getPublicKey();
                Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
                sig.initVerify(publicKey);
                if (jcaSignatureAlgorithmParams != null) {
                    sig.setParameter(jcaSignatureAlgorithmParams);
                }
                sig.update(signedData);
                if (!sig.verify(signature)) {
                    throw new SecurityException("Unable to verify signature of certificate #" + nodeCount + " using " + jcaSignatureAlgorithm + " when verifying" + " SourceStampCertificateLineage object");
                }
            }
            signedData.rewind();
            byte[] encodedCert = readLengthPrefixedByteArray(signedData);
            int signedSigAlgorithm = signedData.getInt();
            if (lastCert != null && lastSigAlgorithmId != signedSigAlgorithm) {
                throw new SecurityException("Signing algorithm ID mismatch for certificate #" + nodeBytes + " when verifying SourceStampCertificateLineage object");
            }
            lastCert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
            lastCert = new GuaranteedEncodedFormX509Certificate(lastCert, encodedCert);
            if (certHistorySet.contains(lastCert)) {
                throw new SecurityException("Encountered duplicate entries in " + "SigningCertificateLineage at certificate #" + nodeCount + ".  All " + "signing certificates should be unique");
            }
            certHistorySet.add(lastCert);
            lastSigAlgorithmId = sigAlgorithmId;
            result.add(new SigningCertificateNode(lastCert, SignatureAlgorithm.findById(signedSigAlgorithm), SignatureAlgorithm.findById(sigAlgorithmId), signature, flags));
        }
    } catch (ApkFormatException | BufferUnderflowException e) {
        throw new IOException("Failed to parse SourceStampCertificateLineage object", e);
    } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | SignatureException e) {
        throw new SecurityException("Failed to verify signature over signed data for certificate #" + nodeCount + " when parsing SourceStampCertificateLineage object", e);
    } catch (CertificateException e) {
        throw new SecurityException("Failed to decode certificate #" + nodeCount + " when parsing SourceStampCertificateLineage object", e);
    }
    return result;
}
Also used : GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) ArrayList(java.util.ArrayList) CertificateException(java.security.cert.CertificateException) SignatureAlgorithm(com.android.apksig.internal.apk.SignatureAlgorithm) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SignatureException(java.security.SignatureException) CertificateFactory(java.security.cert.CertificateFactory) ApkFormatException(com.android.apksig.apk.ApkFormatException) BufferUnderflowException(java.nio.BufferUnderflowException) HashSet(java.util.HashSet) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) PublicKey(java.security.PublicKey) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) ByteBuffer(java.nio.ByteBuffer) X509Certificate(java.security.cert.X509Certificate) GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) ByteArrayInputStream(java.io.ByteArrayInputStream) Signature(java.security.Signature) AlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec)

Example 5 with SignatureAlgorithm

use of com.android.apksig.internal.apk.SignatureAlgorithm in project apksig by venshine.

the class SourceStampVerifier method verifySourceStampSignature.

private static void verifySourceStampSignature(byte[] data, int minSdkVersion, int maxSdkVersion, X509Certificate sourceStampCertificate, ByteBuffer signatures, ApkSignerInfo result) {
    // Parse the signatures block and identify supported signatures
    int signatureCount = 0;
    List<ApkSupportedSignature> supportedSignatures = new ArrayList<>(1);
    while (signatures.hasRemaining()) {
        signatureCount++;
        try {
            ByteBuffer signature = getLengthPrefixedSlice(signatures);
            int sigAlgorithmId = signature.getInt();
            byte[] sigBytes = readLengthPrefixedByteArray(signature);
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.findById(sigAlgorithmId);
            if (signatureAlgorithm == null) {
                result.addWarning(ApkVerificationIssue.SOURCE_STAMP_UNKNOWN_SIG_ALGORITHM, sigAlgorithmId);
                continue;
            }
            supportedSignatures.add(new ApkSupportedSignature(signatureAlgorithm, sigBytes));
        } catch (ApkFormatException | BufferUnderflowException e) {
            result.addWarning(ApkVerificationIssue.SOURCE_STAMP_MALFORMED_SIGNATURE, signatureCount);
            return;
        }
    }
    if (supportedSignatures.isEmpty()) {
        result.addWarning(ApkVerificationIssue.SOURCE_STAMP_NO_SIGNATURE);
        return;
    }
    // Verify signatures over digests using the SourceStamp's certificate.
    List<ApkSupportedSignature> signaturesToVerify;
    try {
        signaturesToVerify = getSignaturesToVerify(supportedSignatures, minSdkVersion, maxSdkVersion, true);
    } catch (NoApkSupportedSignaturesException e) {
        // To facilitate debugging capture the signature algorithms and resulting exception in
        // the warning.
        StringBuilder signatureAlgorithms = new StringBuilder();
        for (ApkSupportedSignature supportedSignature : supportedSignatures) {
            if (signatureAlgorithms.length() > 0) {
                signatureAlgorithms.append(", ");
            }
            signatureAlgorithms.append(supportedSignature.algorithm);
        }
        result.addWarning(ApkVerificationIssue.SOURCE_STAMP_NO_SUPPORTED_SIGNATURE, signatureAlgorithms.toString(), e);
        return;
    }
    for (ApkSupportedSignature signature : signaturesToVerify) {
        SignatureAlgorithm signatureAlgorithm = signature.algorithm;
        String jcaSignatureAlgorithm = signatureAlgorithm.getJcaSignatureAlgorithmAndParams().getFirst();
        AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithm.getJcaSignatureAlgorithmAndParams().getSecond();
        PublicKey publicKey = sourceStampCertificate.getPublicKey();
        try {
            Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
            sig.initVerify(publicKey);
            if (jcaSignatureAlgorithmParams != null) {
                sig.setParameter(jcaSignatureAlgorithmParams);
            }
            sig.update(data);
            byte[] sigBytes = signature.signature;
            if (!sig.verify(sigBytes)) {
                result.addWarning(ApkVerificationIssue.SOURCE_STAMP_DID_NOT_VERIFY, signatureAlgorithm);
                return;
            }
        } catch (InvalidKeyException | InvalidAlgorithmParameterException | SignatureException | NoSuchAlgorithmException e) {
            result.addWarning(ApkVerificationIssue.SOURCE_STAMP_VERIFY_EXCEPTION, signatureAlgorithm, e);
            return;
        }
    }
}
Also used : InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) PublicKey(java.security.PublicKey) ArrayList(java.util.ArrayList) SignatureAlgorithm(com.android.apksig.internal.apk.SignatureAlgorithm) SignatureException(java.security.SignatureException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) ByteBuffer(java.nio.ByteBuffer) ApkSupportedSignature(com.android.apksig.internal.apk.ApkSupportedSignature) ApkFormatException(com.android.apksig.apk.ApkFormatException) ApkSupportedSignature(com.android.apksig.internal.apk.ApkSupportedSignature) Signature(java.security.Signature) NoApkSupportedSignaturesException(com.android.apksig.internal.apk.NoApkSupportedSignaturesException) AlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec) BufferUnderflowException(java.nio.BufferUnderflowException)

Aggregations

SignatureAlgorithm (com.android.apksig.internal.apk.SignatureAlgorithm)14 PublicKey (java.security.PublicKey)9 SignatureException (java.security.SignatureException)9 ArrayList (java.util.ArrayList)8 ApkSigningBlockUtils (com.android.apksig.internal.apk.ApkSigningBlockUtils)7 ByteBuffer (java.nio.ByteBuffer)7 X509Certificate (java.security.cert.X509Certificate)7 ApkFormatException (com.android.apksig.apk.ApkFormatException)6 GuaranteedEncodedFormX509Certificate (com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate)6 BufferUnderflowException (java.nio.BufferUnderflowException)6 InvalidAlgorithmParameterException (java.security.InvalidAlgorithmParameterException)6 InvalidKeyException (java.security.InvalidKeyException)6 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)6 Signature (java.security.Signature)6 CertificateException (java.security.cert.CertificateException)6 AlgorithmParameterSpec (java.security.spec.AlgorithmParameterSpec)6 ContentDigestAlgorithm (com.android.apksig.internal.apk.ContentDigestAlgorithm)5 IOException (java.io.IOException)5 HashSet (java.util.HashSet)4 Pair (com.android.apksig.internal.util.Pair)3