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