private bool VerifySignatureDsa() { byte[] signatureBlockBytes = JarUtils.ReadBytes(ArchivePath, SignatureBlockFilePath); byte[] signatureFileBytes = JarUtils.ReadBytes(ArchivePath, SignatureFilePath); SHA1Managed sha = new SHA1Managed(); // lgtm [cs/weak-crypto] Hash algorithm specified by signature algorithm byte[] hash = sha.ComputeHash(signatureFileBytes); ContentInfo ci = new ContentInfo(signatureFileBytes); SignedCms cms = new SignedCms(ci, detached: true); cms.Decode(signatureBlockBytes); try { cms.CheckSignature(verifySignatureOnly: true); } catch (CryptographicException ce) { JarError.AddError(ce.Message); return(false); } // If there were no exceptions logged then signature verification should be good. return(true); }
/// <summary> /// Verifies each individual entry's x-Digest against the computed digest of the individual section of the entry in /// the manifest. /// </summary> /// <param name="manifestFile">The manifest file to use when computing individual digests.</param> /// <returns>true if verifications was successful, false otherwise.</returns> public bool VerifySignatureSourceFileDigests(JarManifestFile manifestFile) { foreach (JarIndividualEntry signatureFileEntry in IndividualSection) { JarIndividualEntry manifestFileEntry = manifestFile.IndividualSection.FirstOrDefault( i => String.Equals(i.Name, signatureFileEntry.Name)); if (manifestFileEntry != null) { string computedDigest = JarUtils.GetHashDigest(manifestFileEntry.RawText, signatureFileEntry.HashAlgorithmName); if (!String.Equals(computedDigest, signatureFileEntry.DigestValue)) { JarError.AddError(String.Format(JarResources.SignatureFileEntryDigestMismatch, signatureFileEntry.Name, SignatureFilePath, computedDigest, signatureFileEntry.DigestValue)); return(false); } } else { // Signature file contains an entry that's not present in the MANIFEST.MF file JarError.AddError(String.Format(JarResources.MissingManifestEntry, signatureFileEntry.Name, SignatureFilePath)); return(false); } } // If we make it out of the loop we're all good return(true); }
public JarIndividualEntry(string entryText) { Attributes = JarAttributes.From(entryText); // Set up some properties to simplify tasks string name = null; if (Attributes.TryGetValue("Name", out name)) { Name = name; } RawText = entryText; // Only look for xxx-DIGEST for now. // There are also xxx-DIGEST-yyy attributes for language specific files we need to deal with later string digestAttributeKey = Attributes.Keys.FirstOrDefault(key => key.EndsWith("-Digest", StringComparison.OrdinalIgnoreCase)); if (!String.IsNullOrEmpty(digestAttributeKey)) { string manifestDigest = Attributes[digestAttributeKey]; HashAlgorithmName = JarUtils.GetHashAlgorithmFromDigest(digestAttributeKey, "-Digest"); DigestValue = Attributes[digestAttributeKey]; } }
/// <summary> /// Verify the x-Digest-Manifest-Main-Attributes attribute if it exists, otherwise, verify the individual file attributes /// in the signature file and compare their digests to the digests calculated over the individual sections in the manifest /// file. /// </summary> /// <returns>True if the verification succeeded, false otherwise.</returns> public bool VerifyDigestManifestMain(JarManifestFile manifestFile) { if (HasDigestManifestMainAttributes) { string digestAttributeKey = MainAttributes.Keys.FirstOrDefault(key => key.EndsWith("-Digest-Manifest-Main-Attributes", StringComparison.OrdinalIgnoreCase)); JarUtils.GetHashAlgorithmFromDigest(digestAttributeKey, "-Digest-Manifest-Main-Attributes"); return(String.Equals(MainAttributes[digestAttributeKey], manifestFile.GetMainAttributesDigest(JarUtils.GetHashAlgorithmFromDigest(digestAttributeKey, "-Digest-Manifest-Main-Attributes")))); } else { return(VerifySignatureSourceFileDigests(manifestFile)); } }
/// <summary> /// Creates an instance of JarAttributes using the raw section from a manifest file. /// </summary> /// <param name="rawText">A string containing the raw section (main, individual) text.</param> /// <returns></returns> public static JarAttributes From(string rawText) { var jarAttributes = new JarAttributes(rawText); if (String.IsNullOrEmpty(rawText)) { return(jarAttributes); } // We need to deal with continuations (multi-line attributes), so convert the raw text to a stream // and then parse it. using (Stream s = JarUtils.ToStream(rawText)) using (StreamReader reader = new StreamReader(s)) { string line = reader.ReadLine(); while (!reader.EndOfStream) { if (line.Contains(':')) { string[] attributeParts = line.Split(':'); string attributeName = attributeParts[0]; string attributeValue = attributeParts[1].TrimStart(' '); line = reader.ReadLine(); // Continuation values start with SPACE while (line.StartsWith(" ")) { line = line.TrimStart(' ').TrimEnd(JarUtils.NewLine); attributeValue += line; } jarAttributes[attributeName] = attributeValue; } else { line = reader.ReadLine(); } } } return(jarAttributes); }
/// <summary> /// Verify the signature file, e.g. x.SF using the corresponding signature block, e.g. x.RSA /// </summary> /// <returns>True if the verification is successful, false otherwise.</returns> private bool VerifySignatureRsa() { Timestamps.Clear(); byte[] signatureBlockBytes = JarUtils.ReadBytes(ArchivePath, SignatureBlockFilePath); byte[] signatureFileBytes = JarUtils.ReadBytes(ArchivePath, SignatureFilePath); SHA256Managed sha = new SHA256Managed(); byte[] hash = sha.ComputeHash(signatureFileBytes); ContentInfo ci = new ContentInfo(signatureFileBytes); SignedCms cms = new SignedCms(ci, detached: true); cms.Decode(signatureBlockBytes); try { cms.CheckSignature(verifySignatureOnly: true); // See if we can retrieve a timestamp foreach (SignerInfo signerInfo in cms.SignerInfos) { foreach (CryptographicAttributeObject unsignedAttribute in signerInfo.UnsignedAttributes) { if (String.Equals(unsignedAttribute.Oid.Value, WinCrypt.szOID_SIGNATURE_TIMESTAMP_ATTRIBUTE, StringComparison.OrdinalIgnoreCase)) { Pkcs9AttributeObject timestampAttribute = new Pkcs9AttributeObject(unsignedAttribute.Values[0]); SignedCms timestampCms = new SignedCms(); timestampCms.Decode(timestampAttribute.RawData); TstInfo timestampToken = TstInfo.Read(timestampCms.ContentInfo.Content); foreach (SignerInfo timestampSigner in timestampCms.SignerInfos) { foreach (CryptographicAttributeObject sa in timestampSigner.SignedAttributes) { if (String.Equals(sa.Oid.Value, WinCrypt.szOID_RSA_signingTime, StringComparison.OrdinalIgnoreCase)) { var signingTime = (Pkcs9SigningTime)sa.Values[0]; X509Certificate2 timestampSignerCert = timestampSigner.Certificate; Timestamps.Add(new Timestamp { SignedOn = signingTime.SigningTime.ToLocalTime(), EffectiveDate = Convert.ToDateTime(timestampSignerCert.GetEffectiveDateString()).ToLocalTime(), ExpiryDate = Convert.ToDateTime(timestampSignerCert.GetExpirationDateString()).ToLocalTime(), SignatureAlgorithm = timestampSignerCert.SignatureAlgorithm.FriendlyName }); } } } } } } } catch (CryptographicException ce) { JarError.AddError(ce.Message); return(false); } // If there were no exceptions logged then signature verification should be good. return(true); }
/// <summary> /// Verify all the x-Digest-Manifest attributes. /// </summary> /// <param name="manifest">The JAR manifest (META-INF/MANIFEST.MF)</param> /// <returns>True if all the digests were verified, false if any verification failed or there are no x-Digest-Manifest attributes in the signature file.</returns> public bool VerifyDigestManifest(JarManifestFile manifest) { if (ManifestHashDigestAttributes.Count() > 0) { return(ManifestHashDigestAttributes.All( a => String.Equals(MainAttributes[a], manifest.GetManifestDigest(JarUtils.GetHashAlgorithmFromDigest(a, "-Digest-Manifest"))) )); } return(false); }