internal IncrementalHashHasher(HashAlgorithmName hashAlgorithmName) { _incrementalHash = IncrementalHash.CreateHash(hashAlgorithmName); }
internal MD5SHA1IncrementalHasher() { _md5 = IncrementalHash.CreateHash(HashAlgorithmName.MD5); _sha1 = IncrementalHash.CreateHash(HashAlgorithmName.SHA1); }
/// <summary> /// The method that performs the actual validation. /// More information about checksum algorithm: /// https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#portable-pdb-checksum /// </summary> /// <param name="targetDirectory">The directory used during the current validation.</param> /// <param name="packageId">Package Id.</param> /// <param name="packageNormalizedVersion">PackageNormalized version.</param> /// <returns></returns> public virtual IValidationResult ValidateSymbolMatching(string targetDirectory, string packageId, string packageNormalizedVersion) { foreach (string extension in PEExtensionsPatterns) { foreach (string peFile in Directory.GetFiles(targetDirectory, extension, SearchOption.AllDirectories)) { using (var peStream = File.OpenRead(peFile)) using (var peReader = new PEReader(peStream)) { // This checks if portable PDB is associated with the PE file and opens it for reading. // It also validates that it matches the PE file. // It does not validate that the checksum matches, so we need to do that in the following block. if (peReader.TryOpenAssociatedPortablePdb(peFile, File.OpenRead, out var pdbReaderProvider, out var pdbPath) && // No need to validate embedded PDB (pdbPath == null for embedded) pdbPath != null) { // Get all checksum entries. There can be more than one. At least one must match the PDB. var checksumRecords = peReader.ReadDebugDirectory().Where(entry => entry.Type == DebugDirectoryEntryType.PdbChecksum) .Select(e => peReader.ReadPdbChecksumDebugDirectoryData(e)) .ToArray(); if (checksumRecords.Length == 0) { _telemetryService.TrackSymbolsValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Failed, nameof(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch)); return(ValidationResult.FailedWithIssues(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch)); } var pdbBytes = File.ReadAllBytes(pdbPath); var hashes = new Dictionary <string, byte[]>(); using (pdbReaderProvider) { var pdbReader = pdbReaderProvider.GetMetadataReader(); int idOffset = pdbReader.DebugMetadataHeader.IdStartOffset; foreach (var checksumRecord in checksumRecords) { if (!hashes.TryGetValue(checksumRecord.AlgorithmName, out var hash)) { HashAlgorithmName han = new HashAlgorithmName(checksumRecord.AlgorithmName); using (var hashAlg = IncrementalHash.CreateHash(han)) { hashAlg.AppendData(pdbBytes, 0, idOffset); hashAlg.AppendData(new byte[20]); int offset = idOffset + 20; int count = pdbBytes.Length - offset; hashAlg.AppendData(pdbBytes, offset, count); hash = hashAlg.GetHashAndReset(); } hashes.Add(checksumRecord.AlgorithmName, hash); } if (checksumRecord.Checksum.ToArray().SequenceEqual(hash)) { // found the right checksum _telemetryService.TrackSymbolsValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Succeeded, ""); return(ValidationResult.Succeeded); } } // Not found any checksum record that matches the PDB. _telemetryService.TrackSymbolsValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Failed, nameof(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch)); return(ValidationResult.FailedWithIssues(ValidationIssue.SymbolErrorCode_ChecksumDoesNotMatch)); } } } _telemetryService.TrackSymbolsValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Failed, nameof(ValidationIssue.SymbolErrorCode_MatchingPortablePDBNotFound)); return(ValidationResult.FailedWithIssues(ValidationIssue.SymbolErrorCode_MatchingPortablePDBNotFound)); } } // If did not return there were not any PE files to validate. In this case return error to not proceeed with an ingestion. _logger.LogError("{ValidatorName}: There were not any dll or exe files found locally." + "This could indicate an issue in the execution or the package was not correct created. PackageId {PackageId} PackageNormalizedVersion {PackageNormalizedVersion}. " + "SymbolCount: {SymbolCount}", ValidatorName.SymbolsValidator, packageId, packageNormalizedVersion, Directory.GetFiles(targetDirectory, SymbolExtensionPattern, SearchOption.AllDirectories)); _telemetryService.TrackSymbolsValidationResultEvent(packageId, packageNormalizedVersion, ValidationStatus.Failed, nameof(ValidationIssue.SymbolErrorCode_MatchingPortablePDBNotFound)); return(ValidationResult.FailedWithIssues(ValidationIssue.SymbolErrorCode_MatchingPortablePDBNotFound)); }
internal SignerInfoAsn Sign( ReadOnlyMemory <byte> data, string contentTypeOid, bool silent, out X509Certificate2Collection chainCerts) { HashAlgorithmName hashAlgorithmName = Helpers.GetDigestAlgorithm(DigestAlgorithm); IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithmName); hasher.AppendData(data.Span); byte[] dataHash = hasher.GetHashAndReset(); SignerInfoAsn newSignerInfo = new SignerInfoAsn(); newSignerInfo.DigestAlgorithm.Algorithm = DigestAlgorithm; if ((SignedAttributes != null && SignedAttributes.Count > 0) || contentTypeOid == null) { List <AttributeAsn> signedAttrs = BuildAttributes(SignedAttributes); using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.PushSetOf(); writer.WriteOctetString(dataHash); writer.PopSetOf(); signedAttrs.Add( new AttributeAsn { AttrType = new Oid(Oids.MessageDigest, Oids.MessageDigest), AttrValues = writer.Encode(), }); } if (contentTypeOid != null) { using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.PushSetOf(); writer.WriteObjectIdentifier(contentTypeOid); writer.PopSetOf(); signedAttrs.Add( new AttributeAsn { AttrType = new Oid(Oids.ContentType, Oids.ContentType), AttrValues = writer.Encode(), }); } } // Use the serializer/deserializer to DER-normalize the attribute order. newSignerInfo.SignedAttributes = Helpers.NormalizeSet( signedAttrs.ToArray(), normalized => { AsnReader reader = new AsnReader(normalized, AsnEncodingRules.DER); hasher.AppendData(reader.PeekContentBytes().Span); }); dataHash = hasher.GetHashAndReset(); } switch (SignerIdentifierType) { case SubjectIdentifierType.IssuerAndSerialNumber: byte[] serial = Certificate.GetSerialNumber(); Array.Reverse(serial); newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn { Issuer = Certificate.IssuerName.RawData, SerialNumber = serial, }; newSignerInfo.Version = 1; break; case SubjectIdentifierType.SubjectKeyIdentifier: newSignerInfo.Sid.SubjectKeyIdentifier = Certificate.GetSubjectKeyIdentifier(); newSignerInfo.Version = 3; break; case SubjectIdentifierType.NoSignature: newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn { Issuer = SubjectIdentifier.DummySignerEncodedValue, SerialNumber = new byte[1], }; newSignerInfo.Version = 1; break; default: Debug.Fail($"Unresolved SignerIdentifierType value: {SignerIdentifierType}"); throw new CryptographicException(); } if (UnsignedAttributes != null && UnsignedAttributes.Count > 0) { List <AttributeAsn> attrs = BuildAttributes(UnsignedAttributes); newSignerInfo.UnsignedAttributes = Helpers.NormalizeSet(attrs.ToArray()); } bool signed = CmsSignature.Sign( dataHash, hashAlgorithmName, Certificate, PrivateKey, silent, out Oid signatureAlgorithm, out ReadOnlyMemory <byte> signatureValue); if (!signed) { throw new CryptographicException(SR.Cryptography_Cms_CannotDetermineSignatureAlgorithm); } newSignerInfo.SignatureValue = signatureValue; newSignerInfo.SignatureAlgorithm.Algorithm = signatureAlgorithm; X509Certificate2Collection certs = new X509Certificate2Collection(); certs.AddRange(Certificates); if (SignerIdentifierType != SubjectIdentifierType.NoSignature) { if (IncludeOption == X509IncludeOption.EndCertOnly) { certs.Add(Certificate); } else if (IncludeOption != X509IncludeOption.None) { X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; if (!chain.Build(Certificate)) { foreach (X509ChainStatus status in chain.ChainStatus) { if (status.Status == X509ChainStatusFlags.PartialChain) { throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain); } } } X509ChainElementCollection elements = chain.ChainElements; int count = elements.Count; int last = count - 1; if (last == 0) { // If there's always one cert treat it as EE, not root. last = -1; } for (int i = 0; i < count; i++) { X509Certificate2 cert = elements[i].Certificate; if (i == last && IncludeOption == X509IncludeOption.ExcludeRoot && cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData)) { break; } certs.Add(cert); } } } chainCerts = certs; return(newSignerInfo); }
private byte[] InitKey(int mNumCyclesPower, byte[] salt, byte[] pass) { if (mNumCyclesPower == 0x3F) { var key = new byte[32]; int pos; for (pos = 0; pos < salt.Length; pos++) { key[pos] = salt[pos]; } for (int i = 0; i < pass.Length && pos < 32; i++) { key[pos++] = pass[i]; } return(key); } else { #if NETSTANDARD1_3 || NETSTANDARD2_0 using (IncrementalHash sha = IncrementalHash.CreateHash(HashAlgorithmName.SHA256)) { byte[] counter = new byte[8]; long numRounds = 1L << mNumCyclesPower; for (long round = 0; round < numRounds; round++) { sha.AppendData(salt, 0, salt.Length); sha.AppendData(pass, 0, pass.Length); sha.AppendData(counter, 0, 8); // This mirrors the counter so we don't have to convert long to byte[] each round. // (It also ensures the counter is little endian, which BitConverter does not.) for (int i = 0; i < 8; i++) { if (++counter[i] != 0) { break; } } } return(sha.GetHashAndReset()); } #else using (var sha = SHA256.Create()) { byte[] counter = new byte[8]; long numRounds = 1L << mNumCyclesPower; for (long round = 0; round < numRounds; round++) { sha.TransformBlock(salt, 0, salt.Length, null, 0); sha.TransformBlock(pass, 0, pass.Length, null, 0); sha.TransformBlock(counter, 0, 8, null, 0); // This mirrors the counter so we don't have to convert long to byte[] each round. // (It also ensures the counter is little endian, which BitConverter does not.) for (int i = 0; i < 8; i++) { if (++counter[i] != 0) { break; } } } sha.TransformFinalBlock(counter, 0, 0); return(sha.Hash); } #endif } }
public static void UnknownDigestAlgorithm() { Assert.ThrowsAny <CryptographicException>( () => IncrementalHash.CreateHash(new HashAlgorithmName("SHA0"))); }
/// <summary> /// Extracts the <see cref="ArchiveEntry"/> objects from a CPIO file. /// </summary> /// <param name="file"> /// The CPIO file from which to extract the entries. /// </param> /// <returns> /// A list of <see cref="ArchiveEntry"/> objects representing the data in the CPIO file. /// </returns> public List <ArchiveEntry> FromCpio(CpioFile file) { List <ArchiveEntry> value = new List <ArchiveEntry>(); byte[] buffer = new byte[1024]; byte[] fileHeader = null; while (file.Read()) { fileHeader = null; ArchiveEntry entry = new ArchiveEntry() { FileSize = file.EntryHeader.FileSize, Group = "root", Owner = "root", Inode = file.EntryHeader.Ino, Mode = file.EntryHeader.FileMode, Modified = file.EntryHeader.LastModified, TargetPath = file.FileName, Type = ArchiveEntryType.None, LinkTo = string.Empty, Sha256 = Array.Empty <byte>(), SourceFilename = null, IsAscii = true }; if (entry.Mode.HasFlag(LinuxFileMode.S_IFREG) && !entry.Mode.HasFlag(LinuxFileMode.S_IFLNK)) { using (var fileStream = file.Open()) using (var hasher = IncrementalHash.CreateHash(HashAlgorithmName.SHA256)) { int read; while (true) { read = fileStream.Read(buffer, 0, buffer.Length); if (fileHeader == null) { fileHeader = new byte[read]; Buffer.BlockCopy(buffer, 0, fileHeader, 0, read); } hasher.AppendData(buffer, 0, read); entry.IsAscii = entry.IsAscii && fileHeader.All(c => c < 128); if (read < buffer.Length) { break; } } entry.Sha256 = hasher.GetHashAndReset(); } entry.Type = this.GetArchiveEntryType(fileHeader); } else if (entry.Mode.HasFlag(LinuxFileMode.S_IFLNK)) { using (var fileStrema = file.Open()) using (var reader = new StreamReader(fileStrema, Encoding.UTF8)) { entry.LinkTo = reader.ReadToEnd(); } } else { file.Skip(); } if (entry.Mode.HasFlag(LinuxFileMode.S_IFDIR)) { entry.FileSize = 0x1000; } if (entry.TargetPath.StartsWith(".")) { entry.TargetPath = entry.TargetPath.Substring(1); } value.Add(entry); } return(value); }
public IncrementalHasher() { _hasher = IncrementalHash.CreateHash(HashAlgorithmName.SHA256); _buffer = ArrayPool <byte> .Shared.Rent(s_bufferByteSize); }
protected void AddFile(string entry, string relativePath, string prefix, List <ArchiveEntry> value, ITaskItem[] metadata) { var fileName = Path.GetFileName(entry); byte[] fileHeader = null; byte[] hash = null; byte[] md5hash = null; byte[] buffer = new byte[1024]; bool isAscii = true; var fileMetadata = metadata.SingleOrDefault(m => m.IsPublished() && string.Equals(relativePath, m.GetPublishedPath())); using (Stream fileStream = File.OpenRead(entry)) { if (fileName.StartsWith(".") || fileStream.Length == 0) { // Skip hidden and empty files - this would case rmplint errors. return; } using (var hasher = IncrementalHash.CreateHash(HashAlgorithmName.SHA256)) using (var md5hasher = IncrementalHash.CreateHash(HashAlgorithmName.MD5)) { int read; while (true) { read = fileStream.Read(buffer, 0, buffer.Length); if (fileHeader == null) { fileHeader = new byte[read]; Buffer.BlockCopy(buffer, 0, fileHeader, 0, read); } hasher.AppendData(buffer, 0, read); md5hasher.AppendData(buffer, 0, read); isAscii = isAscii && buffer.All(c => c < 128); if (read < buffer.Length) { break; } } hash = hasher.GetHashAndReset(); md5hash = md5hasher.GetHashAndReset(); } // Only support ELF32 and ELF64 colors; otherwise default to BLACK. ArchiveEntryType entryType = this.GetArchiveEntryType(fileHeader); var mode = LinuxFileMode.S_IROTH | LinuxFileMode.S_IRGRP | LinuxFileMode.S_IRUSR | LinuxFileMode.S_IFREG; if (entryType == ArchiveEntryType.Executable32 || entryType == ArchiveEntryType.Executable64) { mode |= LinuxFileMode.S_IXOTH | LinuxFileMode.S_IXGRP | LinuxFileMode.S_IWUSR | LinuxFileMode.S_IXUSR; } // If a Linux path has been specified, use that one, else, use the default one based on the prefix // + current file name. string name = fileMetadata?.GetLinuxPath(); if (name == null) { name = prefix + "/" + fileName; } string linkTo = string.Empty; if (mode.HasFlag(LinuxFileMode.S_IFLNK)) { // Find the link text int stringEnd = 0; while (stringEnd < fileHeader.Length - 1 && fileHeader[stringEnd] != 0) { stringEnd++; } linkTo = Encoding.UTF8.GetString(fileHeader, 0, stringEnd + 1); hash = new byte[] { }; } // If the user has chosen to override the file node, respect that var overridenFileMode = fileMetadata?.GetLinuxFileMode(); if (overridenFileMode != null) { // We expect the user to specify the file mode in its octal representation. try { mode = (LinuxFileMode)Convert.ToUInt32(overridenFileMode, 8); } catch (Exception ex) { throw new Exception($"Could not parse the file mode '{overridenFileMode}' for file '{name}'. Make sure to set the LinuxFileMode attriubute to an octal representation of a Unix file mode."); } } ArchiveEntry archiveEntry = new ArchiveEntry() { FileSize = (uint)fileStream.Length, Group = fileMetadata.GetGroup(), Owner = fileMetadata.GetOwner(), Modified = File.GetLastAccessTimeUtc(entry), SourceFilename = entry, TargetPath = name, Sha256 = hash, Md5Hash = md5hash, Type = entryType, LinkTo = linkTo, Inode = this.inode++, IsAscii = isAscii, Mode = mode }; value.Add(archiveEntry); } }
public static async Task <string> UploadStreamAsync(this S3Helper s3, string bucketName, string key, Stream inputStream, string keyId = null, string contentType = "application/octet-stream", bool throwIfAlreadyExists = false, int msTimeout = int.MaxValue, CancellationToken cancellationToken = default(CancellationToken)) { CancellationToken ct; void UpdateCancellationToken() { if (cancellationToken != null) { ct = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken).Token; } else { ct = new CancellationTokenSource().Token; } } UpdateCancellationToken(); if (throwIfAlreadyExists && await s3.ObjectExistsAsync(bucketName: bucketName, key: key, cancellationToken: ct) .TryCancelAfter(ct, msTimeout: msTimeout)) { throw new Exception($"Object {key} in bucket {bucketName} already exists."); } if (keyId == "") { keyId = null; } if (keyId != null && !keyId.IsGuid()) { UpdateCancellationToken(); var alias = await(new KMSHelper(s3._credentials)).GetKeyAliasByNameAsync(name: keyId, cancellationToken: ct) .TryCancelAfter(ct, msTimeout: msTimeout); keyId = alias.TargetKeyId; } var bufferSize = 128 * 1024; var blob = inputStream.ToMemoryBlob(maxLength: s3.MaxSinglePartSize, bufferSize: bufferSize); var ih = IncrementalHash.CreateHash(HashAlgorithmName.MD5); string md5, etag; if (blob.Length < s3.MaxSinglePartSize) { UpdateCancellationToken(); using (var ms = blob.CopyToMemoryStream(bufferSize: (int)blob.Length)) { var spResult = s3.PutObjectAsync(bucketName: bucketName, key: key, inputStream: ms, keyId: keyId, cancellationToken: ct, contentType: contentType) .TryCancelAfter(ct, msTimeout: msTimeout); blob.Seek(0, SeekOrigin.Begin); ih.AppendData(blob.ToArray()); md5 = ih.GetHashAndReset().ToHexString(); etag = (await spResult).ETag.Trim('"'); return(md5); } } UpdateCancellationToken(); var init = await s3.InitiateMultipartUploadAsync(bucketName, key, contentType : contentType, keyId : keyId, cancellationToken : ct) .TryCancelAfter(ct, msTimeout: msTimeout); var partNumber = 0; var tags = new List <PartETag>(); while (blob.Length > 0) { partNumber = ++partNumber; UpdateCancellationToken(); //copy so new part can be read at the same time using (var ms = blob.CopyToMemoryStream(bufferSize: (int)blob.Length)) { var tUpload = s3.UploadPartAsync( bucketName: bucketName, key: key, uploadId: init.UploadId, partNumber: partNumber, partSize: (int)ms.Length, inputStream: ms, progress: null, cancellationToken: ct).TryCancelAfter(ct, msTimeout: msTimeout); if (ct.IsCancellationRequested) { throw new OperationCanceledException("Operation was cancelled or timed out."); } if (blob.Length <= s3.DefaultPartSize) //read next part from input before stream gets uploaded { blob = inputStream.ToMemoryBlob(maxLength: s3.DefaultPartSize, bufferSize: bufferSize); } tags.Add(new PartETag(partNumber, (await tUpload).ETag)); ms.Seek(0, SeekOrigin.Begin); ih.AppendData(ms.ToArray()); } } UpdateCancellationToken(); var mpResult = await s3.CompleteMultipartUploadAsync( bucketName : bucketName, key : key, uploadId : init.UploadId, partETags : tags, cancellationToken : ct).TryCancelAfter(ct, msTimeout: msTimeout); md5 = ih.GetHashAndReset().ToHexString(); etag = mpResult.ETag.Trim('"'); return(md5); }
protected override object GetInitialState(BinarySerializationContext context) { return(IncrementalHash.CreateHash(HashAlgorithmName.SHA256)); }
internal SignerInfoAsn Sign( ReadOnlyMemory <byte> data, string contentTypeOid, bool silent, out X509Certificate2Collection chainCerts) { HashAlgorithmName hashAlgorithmName = PkcsHelpers.GetDigestAlgorithm(DigestAlgorithm); IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithmName); hasher.AppendData(data.Span); byte[] dataHash = hasher.GetHashAndReset(); SignerInfoAsn newSignerInfo = default; newSignerInfo.DigestAlgorithm.Algorithm = DigestAlgorithm; // If the user specified attributes (not null, count > 0) we need attributes. // If the content type is null we're counter-signing, and need the message digest attr. // If the content type is otherwise not-data we need to record it as the content-type attr. if (SignedAttributes?.Count > 0 || contentTypeOid != Oids.Pkcs7Data) { List <AttributeAsn> signedAttrs = BuildAttributes(SignedAttributes); using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.WriteOctetString(dataHash); signedAttrs.Add( new AttributeAsn { AttrType = new Oid(Oids.MessageDigest, Oids.MessageDigest), AttrValues = new[] { new ReadOnlyMemory <byte>(writer.Encode()) }, }); } if (contentTypeOid != null) { using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.WriteObjectIdentifier(contentTypeOid); signedAttrs.Add( new AttributeAsn { AttrType = new Oid(Oids.ContentType, Oids.ContentType), AttrValues = new[] { new ReadOnlyMemory <byte>(writer.Encode()) }, }); } } // Use the serializer/deserializer to DER-normalize the attribute order. SignedAttributesSet signedAttrsSet = default; signedAttrsSet.SignedAttributes = PkcsHelpers.NormalizeAttributeSet( signedAttrs.ToArray(), normalized => hasher.AppendData(normalized)); // Since this contains user data in a context where BER is permitted, use BER. // There shouldn't be any observable difference here between BER and DER, though, // since the top level fields were written by NormalizeSet. using (AsnWriter attrsWriter = new AsnWriter(AsnEncodingRules.BER)) { signedAttrsSet.Encode(attrsWriter); newSignerInfo.SignedAttributes = attrsWriter.Encode(); } dataHash = hasher.GetHashAndReset(); } switch (SignerIdentifierType) { case SubjectIdentifierType.IssuerAndSerialNumber: byte[] serial = Certificate.GetSerialNumber(); Array.Reverse(serial); newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn { Issuer = Certificate.IssuerName.RawData, SerialNumber = serial, }; newSignerInfo.Version = 1; break; case SubjectIdentifierType.SubjectKeyIdentifier: newSignerInfo.Sid.SubjectKeyIdentifier = PkcsPal.Instance.GetSubjectKeyIdentifier(Certificate); newSignerInfo.Version = 3; break; case SubjectIdentifierType.NoSignature: newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn { Issuer = SubjectIdentifier.DummySignerEncodedValue, SerialNumber = new byte[1], }; newSignerInfo.Version = 1; break; default: Debug.Fail($"Unresolved SignerIdentifierType value: {SignerIdentifierType}"); throw new CryptographicException(); } if (UnsignedAttributes != null && UnsignedAttributes.Count > 0) { List <AttributeAsn> attrs = BuildAttributes(UnsignedAttributes); newSignerInfo.UnsignedAttributes = PkcsHelpers.NormalizeAttributeSet(attrs.ToArray()); } bool signed; Oid signatureAlgorithm; ReadOnlyMemory <byte> signatureValue; if (SignerIdentifierType == SubjectIdentifierType.NoSignature) { signatureAlgorithm = new Oid(Oids.NoSignature, null); signatureValue = dataHash; signed = true; } else { signed = CmsSignature.Sign( dataHash, hashAlgorithmName, Certificate, PrivateKey, silent, out signatureAlgorithm, out signatureValue); } if (!signed) { throw new CryptographicException(SR.Cryptography_Cms_CannotDetermineSignatureAlgorithm); } newSignerInfo.SignatureValue = signatureValue; newSignerInfo.SignatureAlgorithm.Algorithm = signatureAlgorithm; X509Certificate2Collection certs = new X509Certificate2Collection(); certs.AddRange(Certificates); if (SignerIdentifierType != SubjectIdentifierType.NoSignature) { if (IncludeOption == X509IncludeOption.EndCertOnly) { certs.Add(Certificate); } else if (IncludeOption != X509IncludeOption.None) { X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; if (!chain.Build(Certificate)) { foreach (X509ChainStatus status in chain.ChainStatus) { if (status.Status == X509ChainStatusFlags.PartialChain) { throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain); } } } X509ChainElementCollection elements = chain.ChainElements; int count = elements.Count; int last = count - 1; if (last == 0) { // If there's always one cert treat it as EE, not root. last = -1; } for (int i = 0; i < count; i++) { X509Certificate2 cert = elements[i].Certificate; if (i == last && IncludeOption == X509IncludeOption.ExcludeRoot && cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData)) { break; } certs.Add(cert); } } } chainCerts = certs; return(newSignerInfo); }
public void SealWithMac( ReadOnlySpan <char> password, HashAlgorithmName hashAlgorithm, int iterationCount) { if (iterationCount < 1) { throw new ArgumentOutOfRangeException(nameof(iterationCount)); } if (IsSealed) { throw new InvalidOperationException(SR.Cryptography_Pkcs12_PfxIsSealed); } byte[]? rentedAuthSafe = null; Span <byte> authSafeSpan = default; byte[]? rentedMac = null; Span <byte> macSpan = default; Span <byte> salt = stackalloc byte[0]; try { AsnWriter contentsWriter = new AsnWriter(AsnEncodingRules.BER); using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithm)) { contentsWriter.PushSequence(); if (_contents != null) { foreach (ContentInfoAsn contentInfo in _contents) { contentInfo.Encode(contentsWriter); } } contentsWriter.PopSequence(); rentedAuthSafe = CryptoPool.Rent(contentsWriter.GetEncodedLength()); if (!contentsWriter.TryEncode(rentedAuthSafe, out int written)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new InvalidOperationException(); } authSafeSpan = rentedAuthSafe.AsSpan(0, written); // Get an array of the proper size for the hash. byte[] macKey = hasher.GetHashAndReset(); rentedMac = CryptoPool.Rent(macKey.Length); macSpan = rentedMac.AsSpan(0, macKey.Length); // Since the biggest supported hash is SHA-2-512 (64 bytes), the // 128-byte cap here shouldn't ever come into play. Debug.Assert(macKey.Length <= 128); salt = stackalloc byte[Math.Min(macKey.Length, 128)]; RandomNumberGenerator.Fill(salt); Pkcs12Kdf.DeriveMacKey( password, hashAlgorithm, iterationCount, salt, macKey); using (IncrementalHash mac = IncrementalHash.CreateHMAC(hashAlgorithm, macKey)) { mac.AppendData(authSafeSpan); if (!mac.TryGetHashAndReset(macSpan, out int bytesWritten) || bytesWritten != macSpan.Length) { Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} of {macSpan.Length} bytes"); throw new CryptographicException(); } } } // https://tools.ietf.org/html/rfc7292#section-4 // // PFX ::= SEQUENCE { // version INTEGER {v3(3)}(v3,...), // authSafe ContentInfo, // macData MacData OPTIONAL // } AsnWriter writer = new AsnWriter(AsnEncodingRules.BER); { writer.PushSequence(); writer.WriteInteger(3); writer.PushSequence(); { writer.WriteObjectIdentifierForCrypto(Oids.Pkcs7Data); Asn1Tag contextSpecific0 = new Asn1Tag(TagClass.ContextSpecific, 0); writer.PushSequence(contextSpecific0); { writer.WriteOctetString(authSafeSpan); writer.PopSequence(contextSpecific0); } writer.PopSequence(); } // https://tools.ietf.org/html/rfc7292#section-4 // // MacData ::= SEQUENCE { // mac DigestInfo, // macSalt OCTET STRING, // iterations INTEGER DEFAULT 1 // -- Note: The default is for historical reasons and its use is // -- deprecated. // } writer.PushSequence(); { writer.PushSequence(); { writer.PushSequence(); { writer.WriteObjectIdentifierForCrypto(PkcsHelpers.GetOidFromHashAlgorithm(hashAlgorithm)); writer.PopSequence(); } writer.WriteOctetString(macSpan); writer.PopSequence(); } writer.WriteOctetString(salt); if (iterationCount > 1) { writer.WriteInteger(iterationCount); } writer.PopSequence(); } writer.PopSequence(); _sealedData = writer.Encode(); } } finally { CryptographicOperations.ZeroMemory(macSpan); CryptographicOperations.ZeroMemory(authSafeSpan); if (rentedMac != null) { // Already cleared CryptoPool.Return(rentedMac, clearSize: 0); } if (rentedAuthSafe != null) { // Already cleared CryptoPool.Return(rentedAuthSafe, clearSize: 0); } } }