use of sun.security.pkcs.SignerInfo in project android_frameworks_base by ResurrectionRemix.
the class RecoverySystem method verifyPackage.
/**
* Verify the cryptographic signature of a system update package
* before installing it. Note that the package is also verified
* separately by the installer once the device is rebooted into
* the recovery system. This function will return only if the
* package was successfully verified; otherwise it will throw an
* exception.
*
* Verification of a package can take significant time, so this
* function should not be called from a UI thread. Interrupting
* the thread while this function is in progress will result in a
* SecurityException being thrown (and the thread's interrupt flag
* will be cleared).
*
* @param packageFile the package to be verified
* @param listener an object to receive periodic progress
* updates as verification proceeds. May be null.
* @param deviceCertsZipFile the zip file of certificates whose
* public keys we will accept. Verification succeeds if the
* package is signed by the private key corresponding to any
* public key in this file. May be null to use the system default
* file (currently "/system/etc/security/otacerts.zip").
*
* @throws IOException if there were any errors reading the
* package or certs files.
* @throws GeneralSecurityException if verification failed
*/
public static void verifyPackage(File packageFile, ProgressListener listener, File deviceCertsZipFile) throws IOException, GeneralSecurityException {
final long fileLen = packageFile.length();
final RandomAccessFile raf = new RandomAccessFile(packageFile, "r");
try {
final long startTimeMillis = System.currentTimeMillis();
if (listener != null) {
listener.onProgress(0);
}
raf.seek(fileLen - 6);
byte[] footer = new byte[6];
raf.readFully(footer);
if (footer[2] != (byte) 0xff || footer[3] != (byte) 0xff) {
throw new SignatureException("no signature in file (no footer)");
}
final int commentSize = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8);
final int signatureStart = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8);
byte[] eocd = new byte[commentSize + 22];
raf.seek(fileLen - (commentSize + 22));
raf.readFully(eocd);
// end-of-central-directory record.
if (eocd[0] != (byte) 0x50 || eocd[1] != (byte) 0x4b || eocd[2] != (byte) 0x05 || eocd[3] != (byte) 0x06) {
throw new SignatureException("no signature in file (bad footer)");
}
for (int i = 4; i < eocd.length - 3; ++i) {
if (eocd[i] == (byte) 0x50 && eocd[i + 1] == (byte) 0x4b && eocd[i + 2] == (byte) 0x05 && eocd[i + 3] == (byte) 0x06) {
throw new SignatureException("EOCD marker found after start of EOCD");
}
}
// Parse the signature
PKCS7 block = new PKCS7(new ByteArrayInputStream(eocd, commentSize + 22 - signatureStart, signatureStart));
// Take the first certificate from the signature (packages
// should contain only one).
X509Certificate[] certificates = block.getCertificates();
if (certificates == null || certificates.length == 0) {
throw new SignatureException("signature contains no certificates");
}
X509Certificate cert = certificates[0];
PublicKey signatureKey = cert.getPublicKey();
SignerInfo[] signerInfos = block.getSignerInfos();
if (signerInfos == null || signerInfos.length == 0) {
throw new SignatureException("signature contains no signedData");
}
SignerInfo signerInfo = signerInfos[0];
// Check that the public key of the certificate contained
// in the package equals one of our trusted public keys.
boolean verified = false;
HashSet<X509Certificate> trusted = getTrustedCerts(deviceCertsZipFile == null ? DEFAULT_KEYSTORE : deviceCertsZipFile);
for (X509Certificate c : trusted) {
if (c.getPublicKey().equals(signatureKey)) {
verified = true;
break;
}
}
if (!verified) {
throw new SignatureException("signature doesn't match any trusted key");
}
// The signature cert matches a trusted key. Now verify that
// the digest in the cert matches the actual file data.
raf.seek(0);
final ProgressListener listenerForInner = listener;
SignerInfo verifyResult = block.verify(signerInfo, new InputStream() {
// The signature covers all of the OTA package except the
// archive comment and its 2-byte length.
long toRead = fileLen - commentSize - 2;
long soFar = 0;
int lastPercent = 0;
long lastPublishTime = startTimeMillis;
@Override
public int read() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (soFar >= toRead) {
return -1;
}
if (Thread.currentThread().isInterrupted()) {
return -1;
}
int size = len;
if (soFar + size > toRead) {
size = (int) (toRead - soFar);
}
int read = raf.read(b, off, size);
soFar += read;
if (listenerForInner != null) {
long now = System.currentTimeMillis();
int p = (int) (soFar * 100 / toRead);
if (p > lastPercent && now - lastPublishTime > PUBLISH_PROGRESS_INTERVAL_MS) {
lastPercent = p;
lastPublishTime = now;
listenerForInner.onProgress(lastPercent);
}
}
return read;
}
});
final boolean interrupted = Thread.interrupted();
if (listener != null) {
listener.onProgress(100);
}
if (interrupted) {
throw new SignatureException("verification was interrupted");
}
if (verifyResult == null) {
throw new SignatureException("signature digest verification failed");
}
} finally {
raf.close();
}
}
use of sun.security.pkcs.SignerInfo in project jdk8u_jdk by JetBrains.
the class PKCS7VerifyTest method main.
public static void main(String[] args) throws Exception {
if (args.length == 0) {
throw new RuntimeException("usage: java JarVerify <file1> <file2>");
}
// The command " java PKCS7VerifyTest file1 [file2] "
// treats file1 as containing the DER encoding of a PKCS7 signed data
// object. If file2 is absent, the program verifies that some signature
// (SignerInfo) file1 correctly signs the data contained in the
// ContentInfo component of the PKCS7 object encoded by file1. If file2
// is present, the program verifies file1 contains a correct signature
// for the contents of file2.
PKCS7 pkcs7;
byte[] data;
// to avoid attaching binary DSA file, the DSA file was encoded
// in Base64, decode encoded Base64 DSA file below
byte[] base64Bytes = Files.readAllBytes(Paths.get(FILEPATH + args[0]));
pkcs7 = new PKCS7(new ByteArrayInputStream(Base64.getMimeDecoder().decode(base64Bytes)));
if (args.length < 2) {
data = null;
} else {
data = Files.readAllBytes(Paths.get(FILEPATH + args[1]));
}
SignerInfo[] signerInfos = pkcs7.verify(data);
if (signerInfos == null) {
throw new RuntimeException("no signers verify");
}
System.out.println("Verifying SignerInfos:");
for (SignerInfo signerInfo : signerInfos) {
System.out.println(signerInfo.toString());
}
X509Certificate[] certs = pkcs7.getCertificates();
HashMap<String, X509Certificate> certTable = new HashMap(certs.length);
for (X509Certificate cert : certs) {
certTable.put(cert.getSubjectDN().toString(), cert);
}
// try to verify all the certs
for (Map.Entry<String, X509Certificate> entry : certTable.entrySet()) {
X509Certificate cert = entry.getValue();
X509Certificate issuerCert = certTable.get(cert.getIssuerDN().toString());
System.out.println("Subject: " + cert.getSubjectDN());
if (issuerCert == null) {
System.out.println("Issuer certificate not found");
} else {
System.out.println("Issuer: " + cert.getIssuerDN());
cert.verify(issuerCert.getPublicKey());
System.out.println("Cert verifies.");
}
System.out.println();
}
}
use of sun.security.pkcs.SignerInfo in project jdk8u_jdk by JetBrains.
the class TimestampCheck method checkTimestamp.
static void checkTimestamp(String file, String policyId, String digestAlg) throws Exception {
try (JarFile jf = new JarFile(file)) {
JarEntry je = jf.getJarEntry("META-INF/OLD.RSA");
try (InputStream is = jf.getInputStream(je)) {
byte[] content = IOUtils.readFully(is, -1, true);
PKCS7 p7 = new PKCS7(content);
SignerInfo[] si = p7.getSignerInfos();
if (si == null || si.length == 0) {
throw new Exception("Not signed");
}
PKCS9Attribute p9 = si[0].getUnauthenticatedAttributes().getAttribute(PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
PKCS7 tsToken = new PKCS7((byte[]) p9.getValue());
TimestampToken tt = new TimestampToken(tsToken.getContentInfo().getData());
if (!tt.getHashAlgorithm().toString().equals(digestAlg)) {
throw new Exception("Digest alg different");
}
if (!tt.getPolicyID().equals(policyId)) {
throw new Exception("policyId different");
}
}
}
}
use of sun.security.pkcs.SignerInfo in project platform_frameworks_base by android.
the class StrictJarVerifier method verifyBytes.
/**
* Verifies that the signature computed from {@code sfBytes} matches
* that specified in {@code blockBytes} (which is a PKCS7 block). Returns
* certificates listed in the PKCS7 block. Throws a {@code GeneralSecurityException}
* if something goes wrong during verification.
*/
static Certificate[] verifyBytes(byte[] blockBytes, byte[] sfBytes) throws GeneralSecurityException {
Object obj = null;
try {
obj = Providers.startJarVerification();
PKCS7 block = new PKCS7(blockBytes);
SignerInfo[] verifiedSignerInfos = block.verify(sfBytes);
if ((verifiedSignerInfos == null) || (verifiedSignerInfos.length == 0)) {
throw new GeneralSecurityException("Failed to verify signature: no verified SignerInfos");
}
// Ignore any SignerInfo other than the first one, to be compatible with older Android
// platforms which have been doing this for years. See
// libcore/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
// verifySignature method of older platforms.
SignerInfo verifiedSignerInfo = verifiedSignerInfos[0];
List<X509Certificate> verifiedSignerCertChain = verifiedSignerInfo.getCertificateChain(block);
if (verifiedSignerCertChain == null) {
// Should never happen
throw new GeneralSecurityException("Failed to find verified SignerInfo certificate chain");
} else if (verifiedSignerCertChain.isEmpty()) {
// Should never happen
throw new GeneralSecurityException("Verified SignerInfo certificate chain is emtpy");
}
return verifiedSignerCertChain.toArray(new X509Certificate[verifiedSignerCertChain.size()]);
} catch (IOException e) {
throw new GeneralSecurityException("IO exception verifying jar cert", e);
} finally {
Providers.stopJarVerification(obj);
}
}
use of sun.security.pkcs.SignerInfo in project jdk8u_jdk by JetBrains.
the class SignatureFile method verifyJar.
void verifyJar(String jarName) throws Exception {
// if there exists entry inside jar signed
boolean anySigned = false;
JarFile jf = null;
Map<String, String> digestMap = new HashMap<>();
Map<String, PKCS7> sigMap = new HashMap<>();
Map<String, String> sigNameMap = new HashMap<>();
Map<String, String> unparsableSignatures = new HashMap<>();
try {
jf = new JarFile(jarName, true);
Vector<JarEntry> entriesVec = new Vector<>();
byte[] buffer = new byte[8192];
Enumeration<JarEntry> entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry je = entries.nextElement();
entriesVec.addElement(je);
try (InputStream is = jf.getInputStream(je)) {
String name = je.getName();
if (signatureRelated(name) && SignatureFileVerifier.isBlockOrSF(name)) {
String alias = name.substring(name.lastIndexOf('/') + 1, name.lastIndexOf('.'));
try {
if (name.endsWith(".SF")) {
Manifest sf = new Manifest(is);
boolean found = false;
for (Object obj : sf.getMainAttributes().keySet()) {
String key = obj.toString();
if (key.endsWith("-Digest-Manifest")) {
digestMap.put(alias, key.substring(0, key.length() - 16));
found = true;
break;
}
}
if (!found) {
unparsableSignatures.putIfAbsent(alias, String.format(rb.getString("history.unparsable"), name));
}
} else {
sigNameMap.put(alias, name);
sigMap.put(alias, new PKCS7(is));
}
} catch (IOException ioe) {
unparsableSignatures.putIfAbsent(alias, String.format(rb.getString("history.unparsable"), name));
}
} else {
while (is.read(buffer, 0, buffer.length) != -1) {
// we just read. this will throw a SecurityException
// if a signature/digest check fails.
}
}
}
}
Manifest man = jf.getManifest();
boolean hasSignature = false;
// The map to record display info, only used when -verbose provided
// key: signer info string
// value: the list of files with common key
Map<String, List<String>> output = new LinkedHashMap<>();
if (man != null) {
if (verbose != null)
System.out.println();
Enumeration<JarEntry> e = entriesVec.elements();
String tab = rb.getString("6SPACE");
while (e.hasMoreElements()) {
JarEntry je = e.nextElement();
String name = je.getName();
hasSignature = hasSignature || SignatureFileVerifier.isBlockOrSF(name);
CodeSigner[] signers = je.getCodeSigners();
boolean isSigned = (signers != null);
anySigned |= isSigned;
hasUnsignedEntry |= !je.isDirectory() && !isSigned && !signatureRelated(name);
int inStoreOrScope = inKeyStore(signers);
boolean inStore = (inStoreOrScope & IN_KEYSTORE) != 0;
boolean inScope = (inStoreOrScope & IN_SCOPE) != 0;
notSignedByAlias |= (inStoreOrScope & NOT_ALIAS) != 0;
if (keystore != null) {
aliasNotInStore |= isSigned && (!inStore && !inScope);
}
// Only used when -verbose provided
StringBuffer sb = null;
if (verbose != null) {
sb = new StringBuffer();
boolean inManifest = ((man.getAttributes(name) != null) || (man.getAttributes("./" + name) != null) || (man.getAttributes("/" + name) != null));
sb.append((isSigned ? rb.getString("s") : rb.getString("SPACE")) + (inManifest ? rb.getString("m") : rb.getString("SPACE")) + (inStore ? rb.getString("k") : rb.getString("SPACE")) + (inScope ? rb.getString("i") : rb.getString("SPACE")) + ((inStoreOrScope & NOT_ALIAS) != 0 ? "X" : " ") + rb.getString("SPACE"));
sb.append("|");
}
// lines at the beginning and end.
if (isSigned) {
if (showcerts)
sb.append('\n');
for (CodeSigner signer : signers) {
// signerInfo() must be called even if -verbose
// not provided. The method updates various
// warning flags.
String si = signerInfo(signer, tab);
if (showcerts) {
sb.append(si);
sb.append('\n');
}
}
} else if (showcerts && !verbose.equals("all")) {
// to be consistent with old behavior.
if (signatureRelated(name)) {
sb.append("\n" + tab + rb.getString(".Signature.related.entries.") + "\n\n");
} else {
sb.append("\n" + tab + rb.getString(".Unsigned.entries.") + "\n\n");
}
}
if (verbose != null) {
String label = sb.toString();
if (signatureRelated(name)) {
// Entries inside META-INF and other unsigned
// entries are grouped separately.
label = "-" + label;
}
if (!output.containsKey(label)) {
output.put(label, new ArrayList<String>());
}
StringBuffer fb = new StringBuffer();
String s = Long.toString(je.getSize());
for (int i = 6 - s.length(); i > 0; --i) {
fb.append(' ');
}
fb.append(s).append(' ').append(new Date(je.getTime()).toString());
fb.append(' ').append(name);
output.get(label).add(fb.toString());
}
}
}
if (verbose != null) {
for (Entry<String, List<String>> s : output.entrySet()) {
List<String> files = s.getValue();
String key = s.getKey();
if (key.charAt(0) == '-') {
// the signature-related group
key = key.substring(1);
}
int pipe = key.indexOf('|');
if (verbose.equals("all")) {
for (String f : files) {
System.out.println(key.substring(0, pipe) + f);
System.out.printf(key.substring(pipe + 1));
}
} else {
if (verbose.equals("grouped")) {
for (String f : files) {
System.out.println(key.substring(0, pipe) + f);
}
} else if (verbose.equals("summary")) {
System.out.print(key.substring(0, pipe));
if (files.size() > 1) {
System.out.println(files.get(0) + " " + String.format(rb.getString(".and.d.more."), files.size() - 1));
} else {
System.out.println(files.get(0));
}
}
System.out.printf(key.substring(pipe + 1));
}
}
System.out.println();
System.out.println(rb.getString(".s.signature.was.verified."));
System.out.println(rb.getString(".m.entry.is.listed.in.manifest"));
System.out.println(rb.getString(".k.at.least.one.certificate.was.found.in.keystore"));
System.out.println(rb.getString(".i.at.least.one.certificate.was.found.in.identity.scope"));
if (ckaliases.size() > 0) {
System.out.println(rb.getString(".X.not.signed.by.specified.alias.es."));
}
}
if (man == null) {
System.out.println();
System.out.println(rb.getString("no.manifest."));
}
// must be generated so seeWeak can be updated.
if (!digestMap.isEmpty() || !sigMap.isEmpty() || !unparsableSignatures.isEmpty()) {
if (verbose != null) {
System.out.println();
}
for (String s : sigMap.keySet()) {
if (!digestMap.containsKey(s)) {
unparsableSignatures.putIfAbsent(s, String.format(rb.getString("history.nosf"), s));
}
}
for (String s : digestMap.keySet()) {
PKCS7 p7 = sigMap.get(s);
if (p7 != null) {
String history;
try {
SignerInfo si = p7.getSignerInfos()[0];
X509Certificate signer = si.getCertificate(p7);
String digestAlg = digestMap.get(s);
String sigAlg = AlgorithmId.makeSigAlg(si.getDigestAlgorithmId().getName(), si.getDigestEncryptionAlgorithmId().getName());
PublicKey key = signer.getPublicKey();
PKCS7 tsToken = si.getTsToken();
if (tsToken != null) {
SignerInfo tsSi = tsToken.getSignerInfos()[0];
X509Certificate tsSigner = tsSi.getCertificate(tsToken);
byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
PublicKey tsKey = tsSigner.getPublicKey();
String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName();
String tsSigAlg = AlgorithmId.makeSigAlg(tsSi.getDigestAlgorithmId().getName(), tsSi.getDigestEncryptionAlgorithmId().getName());
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.getDefault(Locale.Category.FORMAT));
c.setTime(tsTokenInfo.getDate());
history = String.format(rb.getString("history.with.ts"), signer.getSubjectX500Principal(), withWeak(digestAlg, DIGEST_PRIMITIVE_SET), withWeak(sigAlg, SIG_PRIMITIVE_SET), withWeak(key), c, tsSigner.getSubjectX500Principal(), withWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET), withWeak(tsSigAlg, SIG_PRIMITIVE_SET), withWeak(tsKey));
} else {
history = String.format(rb.getString("history.without.ts"), signer.getSubjectX500Principal(), withWeak(digestAlg, DIGEST_PRIMITIVE_SET), withWeak(sigAlg, SIG_PRIMITIVE_SET), withWeak(key));
}
} catch (Exception e) {
// The only usage of sigNameMap, remember the name
// of the block file if it's invalid.
history = String.format(rb.getString("history.unparsable"), sigNameMap.get(s));
}
if (verbose != null) {
System.out.println(history);
}
} else {
unparsableSignatures.putIfAbsent(s, String.format(rb.getString("history.nobk"), s));
}
}
if (verbose != null) {
for (String s : unparsableSignatures.keySet()) {
System.out.println(unparsableSignatures.get(s));
}
}
}
System.out.println();
if (!anySigned) {
if (seeWeak) {
if (verbose != null) {
System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose"));
System.out.println("\n " + DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS + "=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS));
} else {
System.out.println(rb.getString("jar.treated.unsigned.see.weak"));
}
} else if (hasSignature) {
System.out.println(rb.getString("jar.treated.unsigned"));
} else {
System.out.println(rb.getString("jar.is.unsigned"));
}
} else {
boolean warningAppeared = false;
boolean errorAppeared = false;
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || notYetValidCert || chainNotValidated || hasExpiredCert || hasUnsignedEntry || aliasNotInStore || notSignedByAlias) {
if (strict) {
System.out.println(rb.getString("jar.verified.with.signer.errors."));
System.out.println();
System.out.println(rb.getString("Error."));
errorAppeared = true;
} else {
System.out.println(rb.getString("jar.verified."));
System.out.println();
System.out.println(rb.getString("Warning."));
warningAppeared = true;
}
if (badKeyUsage) {
System.out.println(rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
}
if (badExtendedKeyUsage) {
System.out.println(rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
}
if (badNetscapeCertType) {
System.out.println(rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
}
if (hasUnsignedEntry) {
System.out.println(rb.getString("This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
}
if (hasExpiredCert) {
System.out.println(rb.getString("This.jar.contains.entries.whose.signer.certificate.has.expired."));
}
if (notYetValidCert) {
System.out.println(rb.getString("This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
}
if (chainNotValidated) {
System.out.println(rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated."));
}
if (notSignedByAlias) {
System.out.println(rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es."));
}
if (aliasNotInStore) {
System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));
}
} else {
System.out.println(rb.getString("jar.verified."));
}
if (hasExpiringCert || noTimestamp) {
if (!warningAppeared) {
System.out.println();
System.out.println(rb.getString("Warning."));
warningAppeared = true;
}
if (hasExpiringCert) {
System.out.println(rb.getString("This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));
}
if (noTimestamp) {
System.out.println(String.format(rb.getString("no.timestamp.verifying"), expireDate));
}
}
if (warningAppeared || errorAppeared) {
if (!(verbose != null && showcerts)) {
System.out.println();
System.out.println(rb.getString("Re.run.with.the.verbose.and.certs.options.for.more.details."));
}
}
}
return;
} catch (Exception e) {
System.out.println(rb.getString("jarsigner.") + e);
if (debug) {
e.printStackTrace();
}
} finally {
// close the resource
if (jf != null) {
jf.close();
}
}
System.exit(1);
}
Aggregations