use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.
the class SourceStampVerifier method verifySourceStamp.
/**
* Verifies the provided {@code apk}'s source stamp signature, including verification of the
* SHA-256 digest of the stamp signing certificate matches the {@code expectedCertDigest}, and
* returns the result of the verification.
*
* @see #verifySourceStamp(String)
*/
private SourceStampVerifier.Result verifySourceStamp(DataSource apk, String expectedCertDigest) {
Result result = new Result();
try {
ZipSections zipSections = ApkUtilsLite.findZipSections(apk);
// Attempt to obtain the source stamp's certificate digest from the APK.
List<CentralDirectoryRecord> cdRecords = ZipUtils.parseZipCentralDirectory(apk, zipSections);
CentralDirectoryRecord sourceStampCdRecord = null;
for (CentralDirectoryRecord cdRecord : cdRecords) {
if (SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME.equals(cdRecord.getName())) {
sourceStampCdRecord = cdRecord;
break;
}
}
// APK's signature block to determine the appropriate status to return.
if (sourceStampCdRecord == null) {
boolean stampSigningBlockFound;
try {
ApkSigningBlockUtilsLite.findSignature(apk, zipSections, SourceStampConstants.V2_SOURCE_STAMP_BLOCK_ID);
stampSigningBlockFound = true;
} catch (SignatureNotFoundException e) {
stampSigningBlockFound = false;
}
result.addVerificationError(stampSigningBlockFound ? ApkVerificationIssue.SOURCE_STAMP_SIGNATURE_BLOCK_WITHOUT_CERT_DIGEST : ApkVerificationIssue.SOURCE_STAMP_CERT_DIGEST_AND_SIG_BLOCK_MISSING);
return result;
}
// Verify that the contents of the source stamp certificate digest match the expected
// value, if provided.
byte[] sourceStampCertificateDigest = LocalFileRecord.getUncompressedData(apk, sourceStampCdRecord, zipSections.getZipCentralDirectoryOffset());
if (expectedCertDigest != null) {
String actualCertDigest = ApkSigningBlockUtilsLite.toHex(sourceStampCertificateDigest);
if (!expectedCertDigest.equalsIgnoreCase(actualCertDigest)) {
result.addVerificationError(ApkVerificationIssue.SOURCE_STAMP_EXPECTED_DIGEST_MISMATCH, actualCertDigest, expectedCertDigest);
return result;
}
}
Map<Integer, Map<ContentDigestAlgorithm, byte[]>> signatureSchemeApkContentDigests = new HashMap<>();
if (mMaxSdkVersion >= AndroidSdkVersion.P) {
SignatureInfo signatureInfo;
try {
signatureInfo = ApkSigningBlockUtilsLite.findSignature(apk, zipSections, V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
} catch (SignatureNotFoundException e) {
signatureInfo = null;
}
if (signatureInfo != null) {
Map<ContentDigestAlgorithm, byte[]> apkContentDigests = new EnumMap<>(ContentDigestAlgorithm.class);
parseSigners(signatureInfo.signatureBlock, VERSION_APK_SIGNATURE_SCHEME_V3, apkContentDigests, result);
signatureSchemeApkContentDigests.put(VERSION_APK_SIGNATURE_SCHEME_V3, apkContentDigests);
}
}
if (mMaxSdkVersion >= AndroidSdkVersion.N && (mMinSdkVersion < AndroidSdkVersion.P || signatureSchemeApkContentDigests.isEmpty())) {
SignatureInfo signatureInfo;
try {
signatureInfo = ApkSigningBlockUtilsLite.findSignature(apk, zipSections, V2SchemeConstants.APK_SIGNATURE_SCHEME_V2_BLOCK_ID);
} catch (SignatureNotFoundException e) {
signatureInfo = null;
}
if (signatureInfo != null) {
Map<ContentDigestAlgorithm, byte[]> apkContentDigests = new EnumMap<>(ContentDigestAlgorithm.class);
parseSigners(signatureInfo.signatureBlock, VERSION_APK_SIGNATURE_SCHEME_V2, apkContentDigests, result);
signatureSchemeApkContentDigests.put(VERSION_APK_SIGNATURE_SCHEME_V2, apkContentDigests);
}
}
if (mMinSdkVersion < AndroidSdkVersion.N || signatureSchemeApkContentDigests.isEmpty()) {
Map<ContentDigestAlgorithm, byte[]> apkContentDigests = getApkContentDigestFromV1SigningScheme(cdRecords, apk, zipSections, result);
signatureSchemeApkContentDigests.put(VERSION_JAR_SIGNATURE_SCHEME, apkContentDigests);
}
ApkSigResult sourceStampResult = V2SourceStampVerifier.verify(apk, zipSections, sourceStampCertificateDigest, signatureSchemeApkContentDigests, mMinSdkVersion, mMaxSdkVersion);
result.mergeFrom(sourceStampResult);
return result;
} catch (ApkFormatException | IOException | ZipFormatException e) {
result.addVerificationError(ApkVerificationIssue.MALFORMED_APK, e);
} catch (NoSuchAlgorithmException e) {
result.addVerificationError(ApkVerificationIssue.UNEXPECTED_EXCEPTION, e);
} catch (SignatureNotFoundException e) {
result.addVerificationError(ApkVerificationIssue.SOURCE_STAMP_SIG_MISSING);
}
return result;
}
use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.
the class V2SourceStampVerifier method verify.
/**
* Verifies the provided APK's SourceStamp signatures and returns the result of verification.
* The APK must be considered verified only if {@link ApkSigResult#verified} is
* {@code true}. If verification fails, the result will contain errors -- see {@link
* ApkSigResult#getErrors()}.
*
* @throws NoSuchAlgorithmException if the APK's signatures cannot be verified because a
* required cryptographic algorithm implementation is missing
* @throws SignatureNotFoundException if no SourceStamp signatures are
* found
* @throws IOException if an I/O error occurs when reading the APK
*/
public static ApkSigResult verify(DataSource apk, ZipSections zipSections, byte[] sourceStampCertificateDigest, Map<Integer, Map<ContentDigestAlgorithm, byte[]>> signatureSchemeApkContentDigests, int minSdkVersion, int maxSdkVersion) throws IOException, NoSuchAlgorithmException, SignatureNotFoundException {
ApkSigResult result = new ApkSigResult(Constants.VERSION_SOURCE_STAMP);
SignatureInfo signatureInfo = ApkSigningBlockUtilsLite.findSignature(apk, zipSections, V2_SOURCE_STAMP_BLOCK_ID);
verify(signatureInfo.signatureBlock, sourceStampCertificateDigest, signatureSchemeApkContentDigests, minSdkVersion, maxSdkVersion, result);
return result;
}
use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.
the class ApkSignerTest method getRSAPublicKeyFromSigningBlock.
private RSAPublicKey getRSAPublicKeyFromSigningBlock(File apk, int signatureVersionId) throws Exception {
int signatureVersionBlockId;
switch(signatureVersionId) {
case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2:
signatureVersionBlockId = V2SchemeConstants.APK_SIGNATURE_SCHEME_V2_BLOCK_ID;
break;
case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3:
signatureVersionBlockId = V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID;
break;
default:
throw new Exception("Invalid signature version ID specified: " + signatureVersionId);
}
SignatureInfo signatureInfo = getSignatureInfoFromApk(apk, signatureVersionId, signatureVersionBlockId);
// FORMAT:
// * length prefixed sequence of length prefixed signers
// * length-prefixed signed data
// * V3+ only - minSDK (uint32)
// * V3+ only - maxSDK (uint32)
// * length-prefixed sequence of length-prefixed signatures:
// * length-prefixed bytes: public key (X.509 SubjectPublicKeyInfo, ASN.1 DER encoded)
ByteBuffer signers = ApkSigningBlockUtils.getLengthPrefixedSlice(signatureInfo.signatureBlock);
ByteBuffer signer = ApkSigningBlockUtils.getLengthPrefixedSlice(signers);
// Since all the data is read from the signer block the signedData and signatures are
// discarded.
ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
// For V3+ signature version IDs discard the min / max SDKs as well
if (signatureVersionId >= ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3) {
signer.getInt();
signer.getInt();
}
ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
ByteBuffer publicKey = ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(publicKey, SubjectPublicKeyInfo.class);
ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
// The SubjectPublicKey is stored as a bit string in the SubjectPublicKeyInfo with the first
// byte indicating the number of padding bits in the public key. Read this first byte to
// allow parsing the rest of the RSAPublicKey as a sequence.
subjectPublicKeyBuffer.get();
return Asn1BerParser.parse(subjectPublicKeyBuffer, RSAPublicKey.class);
}
use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.
the class ApkSignerTest method assertSourceStampVerified.
private static void assertSourceStampVerified(File signedApk, ApkVerifier.Result result) throws ApkSigningBlockUtils.SignatureNotFoundException, IOException, ZipFormatException {
SignatureInfo signatureInfo = getSignatureInfoFromApk(signedApk, ApkSigningBlockUtils.VERSION_SOURCE_STAMP, SourceStampConstants.V2_SOURCE_STAMP_BLOCK_ID);
assertNotNull(signatureInfo.signatureBlock);
assertTrue(result.isSourceStampVerified());
}
use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.
the class SigningCertificateLineage method readFromApkDataSource.
/**
* Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3
* signature block of the provided APK DataSource.
*
* @throws IllegalArgumentException if the provided APK does not contain a V3 signature block,
* or if the V3 signature block does not contain a valid lineage.
*/
public static SigningCertificateLineage readFromApkDataSource(DataSource apk) throws IOException, ApkFormatException {
SignatureInfo signatureInfo;
try {
ApkUtils.ZipSections zipSections = ApkUtils.findZipSections(apk);
ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
signatureInfo = ApkSigningBlockUtils.findSignature(apk, zipSections, V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID, result);
} catch (ZipFormatException e) {
throw new ApkFormatException(e.getMessage());
} catch (ApkSigningBlockUtils.SignatureNotFoundException e) {
throw new IllegalArgumentException("The provided APK does not contain a valid V3 signature block.");
}
// FORMAT:
// * length-prefixed sequence of length-prefixed signers:
// * length-prefixed signed data
// * minSDK
// * maxSDK
// * length-prefixed sequence of length-prefixed signatures
// * length-prefixed public key
ByteBuffer signers = getLengthPrefixedSlice(signatureInfo.signatureBlock);
List<SigningCertificateLineage> lineages = new ArrayList<>(1);
while (signers.hasRemaining()) {
ByteBuffer signer = getLengthPrefixedSlice(signers);
ByteBuffer signedData = getLengthPrefixedSlice(signer);
try {
SigningCertificateLineage lineage = readFromSignedData(signedData);
lineages.add(lineage);
} catch (IllegalArgumentException ignored) {
// The current signer block does not contain a valid lineage, but it is possible
// another block will.
}
}
SigningCertificateLineage result;
if (lineages.isEmpty()) {
throw new IllegalArgumentException("The provided APK does not contain a valid lineage.");
} else if (lineages.size() > 1) {
result = consolidateLineages(lineages);
} else {
result = lineages.get(0);
}
return result;
}
Aggregations