internal void Decode(ReadOnlyMemory <byte> encodedMessage) { AsnValueReader reader = new AsnValueReader(encodedMessage.Span, AsnEncodingRules.BER); // Windows (and thus NetFx) reads the leading data and ignores extra. // So use the Decode overload which doesn't throw on extra data. ContentInfoAsn.Decode( ref reader, encodedMessage, out ContentInfoAsn contentInfo); if (contentInfo.ContentType != Oids.Pkcs7Signed) { throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType); } // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller. _heldData = contentInfo.Content.ToArray(); _signedData = SignedDataAsn.Decode(_heldData, AsnEncodingRules.BER); _contentType = _signedData.EncapContentInfo.ContentType; _hasPkcs7Content = false; if (!Detached) { ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content; ReadOnlyMemory <byte> contentValue; if (content.HasValue) { contentValue = GetContent(content.Value, _contentType); // If no OCTET STRING was stripped off, we have PKCS7 interop concerns. _hasPkcs7Content = content.Value.Length == contentValue.Length; } else { contentValue = ReadOnlyMemory <byte> .Empty; } // This is in _heldData, so we don't need a defensive copy. _heldContent = contentValue; // The ContentInfo object/property DOES need a defensive copy, because // a) it is mutable by the user, and // b) it is no longer authoritative // // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>) ContentInfo = new ContentInfo(new Oid(_contentType), contentValue.ToArray()); } else { // Hold a defensive copy of the content bytes, (Windows/NetFx compat) _heldContent = ContentInfo.Content.CloneByteArray(); } Version = _signedData.Version; _hasData = true; }
private void WithSelfInfo(WithSelfInfoDelegate action) { if (_parentSignerInfo == null) { int myIdx = _document.SignerInfos.FindIndexForSigner(this); if (myIdx < 0) { throw new CryptographicException(SR.Cryptography_Cms_SignerNotFound); } ref SignedDataAsn signedData = ref _document.GetRawData(); ref SignerInfoAsn mySigner = ref signedData.SignerInfos[myIdx];
public void Decode(byte[] encodedMessage) { if (encodedMessage == null) { throw new ArgumentNullException(nameof(encodedMessage)); } // Windows (and thus NetFx) reads the leading data and ignores extra. // The deserializer will complain if too much data is given, so use the reader // to ask how much we want to deserialize. AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER); ReadOnlyMemory <byte> cmsSegment = reader.GetEncodedValue(); ContentInfoAsn contentInfo = AsnSerializer.Deserialize <ContentInfoAsn>(cmsSegment, AsnEncodingRules.BER); if (contentInfo.ContentType != Oids.Pkcs7Signed) { throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType); } // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller. _heldData = contentInfo.Content.ToArray(); _signedData = AsnSerializer.Deserialize <SignedDataAsn>(_heldData, AsnEncodingRules.BER); _contentType = _signedData.EncapContentInfo.ContentType; if (!Detached) { ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content; // This is in _heldData, so we don't need a defensive copy. _heldContent = content ?? ReadOnlyMemory <byte> .Empty; // The ContentInfo object/property DOES need a defensive copy, because // a) it is mutable by the user, and // b) it is no longer authoritative // // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>) ContentInfo = new ContentInfo(new Oid(_contentType), _heldContent.Value.ToArray()); } else { // Hold a defensive copy of the content bytes, (Windows/NetFx compat) _heldContent = ContentInfo.Content.CloneByteArray(); } Version = _signedData.Version; _hasData = true; }
public byte[] Encode() { if (!_hasData) { throw new InvalidOperationException(SR.Cryptography_Cms_MessageNotSigned); } try { using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) { _signedData.Encode(writer); return(PkcsHelpers.EncodeContentInfo(writer.Encode(), Oids.Pkcs7Signed)); } } catch (CryptographicException) when(!Detached) { // If we can't write the contents back out then the most likely culprit is an // indefinite length encoding in the content field. To preserve as much input data // as possible while still maintaining our expectations of sorting any SET OF values, // do the following: // * Write the DER normalized version of the SignedData in detached mode. // * BER-decode that structure // * Copy the content field over // * BER-write the modified structure. SignedDataAsn copy = _signedData; copy.EncapContentInfo.Content = null; Debug.Assert(_signedData.EncapContentInfo.Content != null); using (AsnWriter detachedWriter = new AsnWriter(AsnEncodingRules.DER)) { copy.Encode(detachedWriter); copy = SignedDataAsn.Decode(detachedWriter.Encode(), AsnEncodingRules.BER); } copy.EncapContentInfo.Content = _signedData.EncapContentInfo.Content; using (AsnWriter attachedWriter = new AsnWriter(AsnEncodingRules.BER)) { copy.Encode(attachedWriter); return(PkcsHelpers.EncodeContentInfo(attachedWriter.Encode(), Oids.Pkcs7Signed)); } } }
internal void Decode(ReadOnlyMemory <byte> encodedMessage) { // Windows (and thus NetFx) reads the leading data and ignores extra. // So use the Deserialize overload which doesn't throw on extra data. ContentInfoAsn contentInfo = AsnSerializer.Deserialize <ContentInfoAsn>( encodedMessage, AsnEncodingRules.BER, out int bytesRead); if (contentInfo.ContentType != Oids.Pkcs7Signed) { throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType); } // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller. _heldData = contentInfo.Content.ToArray(); _signedData = AsnSerializer.Deserialize <SignedDataAsn>(_heldData, AsnEncodingRules.BER); _contentType = _signedData.EncapContentInfo.ContentType; if (!Detached) { ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content; // This is in _heldData, so we don't need a defensive copy. _heldContent = content ?? ReadOnlyMemory <byte> .Empty; // The ContentInfo object/property DOES need a defensive copy, because // a) it is mutable by the user, and // b) it is no longer authoritative // // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>) ContentInfo = new ContentInfo(new Oid(_contentType), _heldContent.Value.ToArray()); } else { // Hold a defensive copy of the content bytes, (Windows/NetFx compat) _heldContent = ContentInfo.Content.CloneByteArray(); } Version = _signedData.Version; _hasData = true; }
public void Decode(ReadOnlySpan <byte> encodedMessage) { // Hold a copy of the SignedData memory so we are protected against memory reuse by the caller. _heldData = CopyContent(encodedMessage); _signedData = SignedDataAsn.Decode(_heldData, AsnEncodingRules.BER); _contentType = _signedData.EncapContentInfo.ContentType; _hasPkcs7Content = false; if (!Detached) { ReadOnlyMemory <byte>?content = _signedData.EncapContentInfo.Content; ReadOnlyMemory <byte> contentValue; if (content.HasValue) { contentValue = GetContent(content.Value, _contentType); // If no OCTET STRING was stripped off, we have PKCS7 interop concerns. _hasPkcs7Content = content.Value.Length == contentValue.Length; } else { contentValue = ReadOnlyMemory <byte> .Empty; } // This is in _heldData, so we don't need a defensive copy. _heldContent = contentValue; // The ContentInfo object/property DOES need a defensive copy, because // a) it is mutable by the user, and // b) it is no longer authoritative // // (and c: it takes a byte[] and we have a ReadOnlyMemory<byte>) ContentInfo = new ContentInfo(new Oid(_contentType), contentValue.ToArray()); } else { // Hold a defensive copy of the content bytes, (Windows/NetFx compat) _heldContent = ContentInfo.Content.CloneByteArray(); } Version = _signedData.Version; _hasData = true;
public void ComputeSignature(CmsSigner signer, bool silent) { if (signer == null) { throw new ArgumentNullException(nameof(signer)); } // While it shouldn't be possible to change the length of ContentInfo.Content // after it's built, use the property at this stage, then use the saved value // (if applicable) after this point. if (ContentInfo.Content.Length == 0) { throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content); } if (_hasData && signer.SignerIdentifierType == SubjectIdentifierType.NoSignature) { // Even if all signers have been removed, throw if doing a NoSignature signature // on a loaded (from file, or from first signature) document. // // This matches the .NET Framework behavior. throw new CryptographicException(SR.Cryptography_Cms_Sign_No_Signature_First_Signer); } if (signer.Certificate == null && signer.SignerIdentifierType != SubjectIdentifierType.NoSignature) { if (silent) { // .NET Framework compatibility, silent disallows prompting, so throws InvalidOperationException // in this state. // // The message is different than on NetFX, because the resource string was for // enveloped CMS recipients (and the other site which would use that resource // is unreachable code due to CmsRecipient's ctor guarding against null certificates) throw new InvalidOperationException(SR.Cryptography_Cms_NoSignerCertSilent); } // Otherwise, PNSE. .NET Core doesn't support launching the cert picker UI. throw new PlatformNotSupportedException(SR.Cryptography_Cms_NoSignerCert); } // If we had content already, use that now. // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content) ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content; string contentType = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data; X509Certificate2Collection chainCerts; SignerInfoAsn newSigner = signer.Sign(content, contentType, silent, out chainCerts); bool firstSigner = false; if (!_hasData) { firstSigner = true; _signedData = new SignedDataAsn { DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(), SignerInfos = Array.Empty <SignerInfoAsn>(), EncapContentInfo = new EncapsulatedContentInfoAsn { ContentType = contentType }, }; // Since we're going to call Decode before this method exits we don't need to save // the copy of _heldContent or _contentType here if we're attached. if (!Detached) { using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) { writer.WriteOctetString(content.Span); _signedData.EncapContentInfo.Content = writer.Encode(); } } _hasData = true; } int newIdx = _signedData.SignerInfos.Length; Array.Resize(ref _signedData.SignerInfos, newIdx + 1); _signedData.SignerInfos[newIdx] = newSigner; UpdateCertificatesFromAddition(chainCerts); ConsiderDigestAddition(newSigner.DigestAlgorithm); UpdateMetadata(); if (firstSigner) { Reencode(); Debug.Assert(_heldContent != null); Debug.Assert(_contentType == contentType); } }
public void ComputeSignature(CmsSigner signer, bool silent) { if (signer == null) { throw new ArgumentNullException(nameof(signer)); } // While it shouldn't be possible to change the length of ContentInfo.Content // after it's built, use the property at this stage, then use the saved value // (if applicable) after this point. if (ContentInfo.Content.Length == 0) { throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content); } // If we had content already, use that now. // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content) ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content; string contentType = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data; X509Certificate2Collection chainCerts; SignerInfoAsn newSigner = signer.Sign(content, contentType, silent, out chainCerts); bool firstSigner = false; if (!_hasData) { firstSigner = true; _signedData = new SignedDataAsn { DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(), SignerInfos = Array.Empty <SignerInfoAsn>(), EncapContentInfo = new EncapsulatedContentInfoAsn { ContentType = contentType }, }; // Since we're going to call Decode before this method exits we don't need to save // the copy of _heldContent or _contentType here if we're attached. if (!Detached) { using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) { writer.WriteOctetString(content.Span); _signedData.EncapContentInfo.Content = writer.Encode(); } } _hasData = true; } int newIdx = _signedData.SignerInfos.Length; Array.Resize(ref _signedData.SignerInfos, newIdx + 1); _signedData.SignerInfos[newIdx] = newSigner; UpdateCertificatesFromAddition(chainCerts); ConsiderDigestAddition(newSigner.DigestAlgorithm); UpdateMetadata(); if (firstSigner) { Reencode(); Debug.Assert(_heldContent != null); Debug.Assert(_contentType == contentType); } }
public static Pkcs12Info Decode( ReadOnlyMemory <byte> encodedBytes, out int bytesConsumed, bool skipCopy = false) { AsnReader reader = new AsnReader(encodedBytes, AsnEncodingRules.BER); // Trim it to the first value encodedBytes = reader.PeekEncodedValue(); ReadOnlyMemory <byte> maybeCopy = skipCopy ? encodedBytes : encodedBytes.ToArray(); PfxAsn pfx = PfxAsn.Decode(maybeCopy, AsnEncodingRules.BER); // https://tools.ietf.org/html/rfc7292#section-4 only defines version 3. if (pfx.Version != 3) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } ReadOnlyMemory <byte> authSafeBytes = ReadOnlyMemory <byte> .Empty; Pkcs12IntegrityMode mode = Pkcs12IntegrityMode.Unknown; if (pfx.AuthSafe.ContentType == Oids.Pkcs7Data) { authSafeBytes = PkcsHelpers.DecodeOctetStringAsMemory(pfx.AuthSafe.Content); if (pfx.MacData.HasValue) { mode = Pkcs12IntegrityMode.Password; } else { mode = Pkcs12IntegrityMode.None; } } else if (pfx.AuthSafe.ContentType == Oids.Pkcs7Signed) { SignedDataAsn signedData = SignedDataAsn.Decode(pfx.AuthSafe.Content, AsnEncodingRules.BER); mode = Pkcs12IntegrityMode.PublicKey; if (signedData.EncapContentInfo.ContentType == Oids.Pkcs7Data) { authSafeBytes = signedData.EncapContentInfo.Content.GetValueOrDefault(); } if (pfx.MacData.HasValue) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } } if (mode == Pkcs12IntegrityMode.Unknown) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } List <ContentInfoAsn> authSafeData = new List <ContentInfoAsn>(); AsnReader authSafeReader = new AsnReader(authSafeBytes, AsnEncodingRules.BER); AsnReader sequenceReader = authSafeReader.ReadSequence(); authSafeReader.ThrowIfNotEmpty(); while (sequenceReader.HasData) { ContentInfoAsn.Decode(sequenceReader, out ContentInfoAsn contentInfo); authSafeData.Add(contentInfo); } ReadOnlyCollection <Pkcs12SafeContents> authSafe; if (authSafeData.Count == 0) { authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(Array.Empty <Pkcs12SafeContents>()); } else { Pkcs12SafeContents[] contentsArray = new Pkcs12SafeContents[authSafeData.Count]; for (int i = 0; i < contentsArray.Length; i++) { contentsArray[i] = new Pkcs12SafeContents(authSafeData[i]); } authSafe = new ReadOnlyCollection <Pkcs12SafeContents>(contentsArray); } bytesConsumed = encodedBytes.Length; return(new Pkcs12Info { AuthenticatedSafe = authSafe, IntegrityMode = mode, _decoded = pfx, _authSafeContents = authSafeBytes, }); }