Search in sources :

Example 1 with Asn1EncodingException

use of com.android.apksig.internal.asn1.Asn1EncodingException in project apksig by venshine.

the class V1SchemeSigner method generateSignatureBlock.

/**
 * Generates the CMS PKCS #7 signature block corresponding to the provided signature file and
 * signing configuration.
 */
private static byte[] generateSignatureBlock(SignerConfig signerConfig, byte[] signatureFileBytes) throws NoSuchAlgorithmException, InvalidKeyException, CertificateException, SignatureException {
    // Obtain relevant bits of signing configuration
    List<X509Certificate> signerCerts = signerConfig.certificates;
    X509Certificate signingCert = signerCerts.get(0);
    PublicKey publicKey = signingCert.getPublicKey();
    DigestAlgorithm digestAlgorithm = signerConfig.signatureDigestAlgorithm;
    Pair<String, AlgorithmIdentifier> signatureAlgs = getSignerInfoSignatureAlgorithm(publicKey, digestAlgorithm, signerConfig.deterministicDsaSigning);
    String jcaSignatureAlgorithm = signatureAlgs.getFirst();
    // Generate the cryptographic signature of the signature file
    byte[] signatureBytes;
    try {
        Signature signature = Signature.getInstance(jcaSignatureAlgorithm);
        signature.initSign(signerConfig.privateKey);
        signature.update(signatureFileBytes);
        signatureBytes = signature.sign();
    } catch (InvalidKeyException e) {
        throw new InvalidKeyException("Failed to sign using " + jcaSignatureAlgorithm, e);
    } catch (SignatureException e) {
        throw new SignatureException("Failed to sign using " + jcaSignatureAlgorithm, e);
    }
    // Verify the signature against the public key in the signing certificate
    try {
        Signature signature = Signature.getInstance(jcaSignatureAlgorithm);
        signature.initVerify(publicKey);
        signature.update(signatureFileBytes);
        if (!signature.verify(signatureBytes)) {
            throw new SignatureException("Signature did not verify");
        }
    } catch (InvalidKeyException e) {
        throw new InvalidKeyException("Failed to verify generated " + jcaSignatureAlgorithm + " signature using" + " public key from certificate", e);
    } catch (SignatureException e) {
        throw new SignatureException("Failed to verify generated " + jcaSignatureAlgorithm + " signature using" + " public key from certificate", e);
    }
    AlgorithmIdentifier digestAlgorithmId = getSignerInfoDigestAlgorithmOid(digestAlgorithm);
    AlgorithmIdentifier signatureAlgorithmId = signatureAlgs.getSecond();
    try {
        return ApkSigningBlockUtils.generatePkcs7DerEncodedMessage(signatureBytes, null, signerCerts, digestAlgorithmId, signatureAlgorithmId);
    } catch (Asn1EncodingException | CertificateEncodingException ex) {
        throw new SignatureException("Failed to encode signature block");
    }
}
Also used : Asn1EncodingException(com.android.apksig.internal.asn1.Asn1EncodingException) PublicKey(java.security.PublicKey) CertificateEncodingException(java.security.cert.CertificateEncodingException) SignatureException(java.security.SignatureException) InvalidKeyException(java.security.InvalidKeyException) X509Certificate(java.security.cert.X509Certificate) AlgorithmIdentifier(com.android.apksig.internal.pkcs7.AlgorithmIdentifier) Signature(java.security.Signature)

Example 2 with Asn1EncodingException

use of com.android.apksig.internal.asn1.Asn1EncodingException in project apksig by venshine.

the class ApkSigningBlockUtils method encodePublicKey.

