Search in sources :

Example 1 with Asn1DecodingException

use of com.android.apksig.internal.asn1.Asn1DecodingException 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 2 with Asn1DecodingException

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

the class Asn1BerParser method parseSequence.

private static <T> T parseSequence(BerDataValue container, Class<T> containerClass, boolean isUnencodedContainer) throws Asn1DecodingException {
    List<AnnotatedField> fields = getAnnotatedFields(containerClass);
    Collections.sort(fields, (f1, f2) -> f1.getAnnotation().index() - f2.getAnnotation().index());
    // Check that there are no fields with the same index
    if (fields.size() > 1) {
        AnnotatedField lastField = null;
        for (AnnotatedField field : fields) {
            if ((lastField != null) && (lastField.getAnnotation().index() == field.getAnnotation().index())) {
                throw new Asn1DecodingException("Fields have the same index: " + containerClass.getName() + "." + lastField.getField().getName() + " and ." + field.getField().getName());
            }
            lastField = field;
        }
    }
    // Instantiate the container object / result
    T t;
    try {
        t = containerClass.getConstructor().newInstance();
    } catch (IllegalArgumentException | ReflectiveOperationException e) {
        throw new Asn1DecodingException("Failed to instantiate " + containerClass.getName(), e);
    }
    // Parse fields one by one. A complication is that there may be optional fields.
    int nextUnreadFieldIndex = 0;
    BerDataValueReader elementsReader = container.contentsReader();
    while (nextUnreadFieldIndex < fields.size()) {
        BerDataValue dataValue;
        try {
            // the container should be used when assigning to this field.
            if (isUnencodedContainer && nextUnreadFieldIndex == 0) {
                dataValue = container;
            } else {
                dataValue = elementsReader.readDataValue();
            }
        } catch (BerDataValueFormatException e) {
            throw new Asn1DecodingException("Malformed data value", e);
        }
        if (dataValue == null) {
            break;
        }
        for (int i = nextUnreadFieldIndex; i < fields.size(); i++) {
            AnnotatedField field = fields.get(i);
            try {
                if (field.isOptional()) {
                    // it from the wrong tag.
                    try {
                        field.setValueFrom(dataValue, t);
                        nextUnreadFieldIndex = i + 1;
                        break;
                    } catch (Asn1UnexpectedTagException e) {
                        // next / iteration of the loop
                        continue;
                    }
                } else {
                    // Mandatory field -- if we can't set its value from this data value, then
                    // it's an error
                    field.setValueFrom(dataValue, t);
                    nextUnreadFieldIndex = i + 1;
                    break;
                }
            } catch (Asn1DecodingException e) {
                throw new Asn1DecodingException("Failed to parse " + containerClass.getName() + "." + field.getField().getName(), e);
            }
        }
    }
    return t;
}
Also used : BerDataValue(com.android.apksig.internal.asn1.ber.BerDataValue) BerDataValueFormatException(com.android.apksig.internal.asn1.ber.BerDataValueFormatException) ByteBufferBerDataValueReader(com.android.apksig.internal.asn1.ber.ByteBufferBerDataValueReader) BerDataValueReader(com.android.apksig.internal.asn1.ber.BerDataValueReader)

Example 3 with Asn1DecodingException

use of com.android.apksig.internal.asn1.Asn1DecodingException 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 Asn1DecodingException

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

the class Asn1BerParser method parseSetOf.

// NOTE: This method returns List rather than Set because ASN.1 SET_OF does require uniqueness
// of elements -- it's an unordered collection.
@SuppressWarnings("unchecked")
private static <T> List<T> parseSetOf(BerDataValue container, Class<T> elementClass) throws Asn1DecodingException {
    List<T> result = new ArrayList<>();
    BerDataValueReader elementsReader = container.contentsReader();
    while (true) {
        BerDataValue dataValue;
        try {
            dataValue = elementsReader.readDataValue();
        } catch (BerDataValueFormatException e) {
            throw new Asn1DecodingException("Malformed data value", e);
        }
        if (dataValue == null) {
            break;
        }
        T element;
        if (ByteBuffer.class.equals(elementClass)) {
            element = (T) dataValue.getEncodedContents();
        } else if (Asn1OpaqueObject.class.equals(elementClass)) {
            element = (T) new Asn1OpaqueObject(dataValue.getEncoded());
        } else {
            element = parse(dataValue, elementClass);
        }
        result.add(element);
    }
    return result;
}
Also used : BerDataValue(com.android.apksig.internal.asn1.ber.BerDataValue) BerDataValueFormatException(com.android.apksig.internal.asn1.ber.BerDataValueFormatException) ArrayList(java.util.ArrayList) ByteBufferBerDataValueReader(com.android.apksig.internal.asn1.ber.ByteBufferBerDataValueReader) BerDataValueReader(com.android.apksig.internal.asn1.ber.BerDataValueReader)

Example 5 with Asn1DecodingException

use of com.android.apksig.internal.asn1.Asn1DecodingException 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)

Aggregations

Asn1DecodingException (com.android.apksig.internal.asn1.Asn1DecodingException)3 Asn1EncodingException (com.android.apksig.internal.asn1.Asn1EncodingException)3 ByteBuffer (java.nio.ByteBuffer)3 BerDataValue (com.android.apksig.internal.asn1.ber.BerDataValue)2 BerDataValueFormatException (com.android.apksig.internal.asn1.ber.BerDataValueFormatException)2 BerDataValueReader (com.android.apksig.internal.asn1.ber.BerDataValueReader)2 ByteBufferBerDataValueReader (com.android.apksig.internal.asn1.ber.ByteBufferBerDataValueReader)2 Certificate (com.android.apksig.internal.x509.Certificate)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 CertificateException (java.security.cert.CertificateException)2 X509Certificate (java.security.cert.X509Certificate)2 ArrayList (java.util.ArrayList)2 RSAPublicKey (com.android.apksig.internal.x509.RSAPublicKey)1 SubjectPublicKeyInfo (com.android.apksig.internal.x509.SubjectPublicKeyInfo)1 IOException (java.io.IOException)1 BigInteger (java.math.BigInteger)1 InvalidKeyException (java.security.InvalidKeyException)1 InvalidKeySpecException (java.security.spec.InvalidKeySpecException)1