Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Verifies whether or not the JAR file is signed.
        /// </summary>
        /// <returns>True if the JAR file is signed, false otherwise.</returns>
        public bool IsSigned()
        {
            // If there are no signature files or a manifest then don't bother doing anything further.
            if (!(HasSignatureFile && HasManifestFile))
            {
                JarError.AddError(JarResources.MissingSignatureOrManifestFile);
                return(false);
            }

            // Verify the file based on the spec at https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html
            //
            // STEP 1: Verify the signature over the signature file when the manifest is first parsed. For
            // efficiency, this verification can be remembered. Note that this verification only validates
            // the signature directions themselves, not the actual archive files.
            //
            // Note: There can be multiple signature (.SF) files, e.g. as new files are added to the archive after it was signed.
            if (!SignatureFiles.All(sf => sf.VerifySignature()))
            {
                return(false);
            }

            // STEP 2: If an x-Digest-Manifest attribute exists in the signature file, verify the value against a digest calculated
            // over the entire manifest. If more than one x-Digest-Manifest attribute exists in the signature file,
            // verify that at least one of them matches the calculated digest value.

            // Get all the signature files that failed to verify the x-Digest-Manifest attributes
            IEnumerable <JarSignatureFile> signatureFilesFailedVerifyDigestManifest = from sf in SignatureFiles
                                                                                      where !sf.VerifyDigestManifest(Manifest)
                                                                                      select sf;

            if (signatureFilesFailedVerifyDigestManifest.Count() > 0)
            {
                // STEP 3: If an x-Digest-Manifest attribute does not exist in the signature file or none of the digest values calculated
                // in the previous step match, then a less optimized verification is performed:
                //   * If an x-Digest-Manifest-Main-Attributes entry exists in the signature file, verify the value against
                //     a digest calculated over the main  attributes in the manifest file. If this calculation fails, then JAR
                //     file verification fails. This decision can be remembered for efficiency. If an x-Digest-Manifest-Main-Attributes
                //     entry does not exist in the signature file, its nonexistence does not affect JAR file verification and the
                //     manifest main attributes are not verified.
                //   * Verify the digest value in each source file information section in the signature file against a digest value
                //     calculated against the corresponding entry in the manifest file. If any of the digest values don't match, then
                //     JAR file verification fails.
                if (!signatureFilesFailedVerifyDigestManifest.All(sf => sf.VerifyDigestManifestMain(Manifest)))
                {
                    return(false);
                }
            }

            // STEP 4: For each entry in the manifest, verify the digest value in the manifest file against
            // a digest calculated over the actual data referenced in the "Name:" attribute, which
            // specifies either a relative file path or URL. If any of the digest values don't match,
            // then JAR file verification fails.
            if (!Manifest.VerifyManifestEntries())
            {
                return(false);
            }

            return(true);
        }
Exemplo n.º 4
0
        private bool Verify(JarIndividualEntry entry, ZipArchiveEntry archiveEntry)
        {
            using (Stream stream = archiveEntry.Open())
            {
                HashAlgorithm ha           = HashAlgorithm.Create(entry.HashAlgorithmName);
                byte[]        computedHash = ha.ComputeHash(stream);
                string        hashDigest   = Convert.ToBase64String(computedHash);

                // Compare the computed hash digest against the value provided in the manifest file.
                if (!String.Equals(entry.DigestValue, hashDigest))
                {
                    JarError.AddError(String.Format(JarResources.ManifestEntryDigestMismatch, entry.Name, entry.DigestValue, hashDigest));
                    return(false);
                }

                return(true);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Verify the signature over the signature file.
        /// </summary>
        /// <returns>True if the signature was verified successfully, false otherwise.</returns>
        public bool VerifySignature()
        {
            if (String.IsNullOrEmpty(SignatureBlockFilePath))
            {
                JarError.AddError(String.Format(JarResources.MissingSignatureBlockFile, BaseFilename + ".RSA", BaseFilename + ".DSA"));
                return(false);
            }

            if (String.Equals(Path.GetExtension(SignatureBlockFilePath), ".RSA", StringComparison.OrdinalIgnoreCase))
            {
                return(VerifySignatureRsa());
            }

            if (String.Equals(Path.GetExtension(SignatureBlockFilePath), ".DSA", StringComparison.OrdinalIgnoreCase))
            {
                return(VerifySignatureDsa());
            }

            return(false);
        }
Exemplo n.º 6
0
        /// <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);
        }