public static byte[] encodePublicKey(PublicKey publicKey) throws InvalidKeyException, NoSuchAlgorithmException {
    byte[] encodedPublicKey = null;
    if ("X.509".equals(publicKey.getFormat())) {
        encodedPublicKey = publicKey.getEncoded();
        // if the key is an RSA key check for a negative modulus
        String keyAlgorithm = publicKey.getAlgorithm();
        if ("RSA".equals(keyAlgorithm) || OID_RSA_ENCRYPTION.equals(keyAlgorithm)) {
            try {
                // Parse the encoded public key into the separate elements of the
                // SubjectPublicKeyInfo to obtain the SubjectPublicKey.
                ByteBuffer encodedPublicKeyBuffer = ByteBuffer.wrap(encodedPublicKey);
                SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(encodedPublicKeyBuffer, SubjectPublicKeyInfo.class);
                // The SubjectPublicKey is encoded as a bit string within the
                // SubjectPublicKeyInfo. The first byte of the encoding is the number of padding
                // bits; store this and decode the rest of the bit string into the RSA modulus
                // and exponent.
                ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
                byte padding = subjectPublicKeyBuffer.get();
                RSAPublicKey rsaPublicKey = Asn1BerParser.parse(subjectPublicKeyBuffer, RSAPublicKey.class);
                // byte.
                if (rsaPublicKey.modulus.compareTo(BigInteger.ZERO) < 0) {
                    // A negative modulus indicates the leading bit in the integer is 1. Per
                    // ASN.1 encoding rules to encode a positive integer with the leading bit
                    // set to 1 a byte containing all zeros should precede the integer encoding.
                    byte[] encodedModulus = rsaPublicKey.modulus.toByteArray();
                    byte[] reencodedModulus = new byte[encodedModulus.length + 1];
                    reencodedModulus[0] = 0;
                    System.arraycopy(encodedModulus, 0, reencodedModulus, 1, encodedModulus.length);
                    rsaPublicKey.modulus = new BigInteger(reencodedModulus);
                    // Once the modulus has been corrected reencode the RSAPublicKey, then
                    // restore the padding value in the bit string and reencode the entire
                    // SubjectPublicKeyInfo to be returned to the caller.
                    byte[] reencodedRSAPublicKey = Asn1DerEncoder.encode(rsaPublicKey);
                    byte[] reencodedSubjectPublicKey = new byte[reencodedRSAPublicKey.length + 1];
                    reencodedSubjectPublicKey[0] = padding;
                    System.arraycopy(reencodedRSAPublicKey, 0, reencodedSubjectPublicKey, 1, reencodedRSAPublicKey.length);
                    subjectPublicKeyInfo.subjectPublicKey = ByteBuffer.wrap(reencodedSubjectPublicKey);
                    encodedPublicKey = Asn1DerEncoder.encode(subjectPublicKeyInfo);
                }
            } catch (Asn1DecodingException | Asn1EncodingException e) {
                System.out.println("Caught a exception encoding the public key: " + e);
                e.printStackTrace();
                encodedPublicKey = null;
            }
        }
    }
    if (encodedPublicKey == null) {
        try {
            encodedPublicKey = KeyFactory.getInstance(publicKey.getAlgorithm()).getKeySpec(publicKey, X509EncodedKeySpec.class).getEncoded();
        } catch (InvalidKeySpecException e) {
            throw new InvalidKeyException("Failed to obtain X.509 encoded form of public key " + publicKey + " of class " + publicKey.getClass().getName(), e);
        }
    }
    if ((encodedPublicKey == null) || (encodedPublicKey.length == 0)) {
        throw new InvalidKeyException("Failed to obtain X.509 encoded form of public key " + publicKey + " of class " + publicKey.getClass().getName());
    }
    return encodedPublicKey;
}
Also used : Asn1EncodingException(com.android.apksig.internal.asn1.Asn1EncodingException) RSAPublicKey(com.android.apksig.internal.x509.RSAPublicKey) Asn1DecodingException(com.android.apksig.internal.asn1.Asn1DecodingException) BigInteger(java.math.BigInteger) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) InvalidKeyException(java.security.InvalidKeyException) ByteBuffer(java.nio.ByteBuffer) SubjectPublicKeyInfo(com.android.apksig.internal.x509.SubjectPublicKeyInfo)

Example 3 with Asn1EncodingException

use of com.android.apksig.internal.asn1.Asn1EncodingException in project apksig by venshine.

the class X509CertificateUtils method generateCertificates.

/**
 * Generates a {@code Collection} of {@code Certificate} objects from the encoded {@code
 * InputStream} using the provided {@code CertificateFactory}.
 *
 * @throws CertificateException if the InputStream cannot be decoded to zero or more valid
 *                              {@code Certificates} objects.
 */
