然后是使用签名文件(SF 文件)检验 MF 文件没有被修改过,并把SF文件和其对应的证书链对应起来了,还有把SF文件和SF文件中所包含的文件对应起来(看起来好像是一个文件可能被多个 SF 文件包含,但是我没见过)。
privatevoidverifyCertificate(String certFile) { // Found Digital Sig, .SF should already have been read StringsignatureFile= certFile.substring(0, certFile.lastIndexOf('.')) + ".SF"; byte[] sfBytes = metaEntries.get(signatureFile); if (sfBytes == null) { return; }
byte[] manifestBytes = metaEntries.get(JarFile.MANIFEST_NAME); // Manifest entry is required for any verifications. if (manifestBytes == null) { return; }
// Use .SF to verify the mainAttributes of the manifest // If there is no -Digest-Manifest-Main-Attributes entry in .SF // file, such as those created before java 1.5, then we ignore // such verification. if (mainAttributesEnd > 0 && !createdBySigntool) { StringdigestAttribute="-Digest-Manifest-Main-Attributes"; if (!verify(attributes, digestAttribute, manifestBytes, 0, mainAttributesEnd, false, true)) { throw failedVerification(jarName, signatureFile); } }
// Use .SF to verify the whole manifest. StringdigestAttribute= createdBySigntool ? "-Digest" : "-Digest-Manifest"; if (!verify(attributes, digestAttribute, manifestBytes, 0, manifestBytes.length, false, false)) { Iterator<Map.Entry<String, Attributes>> it = entries.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, Attributes> entry = it.next(); StrictJarManifest.Chunkchunk= manifest.getChunk(entry.getKey()); if (chunk == null) { return; } if (!verify(entry.getValue(), "-Digest", manifestBytes, chunk.start, chunk.end, createdBySigntool, false)) { throw invalidDigest(signatureFile, entry.getKey(), jarName); } } } metaEntries.put(signatureFile, null); signatures.put(signatureFile, entries);// 把SF文件和SF文件中所包含的文件对应起来 }
VerifierEntry initEntry(String name) { // If no manifest is present by the time an entry is found, // verification cannot occur. If no signature files have // been found, do not verify. if (manifest == null || signatures.isEmpty()) { returnnull; }
Attributesattributes= manifest.getAttributes(name); // entry has no digest if (attributes == null) { returnnull; }
ArrayList<Certificate[]> certChains = newArrayList<Certificate[]>(); Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, HashMap<String, Attributes>> entry = it.next(); HashMap<String, Attributes> hm = entry.getValue(); if (hm.get(name) != null) { // Found an entry for entry name in .SF file StringsignatureFile= entry.getKey(); Certificate[] certChain = certificates.get(signatureFile); if (certChain != null) { certChains.add(certChain); } } }
// entry is not signed if (certChains.isEmpty()) { returnnull; } Certificate[][] certChainsArray = certChains.toArray(newCertificate[certChains.size()][]);
for (inti=0; i < DIGEST_ALGORITHMS.length; i++) { finalStringalgorithm= DIGEST_ALGORITHMS[i]; finalStringhash= attributes.getValue(algorithm + "-Digest"); if (hash == null) { continue; } byte[] hashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
/** * Returns the encoded form of this certificate. It is * assumed that each certificate type would have only a single * form of encoding; for example, X.509 certificates would * be encoded as ASN.1 DER. * * @return the encoded form of this certificate * * @exception CertificateEncodingException if an encoding error occurs. */ publicabstractbyte[] getEncoded() throws CertificateEncodingException;
省流
好,PackageInfo.signatures 得到其实就是公钥数字证书转换为 DER 格式的二进制数据。