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;
}
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;
}
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);
}
}
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;
}
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);
}
}
Aggregations