public static Collection<? extends java.security.cert.Certificate> generateCertificates(InputStream in, CertificateFactory certFactory) throws CertificateException {
    // Since the InputStream is not guaranteed to support mark / reset operations first read it
    // into a byte array to allow using the BER parser / DER encoder if it cannot be read by
    // the CertificateFactory.
    byte[] encodedCerts;
    try {
        encodedCerts = ByteStreams.toByteArray(in);
    } catch (IOException e) {
        throw new CertificateException("Failed to read the input stream", e);
    }
    try {
        return certFactory.generateCertificates(new ByteArrayInputStream(encodedCerts));
    } catch (CertificateException e) {
    // This could be expected if the certificates are encoded using a BER encoding that does
    // not use the minimum number of bytes to represent the length of the contents; attempt
    // to decode the certificates using the BER parser and re-encode using the DER encoder
    // below.
    }
    try {
        Collection<X509Certificate> certificates = new ArrayList<>(1);
        ByteBuffer encodedCertsBuffer = ByteBuffer.wrap(encodedCerts);
        while (encodedCertsBuffer.hasRemaining()) {
            ByteBuffer certBuffer = getNextDEREncodedCertificateBlock(encodedCertsBuffer);
            int startingPos = certBuffer.position();
            Certificate reencodedCert = Asn1BerParser.parse(certBuffer, Certificate.class);
            byte[] reencodedForm = Asn1DerEncoder.encode(reencodedCert);
            X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(reencodedForm));
            byte[] originalEncoding = new byte[certBuffer.position() - startingPos];
            certBuffer.position(startingPos);
            certBuffer.get(originalEncoding);
            GuaranteedEncodedFormX509Certificate guaranteedEncodedCert = new GuaranteedEncodedFormX509Certificate(certificate, originalEncoding);
            certificates.add(guaranteedEncodedCert);
        }
        return certificates;
    } catch (Asn1DecodingException | Asn1EncodingException e) {
        throw new CertificateException("Failed to parse certificates", e);
    }
}
Also used : Asn1EncodingException(com.android.apksig.internal.asn1.Asn1EncodingException) ArrayList(java.util.ArrayList) CertificateException(java.security.cert.CertificateException) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) X509Certificate(java.security.cert.X509Certificate) ByteArrayInputStream(java.io.ByteArrayInputStream) Asn1DecodingException(com.android.apksig.internal.asn1.Asn1DecodingException) X509Certificate(java.security.cert.X509Certificate) Certificate(com.android.apksig.internal.x509.Certificate)

Example 4 with Asn1EncodingException

use of com.android.apksig.internal.asn1.Asn1EncodingException in project apksig by venshine.

the class X509CertificateUtils method generateCertificate.

/**
 * Generates an {@code X509Certificate} from the encoded form using the provided
 * {@code CertificateFactory}.
 *
 * @throws CertificateException if the encodedForm cannot be decoded to a valid certificate.
 */
public static X509Certificate generateCertificate(byte[] encodedForm, CertificateFactory certFactory) throws CertificateException {
    X509Certificate certificate;
    try {
        certificate = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(encodedForm));
        return certificate;
    } catch (CertificateException e) {
    // This could be expected if the certificate is encoded using a BER encoding that does
    // not use the minimum number of bytes to represent the length of the contents; attempt
    // to decode the certificate using the BER parser and re-encode using the DER encoder
    // below.
    }
    try {
        // Some apps were previously signed with a BER encoded certificate that now results
        // in exceptions from the CertificateFactory generateCertificate(s) methods. Since
        // the original BER encoding of the certificate is used as the signature for these
        // apps that original encoding must be maintained when signing updated versions of
        // these apps and any new apps that may require capabilities guarded by the
        // signature. To maintain the same signature the BER parser can be used to parse
        // the certificate, then it can be re-encoded to its DER equivalent which is
        // accepted by the generateCertificate method. The positions in the ByteBuffer can
        // then be used with the GuaranteedEncodedFormX509Certificate object to ensure the
        // getEncoded method returns the original signature of the app.
        ByteBuffer encodedCertBuffer = getNextDEREncodedCertificateBlock(ByteBuffer.wrap(encodedForm));
        int startingPos = encodedCertBuffer.position();
        Certificate reencodedCert = Asn1BerParser.parse(encodedCertBuffer, Certificate.class);
        byte[] reencodedForm = Asn1DerEncoder.encode(reencodedCert);
        certificate = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(reencodedForm));
        // If the reencodedForm is successfully accepted by the CertificateFactory then copy the
        // original encoding from the ByteBuffer and use that encoding in the Guaranteed object.
        byte[] originalEncoding = new byte[encodedCertBuffer.position() - startingPos];
        encodedCertBuffer.position(startingPos);
        encodedCertBuffer.get(originalEncoding);
        GuaranteedEncodedFormX509Certificate guaranteedEncodedCert = new GuaranteedEncodedFormX509Certificate(certificate, originalEncoding);
        return guaranteedEncodedCert;
    } catch (Asn1DecodingException | Asn1EncodingException | CertificateException e) {
        throw new CertificateException("Failed to parse certificate", e);
    }
}
Also used : Asn1EncodingException(com.android.apksig.internal.asn1.Asn1EncodingException) ByteArrayInputStream(java.io.ByteArrayInputStream) Asn1DecodingException(com.android.apksig.internal.asn1.Asn1DecodingException) CertificateException(java.security.cert.CertificateException) ByteBuffer(java.nio.ByteBuffer) X509Certificate(java.security.cert.X509Certificate) X509Certificate(java.security.cert.X509Certificate) Certificate(com.android.apksig.internal.x509.Certificate)

Example 5 with Asn1EncodingException

use of com.android.apksig.internal.asn1.Asn1EncodingException in project apksig by venshine.

the class ApkSigningBlockUtils method generatePkcs7DerEncodedMessage.

/**
 * Wrap the signature according to CMS PKCS #7 RFC 5652.
 * The high-level simplified structure is as follows:
 * // ContentInfo
 *     //   digestAlgorithm
 *     //   SignedData
 *     //     bag of certificates
 *     //     SignerInfo
 *     //       signing cert issuer and serial number (for locating the cert in the above bag)
 *     //       digestAlgorithm
 *     //       signatureAlgorithm
 *     //       signature
 *
 * @throws Asn1EncodingException if the ASN.1 structure could not be encoded
 */
public static byte[] generatePkcs7DerEncodedMessage(byte[] signatureBytes, ByteBuffer data, List<X509Certificate> signerCerts, AlgorithmIdentifier digestAlgorithmId, AlgorithmIdentifier signatureAlgorithmId) throws Asn1EncodingException, CertificateEncodingException {
    SignerInfo signerInfo = new SignerInfo();
    signerInfo.version = 1;
    X509Certificate signingCert = signerCerts.get(0);
    X500Principal signerCertIssuer = signingCert.getIssuerX500Principal();
    signerInfo.sid = new SignerIdentifier(new IssuerAndSerialNumber(new Asn1OpaqueObject(signerCertIssuer.getEncoded()), signingCert.getSerialNumber()));
    signerInfo.digestAlgorithm = digestAlgorithmId;
    signerInfo.signatureAlgorithm = signatureAlgorithmId;
    signerInfo.signature = ByteBuffer.wrap(signatureBytes);
    SignedData signedData = new SignedData();
    signedData.certificates = new ArrayList<>(signerCerts.size());
    for (X509Certificate cert : signerCerts) {
        signedData.certificates.add(new Asn1OpaqueObject(cert.getEncoded()));
    }
    signedData.version = 1;
    signedData.digestAlgorithms = Collections.singletonList(digestAlgorithmId);
    signedData.encapContentInfo = new EncapsulatedContentInfo(Pkcs7Constants.OID_DATA);
    // If data is not null, data will be embedded as is in the result -- an attached pcsk7
    signedData.encapContentInfo.content = data;
    signedData.signerInfos = Collections.singletonList(signerInfo);
    ContentInfo contentInfo = new ContentInfo();
    contentInfo.contentType = Pkcs7Constants.OID_SIGNED_DATA;
    contentInfo.content = new Asn1OpaqueObject(Asn1DerEncoder.encode(signedData));
    return Asn1DerEncoder.encode(contentInfo);
}
Also used : IssuerAndSerialNumber(com.android.apksig.internal.pkcs7.IssuerAndSerialNumber) SignerInfo(com.android.apksig.internal.pkcs7.SignerInfo) SignedData(com.android.apksig.internal.pkcs7.SignedData) ContentInfo(com.android.apksig.internal.pkcs7.ContentInfo) EncapsulatedContentInfo(com.android.apksig.internal.pkcs7.EncapsulatedContentInfo) X500Principal(javax.security.auth.x500.X500Principal) SignerIdentifier(com.android.apksig.internal.pkcs7.SignerIdentifier) EncapsulatedContentInfo(com.android.apksig.internal.pkcs7.EncapsulatedContentInfo) Asn1OpaqueObject(com.android.apksig.internal.asn1.Asn1OpaqueObject) X509Certificate(java.security.cert.X509Certificate) GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate)

Aggregations

Asn1EncodingException (com.android.apksig.internal.asn1.Asn1EncodingException)4 X509Certificate (java.security.cert.X509Certificate)4 Asn1DecodingException (com.android.apksig.internal.asn1.Asn1DecodingException)3 ByteBuffer (java.nio.ByteBuffer)3 Certificate (com.android.apksig.internal.x509.Certificate)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 InvalidKeyException (java.security.InvalidKeyException)2 CertificateException (java.security.cert.CertificateException)2 Asn1OpaqueObject (com.android.apksig.internal.asn1.Asn1OpaqueObject)1 AlgorithmIdentifier (com.android.apksig.internal.pkcs7.AlgorithmIdentifier)1 ContentInfo (com.android.apksig.internal.pkcs7.ContentInfo)1 EncapsulatedContentInfo (com.android.apksig.internal.pkcs7.EncapsulatedContentInfo)1 IssuerAndSerialNumber (com.android.apksig.internal.pkcs7.IssuerAndSerialNumber)1 SignedData (com.android.apksig.internal.pkcs7.SignedData)1 SignerIdentifier (com.android.apksig.internal.pkcs7.SignerIdentifier)1 SignerInfo (com.android.apksig.internal.pkcs7.SignerInfo)1 GuaranteedEncodedFormX509Certificate (com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate)1 RSAPublicKey (com.android.apksig.internal.x509.RSAPublicKey)1 SubjectPublicKeyInfo (com.android.apksig.internal.x509.SubjectPublicKeyInfo)1 IOException (java.io.IOException)1