Imported Upstream version 5.16.0.100

Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-08-07 15:19:03 +00:00
parent 0a9828183b
commit 7d7f676260
4419 changed files with 170950 additions and 90273 deletions

View File

@@ -8,6 +8,12 @@
<ProjectReference Include="..\src\System.Security.Cryptography.Pkcs.csproj" />
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
<HarvestIncludePaths Include="ref/netstandard1.3;runtimes/win/lib/netstandard1.3;lib/netstandard1.3" />
<!--
Suppress NETStandard.Library collpasing as it add more dependencies then needed in some
scenarios like .NET Framework which adds an unecessary amount of package dependencies to download
-->
<SuppressMetaPackage Include="NETStandard.Library" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -20,8 +20,8 @@ namespace System.Security.Cryptography
public CryptographicAttributeObjectCollection(System.Security.Cryptography.CryptographicAttributeObject attribute) { }
public int Count { get { throw null; } }
public System.Security.Cryptography.CryptographicAttributeObject this[int index] { get { throw null; } }
bool System.Collections.ICollection.IsSynchronized { get { throw null; } }
object System.Collections.ICollection.SyncRoot { get { throw null; } }
public bool IsSynchronized { get { throw null; } }
public object SyncRoot { get { throw null; } }
public int Add(System.Security.Cryptography.AsnEncodedData asnEncodedData) { throw null; }
public int Add(System.Security.Cryptography.CryptographicAttributeObject attribute) { throw null; }
public void CopyTo(System.Security.Cryptography.CryptographicAttributeObject[] array, int index) { }
@@ -48,6 +48,7 @@ namespace System.Security.Cryptography.Pkcs
public AlgorithmIdentifier(System.Security.Cryptography.Oid oid, int keyLength) { }
public int KeyLength { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Security.Cryptography.Oid Oid { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public byte[] Parameters { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
public sealed partial class CmsRecipient
{
@@ -63,8 +64,8 @@ namespace System.Security.Cryptography.Pkcs
public CmsRecipientCollection(System.Security.Cryptography.Pkcs.SubjectIdentifierType recipientIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2Collection certificates) { }
public int Count { get { throw null; } }
public System.Security.Cryptography.Pkcs.CmsRecipient this[int index] { get { throw null; } }
bool System.Collections.ICollection.IsSynchronized { get { throw null; } }
object System.Collections.ICollection.SyncRoot { get { throw null; } }
public bool IsSynchronized { get { throw null; } }
public object SyncRoot { get { throw null; } }
public int Add(System.Security.Cryptography.Pkcs.CmsRecipient recipient) { throw null; }
public void CopyTo(System.Array array, int index) { }
public void CopyTo(System.Security.Cryptography.Pkcs.CmsRecipient[] array, int index) { }
@@ -91,9 +92,9 @@ namespace System.Security.Cryptography.Pkcs
public SubjectIdentifierType SignerIdentifierType { get => throw null; set => throw null; }
public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate { get => throw null; set => throw null; }
public Oid DigestAlgorithm { get => throw null; set => throw null; }
public CryptographicAttributeObjectCollection SignedAttributes { get => throw null; set => throw null; }
public CryptographicAttributeObjectCollection UnsignedAttributes { get => throw null; set => throw null; }
public System.Security.Cryptography.X509Certificates.X509Certificate2Collection Certificates { get => throw null; set => throw null; }
public CryptographicAttributeObjectCollection SignedAttributes { get => throw null; }
public CryptographicAttributeObjectCollection UnsignedAttributes { get => throw null; }
public System.Security.Cryptography.X509Certificates.X509Certificate2Collection Certificates { get => throw null; }
public System.Security.Cryptography.X509Certificates.X509IncludeOption IncludeOption { get => throw null; set => throw null; }
}
public sealed partial class ContentInfo
@@ -208,8 +209,8 @@ namespace System.Security.Cryptography.Pkcs
internal RecipientInfoCollection() { }
public int Count { get { throw null; } }
public System.Security.Cryptography.Pkcs.RecipientInfo this[int index] { get { throw null; } }
bool System.Collections.ICollection.IsSynchronized { get { throw null; } }
object System.Collections.ICollection.SyncRoot { get { throw null; } }
public bool IsSynchronized { get { throw null; } }
public object SyncRoot { get { throw null; } }
public void CopyTo(System.Array array, int index) { }
public void CopyTo(System.Security.Cryptography.Pkcs.RecipientInfo[] array, int index) { }
public System.Security.Cryptography.Pkcs.RecipientInfoEnumerator GetEnumerator() { throw null; }

View File

@@ -24,6 +24,7 @@
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.Csp\ref\System.Security.Cryptography.Csp.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.Encoding\ref\System.Security.Cryptography.Encoding.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.Primitives\ref\System.Security.Cryptography.Primitives.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.X509Certificates\ref\System.Security.Cryptography.X509Certificates.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />

View File

@@ -5,8 +5,60 @@
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
using System.Security.Cryptography.X509Certificates;
namespace System.Security.Cryptography.Pkcs
{
public sealed partial class Rfc3161TimestampRequest
{
private Rfc3161TimestampRequest() { }
public int Version => throw null;
public ReadOnlyMemory<byte> GetMessageHash() => throw null;
public Oid HashAlgorithmId => throw null;
public Oid RequestedPolicyId => throw null;
public bool RequestSignerCertificate => throw null;
public ReadOnlyMemory<byte>? GetNonce() => throw null;
public bool HasExtensions => throw null;
public X509ExtensionCollection GetExtensions() => throw null;
public byte[] Encode() => throw null;
public bool TryEncode(Span<byte> destination, out int bytesWritten) => throw null;
public Rfc3161TimestampToken ProcessResponse(ReadOnlyMemory<byte> responseBytes, out int bytesConsumed) => throw null;
public static Rfc3161TimestampRequest CreateFromData(ReadOnlySpan<byte> data, HashAlgorithmName hashAlgorithm, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
public static Rfc3161TimestampRequest CreateFromHash(ReadOnlyMemory<byte> hash, HashAlgorithmName hashAlgorithm, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
public static Rfc3161TimestampRequest CreateFromHash(ReadOnlyMemory<byte> hash, Oid hashAlgorithmId, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
public static Rfc3161TimestampRequest CreateFromSignerInfo(SignerInfo signerInfo, HashAlgorithmName hashAlgorithm, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
public static bool TryDecode(ReadOnlyMemory<byte> encodedBytes, out Rfc3161TimestampRequest request, out int bytesConsumed) => throw null;
}
public sealed partial class Rfc3161TimestampToken
{
private Rfc3161TimestampToken() { }
public Rfc3161TimestampTokenInfo TokenInfo => throw null;
public SignedCms AsSignedCms() => throw null;
public bool VerifySignatureForHash(ReadOnlySpan<byte> hash, HashAlgorithmName hashAlgorithm, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
public bool VerifySignatureForHash(ReadOnlySpan<byte> hash, Oid hashAlgorithmId, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
public bool VerifySignatureForData(ReadOnlySpan<byte> data, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
public bool VerifySignatureForSignerInfo(SignerInfo signerInfo, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
public static bool TryDecode(ReadOnlyMemory<byte> encodedBytes, out Rfc3161TimestampToken token, out int bytesConsumed) => throw null;
}
public sealed partial class Rfc3161TimestampTokenInfo
{
public Rfc3161TimestampTokenInfo(Oid policyId, Oid hashAlgorithmId, ReadOnlyMemory<byte> messageHash, ReadOnlyMemory<byte> serialNumber, DateTimeOffset timestamp, long? accuracyInMicroseconds=null, bool isOrdering=false, ReadOnlyMemory<byte>? nonce=null, ReadOnlyMemory<byte>? timestampAuthorityName=null, X509ExtensionCollection extensions =null) { throw null; }
public int Version => throw null;
public Oid PolicyId=> throw null;
public Oid HashAlgorithmId => throw null;
public ReadOnlyMemory<byte> GetMessageHash() { throw null; }
public ReadOnlyMemory<byte> GetSerialNumber() { throw null; }
public DateTimeOffset Timestamp => throw null;
public long? AccuracyInMicroseconds => throw null;
public bool IsOrdering => throw null;
public ReadOnlyMemory<byte>? GetNonce() { throw null; }
public ReadOnlyMemory<byte>? GetTimestampAuthorityName() { throw null; }
public bool HasExtensions => throw null;
public X509ExtensionCollection GetExtensions() { throw null; }
public byte[] Encode() => throw null;
public bool TryEncode(Span<byte> destination, out int bytesWritten) => throw null;
public static bool TryDecode(ReadOnlyMemory<byte> encodedBytes, out Rfc3161TimestampTokenInfo timestampTokenInfo, out int bytesConsumed) { throw null; }
}
public sealed partial class SignerInfo
{
public Oid SignatureAlgorithm => throw null;

View File

@@ -6,6 +6,7 @@ using System;
using System.Buffers;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
@@ -56,6 +57,22 @@ namespace Internal.Cryptography
}
}
internal static string GetOidFromHashAlgorithm(HashAlgorithmName algName)
{
if (algName == HashAlgorithmName.MD5)
return Oids.Md5;
if (algName == HashAlgorithmName.SHA1)
return Oids.Sha1;
if (algName == HashAlgorithmName.SHA256)
return Oids.Sha256;
if (algName == HashAlgorithmName.SHA384)
return Oids.Sha384;
if (algName == HashAlgorithmName.SHA512)
return Oids.Sha512;
throw new CryptographicException(SR.Cryptography_Cms_UnknownAlgorithm, algName.Name);
}
/// <summary>
/// This is not just a convenience wrapper for Array.Resize(). In DEBUG builds, it forces the array to move in memory even if no resize is needed. This should be used by
/// helper methods that do anything of the form "call a native api once to get the estimated size, call it again to get the data and return the data in a byte[] array."
@@ -119,6 +136,26 @@ namespace Internal.Cryptography
return set.SetData;
}
internal static byte[] EncodeContentInfo<T>(
T value,
string contentType,
AsnEncodingRules ruleSet = AsnEncodingRules.DER)
{
using (AsnWriter innerWriter = AsnSerializer.Serialize(value, ruleSet))
{
ContentInfoAsn content = new ContentInfoAsn
{
ContentType = contentType,
Content = innerWriter.Encode(),
};
using (AsnWriter outerWriter = AsnSerializer.Serialize(content, ruleSet))
{
return outerWriter.Encode();
}
}
}
public static CmsRecipientCollection DeepCopy(this CmsRecipientCollection recipients)
{
CmsRecipientCollection recipientsCopy = new CmsRecipientCollection();
@@ -151,7 +188,7 @@ namespace Internal.Cryptography
public static X509Certificate2Collection GetStoreCertificates(StoreName storeName, StoreLocation storeLocation, bool openExistingOnly)
{
using (X509Store store = new X509Store())
using (X509Store store = new X509Store(storeName, storeLocation))
{
OpenFlags flags = OpenFlags.ReadOnly | OpenFlags.IncludeArchived;
if (openExistingOnly)
@@ -234,14 +271,14 @@ namespace Internal.Cryptography
return skiString.UpperHexStringToByteArray();
}
public static string ToSkiString(this ReadOnlySpan<byte> skiBytes)
public static string ToSkiString(this byte[] skiBytes)
{
return ToUpperHexString(skiBytes);
}
public static string ToSkiString(this byte[] skiBytes)
public static string ToBigEndianHex(this ReadOnlySpan<byte> bytes)
{
return ToUpperHexString(skiBytes);
return ToUpperHexString(bytes);
}
/// <summary>
@@ -398,6 +435,29 @@ namespace Internal.Cryptography
#endif
}
internal static byte[] OneShot(this ICryptoTransform transform, byte[] data)
{
return OneShot(transform, data, 0, data.Length);
}
internal static byte[] OneShot(this ICryptoTransform transform, byte[] data, int offset, int length)
{
if (transform.CanTransformMultipleBlocks)
{
return transform.TransformFinalBlock(data, offset, length);
}
using (MemoryStream memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, offset, length);
}
return memoryStream.ToArray();
}
}
private static ReadOnlyMemory<byte> GetSubjectPublicKeyInfo(X509Certificate2 certificate)
{
var parsedCertificate = AsnSerializer.Deserialize<Certificate>(certificate.RawData, AsnEncodingRules.DER);

View File

@@ -2,19 +2,22 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text;
using System.Diagnostics;
namespace Internal.Cryptography
{
internal static class Oids
{
// Symmetric encryption algorithms
public const string Rc2Cbc = "1.2.840.113549.3.2";
public const string Rc4 = "1.2.840.113549.3.4";
public const string TripleDesCbc = "1.2.840.113549.3.7";
public const string DesCbc = "1.3.14.3.2.7";
public const string Aes128Cbc = "2.16.840.1.101.3.4.1.2";
public const string Aes192Cbc = "2.16.840.1.101.3.4.1.22";
public const string Aes256Cbc = "2.16.840.1.101.3.4.1.42";
// Asymmetric encryption algorithms
public const string Rsa = "1.2.840.113549.1.1.1";
public const string RsaOaep = "1.2.840.113549.1.1.7";
public const string RsaPss = "1.2.840.113549.1.1.10";
public const string Esdh = "1.2.840.113549.1.9.16.3.5";
@@ -24,6 +27,8 @@ namespace Internal.Cryptography
public const string DocumentDescription = "1.3.6.1.4.1.311.88.2.2";
public const string MessageDigest = "1.2.840.113549.1.9.4";
public const string CounterSigner = "1.2.840.113549.1.9.6";
public const string SigningCertificate = "1.2.840.113549.1.9.16.2.12";
public const string SigningCertificateV2 = "1.2.840.113549.1.9.16.2.47";
public const string DocumentName = "1.3.6.1.4.1.311.88.2.1";
// Key wrap algorithms
@@ -64,5 +69,9 @@ namespace Internal.Cryptography
// Cert Extensions
public const string SubjectKeyIdentifier = "2.5.29.14";
public const string KeyUsage = "2.5.29.15";
// RFC3161 Timestamping
public const string TstInfo = "1.2.840.113549.1.9.16.1.4";
public const string TimeStampingPurpose = "1.3.6.1.5.5.7.3.8";
}
}

View File

@@ -0,0 +1,140 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Pkcs.Asn1;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
namespace Internal.Cryptography.Pal.AnyOS
{
internal static class AsnHelpers
{
internal static SubjectIdentifierOrKey ToSubjectIdentifierOrKey(
this OriginatorIdentifierOrKeyAsn originator)
{
if (originator.IssuerAndSerialNumber != null)
{
var name = new X500DistinguishedName(originator.IssuerAndSerialNumber.Value.Issuer.ToArray());
return new SubjectIdentifierOrKey(
SubjectIdentifierOrKeyType.IssuerAndSerialNumber,
new X509IssuerSerial(
name.Name,
originator.IssuerAndSerialNumber.Value.SerialNumber.Span.ToBigEndianHex()));
}
if (originator.SubjectKeyIdentifier != null)
{
return new SubjectIdentifierOrKey(
SubjectIdentifierOrKeyType.SubjectKeyIdentifier,
originator.SubjectKeyIdentifier.Value.Span.ToBigEndianHex());
}
if (originator.OriginatorKey != null)
{
OriginatorPublicKeyAsn originatorKey = originator.OriginatorKey;
return new SubjectIdentifierOrKey(
SubjectIdentifierOrKeyType.PublicKeyInfo,
new PublicKeyInfo(
originatorKey.Algorithm.ToPresentationObject(),
originatorKey.PublicKey.ToArray()));
}
Debug.Fail("Unknown SubjectIdentifierOrKey state");
return new SubjectIdentifierOrKey(SubjectIdentifierOrKeyType.Unknown, String.Empty);
}
internal static AlgorithmIdentifier ToPresentationObject(this AlgorithmIdentifierAsn asn)
{
int keyLength;
switch (asn.Algorithm.Value)
{
case Oids.Rc2Cbc:
{
if (asn.Parameters == null)
{
keyLength = 0;
break;
}
Rc2CbcParameters rc2Params = AsnSerializer.Deserialize<Rc2CbcParameters>(
asn.Parameters.Value,
AsnEncodingRules.BER);
int keySize = rc2Params.GetEffectiveKeyBits();
// These are the only values .NET Framework would set.
switch (keySize)
{
case 40:
case 56:
case 64:
case 128:
keyLength = keySize;
break;
default:
keyLength = 0;
break;
}
break;
}
case Oids.Rc4:
{
if (asn.Parameters == null)
{
keyLength = 0;
break;
}
int saltLen = 0;
AsnReader reader = new AsnReader(asn.Parameters.Value, AsnEncodingRules.BER);
// DER NULL is considered the same as not present.
// No call to ReadNull() is necessary because the serializer already verified that
// there's no data after the [AnyValue] value.
if (reader.PeekTag() != Asn1Tag.Null)
{
if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> contents))
{
saltLen = contents.Length;
}
else
{
Span<byte> salt = stackalloc byte[KeyLengths.Rc4Max_128Bit / 8];
if (!reader.TryCopyOctetStringBytes(salt, out saltLen))
{
throw new CryptographicException();
}
}
}
keyLength = KeyLengths.Rc4Max_128Bit - 8 * saltLen;
break;
}
case Oids.DesCbc:
keyLength = KeyLengths.Des_64Bit;
break;
case Oids.TripleDesCbc:
keyLength = KeyLengths.TripleDes_192Bit;
break;
default:
// .NET Framework doesn't set a keylength for AES, or any other algorithm than the ones
// listed here.
keyLength = 0;
break;
}
return new AlgorithmIdentifier(new Oid(asn.Algorithm), keyLength);
}
}
}

View File

@@ -0,0 +1,172 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Buffers;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs.Asn1;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
private static readonly byte[] s_invalidEmptyOid = { 0x06, 0x00 };
public override byte[] EncodeOctetString(byte[] octets)
{
// Write using DER to support the most readers.
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
{
writer.WriteOctetString(octets);
return writer.Encode();
}
}
public override byte[] DecodeOctetString(byte[] encodedOctets)
{
// Read using BER because the CMS specification says the encoding is BER.
AsnReader reader = new AsnReader(encodedOctets, AsnEncodingRules.BER);
const int ArbitraryStackLimit = 256;
Span<byte> tmp = stackalloc byte[ArbitraryStackLimit];
// Use stackalloc 0 so data can later hold a slice of tmp.
#if __MonoCS__
ReadOnlySpan<byte> data = new byte[0];
#else
ReadOnlySpan<byte> data = stackalloc byte[0];
#endif
byte[] poolBytes = null;
try
{
if (!reader.TryGetPrimitiveOctetStringBytes(out var contents))
{
if (reader.TryCopyOctetStringBytes(tmp, out int bytesWritten))
{
data = tmp.Slice(0, bytesWritten);
}
else
{
poolBytes = ArrayPool<byte>.Shared.Rent(reader.PeekContentBytes().Length);
if (!reader.TryCopyOctetStringBytes(poolBytes, out bytesWritten))
{
Debug.Fail("TryCopyOctetStringBytes failed with a provably-large-enough buffer");
throw new CryptographicException();
}
data = new ReadOnlySpan<byte>(poolBytes, 0, bytesWritten);
}
}
else
{
data = contents.Span;
}
if (reader.HasData)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
return data.ToArray();
}
finally
{
if (poolBytes != null)
{
Array.Clear(poolBytes, 0, data.Length);
ArrayPool<byte>.Shared.Return(poolBytes);
}
}
}
public override byte[] EncodeUtcTime(DateTime utcTime)
{
const int minLegalYear = 1950;
// Write using DER to support the most readers.
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
{
try
{
// Sending the DateTime through ToLocalTime here will cause the right normalization
// of DateTimeKind.Unknown.
//
// Unknown => Local (adjust) => UTC (adjust "back", add Z marker; matches Windows)
if (utcTime.Kind == DateTimeKind.Unspecified)
{
writer.WriteUtcTime(utcTime.ToLocalTime(), minLegalYear);
}
else
{
writer.WriteUtcTime(utcTime, minLegalYear);
}
return writer.Encode();
}
catch (ArgumentException ex)
{
throw new CryptographicException(ex.Message, ex);
}
}
}
public override DateTime DecodeUtcTime(byte[] encodedUtcTime)
{
// Read using BER because the CMS specification says the encoding is BER.
AsnReader reader = new AsnReader(encodedUtcTime, AsnEncodingRules.BER);
DateTimeOffset value = reader.GetUtcTime();
if (reader.HasData)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
return value.UtcDateTime;
}
public override string DecodeOid(byte[] encodedOid)
{
// Windows compat.
if (s_invalidEmptyOid.AsSpan().SequenceEqual(encodedOid))
{
return string.Empty;
}
// Read using BER because the CMS specification says the encoding is BER.
AsnReader reader = new AsnReader(encodedOid, AsnEncodingRules.BER);
string value = reader.ReadObjectIdentifierAsString();
if (reader.HasData)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
return value;
}
public override Oid GetEncodedMessageType(byte[] encodedMessage)
{
AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
ContentInfoAsn contentInfo = AsnSerializer.Deserialize<ContentInfoAsn>(
reader.GetEncodedValue(),
AsnEncodingRules.BER);
switch (contentInfo.ContentType)
{
case Oids.Pkcs7Data:
case Oids.Pkcs7Signed:
case Oids.Pkcs7Enveloped:
case Oids.Pkcs7SignedEnveloped:
case Oids.Pkcs7Hashed:
case Oids.Pkcs7Encrypted:
return new Oid(contentInfo.ContentType);
}
throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
}
}
}

View File

@@ -0,0 +1,94 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Pkcs.Asn1;
using System.Security.Cryptography.X509Certificates;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
public override DecryptorPal Decode(
byte[] encodedMessage,
out int version,
out ContentInfo contentInfo,
out AlgorithmIdentifier contentEncryptionAlgorithm,
out X509Certificate2Collection originatorCerts,
out CryptographicAttributeObjectCollection unprotectedAttributes)
{
// Read using BER because the CMS specification says the encoding is BER.
AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
ContentInfoAsn parsedContentInfo = AsnSerializer.Deserialize<ContentInfoAsn>(
reader.GetEncodedValue(),
AsnEncodingRules.BER);
if (parsedContentInfo.ContentType != Oids.Pkcs7Enveloped)
{
throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
}
byte[] copy = parsedContentInfo.Content.ToArray();
EnvelopedDataAsn data = AsnSerializer.Deserialize<EnvelopedDataAsn>(
copy,
AsnEncodingRules.BER);
version = data.Version;
contentInfo = new ContentInfo(
new Oid(data.EncryptedContentInfo.ContentType),
data.EncryptedContentInfo.EncryptedContent?.ToArray() ?? Array.Empty<byte>());
contentEncryptionAlgorithm =
data.EncryptedContentInfo.ContentEncryptionAlgorithm.ToPresentationObject();
originatorCerts = new X509Certificate2Collection();
if (data.OriginatorInfo != null && data.OriginatorInfo.CertificateSet != null)
{
foreach (CertificateChoiceAsn certChoice in data.OriginatorInfo.CertificateSet)
{
if (certChoice.Certificate != null)
{
originatorCerts.Add(new X509Certificate2(certChoice.Certificate.Value.ToArray()));
}
}
}
unprotectedAttributes = SignerInfo.MakeAttributeCollection(data.UnprotectedAttributes);
var recipientInfos = new List<RecipientInfo>();
foreach (RecipientInfoAsn recipientInfo in data.RecipientInfos)
{
if (recipientInfo.Ktri != null)
{
recipientInfos.Add(new KeyTransRecipientInfo(new ManagedKeyTransPal(recipientInfo.Ktri)));
}
else if (recipientInfo.Kari != null)
{
for (int i = 0; i < recipientInfo.Kari.RecipientEncryptedKeys.Length; i++)
{
recipientInfos.Add(
new KeyAgreeRecipientInfo(new ManagedKeyAgreePal(recipientInfo.Kari, i)));
}
}
else
{
Debug.Fail($"{nameof(RecipientInfoAsn)} deserialized with an unknown recipient type");
throw new CryptographicException();
}
}
return new ManagedDecryptorPal(copy, data, new RecipientInfoCollection(recipientInfos));
}
}
}

View File

@@ -0,0 +1,186 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Buffers;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Pkcs.Asn1;
using System.Security.Cryptography.X509Certificates;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
private sealed class ManagedDecryptorPal : DecryptorPal
{
private byte[] _dataCopy;
private EnvelopedDataAsn _envelopedData;
public ManagedDecryptorPal(
byte[] dataCopy,
EnvelopedDataAsn envelopedDataAsn,
RecipientInfoCollection recipientInfos)
: base(recipientInfos)
{
_dataCopy = dataCopy;
_envelopedData = envelopedDataAsn;
}
public override unsafe ContentInfo TryDecrypt(
RecipientInfo recipientInfo,
X509Certificate2 cert,
X509Certificate2Collection originatorCerts,
X509Certificate2Collection extraStore,
out Exception exception)
{
// When encryptedContent is null Windows seems to decrypt the CEK first,
// then return a 0 byte answer.
byte[] cek;
if (recipientInfo.Pal is ManagedKeyTransPal ktri)
{
cek = ktri.DecryptCek(cert, out exception);
}
else
{
exception = new CryptographicException(
SR.Cryptography_Cms_RecipientType_NotSupported,
recipientInfo.Type.ToString());
return null;
}
byte[] decrypted;
// Pin CEK to prevent it from getting copied during heap compaction.
fixed (byte* pinnedCek = cek)
{
try
{
if (exception != null)
{
return null;
}
ReadOnlyMemory<byte>? encryptedContent = _envelopedData.EncryptedContentInfo.EncryptedContent;
if (encryptedContent == null)
{
exception = null;
return new ContentInfo(
new Oid(_envelopedData.EncryptedContentInfo.ContentType),
Array.Empty<byte>());
}
decrypted = DecryptContent(encryptedContent.Value, cek, out exception);
}
finally
{
if (cek != null)
{
Array.Clear(cek, 0, cek.Length);
}
}
}
if (exception != null)
{
return null;
}
if (_envelopedData.EncryptedContentInfo.ContentType == Oids.Pkcs7Data)
{
byte[] tmp = null;
try
{
AsnReader reader = new AsnReader(decrypted, AsnEncodingRules.BER);
if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> contents))
{
decrypted = contents.ToArray();
}
else
{
tmp = ArrayPool<byte>.Shared.Rent(decrypted.Length);
if (reader.TryCopyOctetStringBytes(tmp, out int written))
{
Span<byte> innerContents = new Span<byte>(tmp, 0, written);
decrypted = innerContents.ToArray();
innerContents.Clear();
}
else
{
Debug.Fail("Octet string grew during copy");
// If this happens (which requires decrypted was overwritten, which
// shouldn't be possible), just leave decrypted alone.
}
}
}
catch (CryptographicException)
{
}
finally
{
if (tmp != null)
{
// Already cleared
ArrayPool<byte>.Shared.Return(tmp);
}
}
}
exception = null;
return new ContentInfo(
new Oid(_envelopedData.EncryptedContentInfo.ContentType),
decrypted);
}
private byte[] DecryptContent(ReadOnlyMemory<byte> encryptedContent, byte[] cek, out Exception exception)
{
exception = null;
int encryptedContentLength = encryptedContent.Length;
byte[] encryptedContentArray = ArrayPool<byte>.Shared.Rent(encryptedContentLength);
try
{
encryptedContent.CopyTo(encryptedContentArray);
AlgorithmIdentifierAsn contentEncryptionAlgorithm =
_envelopedData.EncryptedContentInfo.ContentEncryptionAlgorithm;
using (SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm))
using (ICryptoTransform decryptor = alg.CreateDecryptor(cek, alg.IV))
{
return decryptor.OneShot(
encryptedContentArray,
0,
encryptedContentLength);
}
}
catch (CryptographicException e)
{
exception = e;
return null;
}
finally
{
Array.Clear(encryptedContentArray, 0, encryptedContentLength);
ArrayPool<byte>.Shared.Return(encryptedContentArray);
encryptedContentArray = null;
}
}
public override void Dispose()
{
}
}
}
}

View File

@@ -0,0 +1,186 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Pkcs.Asn1;
using System.Security.Cryptography.X509Certificates;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
public override unsafe byte[] Encrypt(
CmsRecipientCollection recipients,
ContentInfo contentInfo,
AlgorithmIdentifier contentEncryptionAlgorithm,
X509Certificate2Collection originatorCerts,
CryptographicAttributeObjectCollection unprotectedAttributes)
{
byte[] encryptedContent = EncryptContent(
contentInfo,
contentEncryptionAlgorithm,
out byte[] cek,
out byte[] parameterBytes);
// Pin the CEK to prevent it from getting copied during heap compaction.
fixed (byte* pinnedCek = cek)
{
try
{
return Encrypt(
recipients,
contentInfo,
contentEncryptionAlgorithm,
originatorCerts,
unprotectedAttributes,
encryptedContent,
cek,
parameterBytes);
}
finally
{
Array.Clear(cek, 0, cek.Length);
}
}
}
private static byte[] Encrypt(
CmsRecipientCollection recipients,
ContentInfo contentInfo,
AlgorithmIdentifier contentEncryptionAlgorithm,
X509Certificate2Collection originatorCerts,
CryptographicAttributeObjectCollection unprotectedAttributes,
byte[] encryptedContent,
byte[] cek,
byte[] parameterBytes)
{
EnvelopedDataAsn envelopedData = new EnvelopedDataAsn
{
EncryptedContentInfo =
{
ContentType = contentInfo.ContentType.Value,
ContentEncryptionAlgorithm =
{
Algorithm = contentEncryptionAlgorithm.Oid,
Parameters = parameterBytes,
},
EncryptedContent = encryptedContent,
},
};
if (unprotectedAttributes != null && unprotectedAttributes.Count > 0)
{
List<AttributeAsn> attrList = CmsSigner.BuildAttributes(unprotectedAttributes);
envelopedData.UnprotectedAttributes = Helpers.NormalizeSet(attrList.ToArray());
}
if (originatorCerts != null && originatorCerts.Count > 0)
{
CertificateChoiceAsn[] certs = new CertificateChoiceAsn[originatorCerts.Count];
for (int i = 0; i < originatorCerts.Count; i++)
{
certs[i].Certificate = originatorCerts[i].RawData;
}
envelopedData.OriginatorInfo = new OriginatorInfoAsn
{
CertificateSet = certs,
};
}
envelopedData.RecipientInfos = new RecipientInfoAsn[recipients.Count];
bool allRecipientsVersion0 = true;
for (var i = 0; i < recipients.Count; i++)
{
CmsRecipient recipient = recipients[i];
bool v0Recipient;
switch (recipient.Certificate.GetKeyAlgorithm())
{
case Oids.Rsa:
envelopedData.RecipientInfos[i].Ktri = MakeKtri(cek, recipient, out v0Recipient);
break;
default:
throw new CryptographicException(
SR.Cryptography_Cms_UnknownAlgorithm,
recipient.Certificate.GetKeyAlgorithm());
}
allRecipientsVersion0 = allRecipientsVersion0 && v0Recipient;
}
// https://tools.ietf.org/html/rfc5652#section-6.1
//
// v4 (RFC 3852):
// * OriginatorInfo contains certificates with type other (not supported)
// * OriginatorInfo contains crls with type other (not supported)
// v3 (RFC 3369):
// * OriginatorInfo contains v2 attribute certificates (not supported)
// * Any PWRI (password) recipients are present (not supported)
// * Any ORI (other) recipients are present (not supported)
// v2 (RFC 2630):
// * OriginatorInfo is present
// * Any RecipientInfo has a non-zero version number
// * UnprotectedAttrs is present
// v1 (not defined for EnvelopedData)
// v0 (RFC 2315):
// * Anything not already matched
if (envelopedData.OriginatorInfo != null ||
!allRecipientsVersion0 ||
envelopedData.UnprotectedAttributes != null)
{
envelopedData.Version = 2;
}
return Helpers.EncodeContentInfo(envelopedData, Oids.Pkcs7Enveloped);
}
private byte[] EncryptContent(
ContentInfo contentInfo,
AlgorithmIdentifier contentEncryptionAlgorithm,
out byte[] cek,
out byte[] parameterBytes)
{
using (SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm))
using (ICryptoTransform encryptor = alg.CreateEncryptor())
{
cek = alg.Key;
if (alg is RC2)
{
Rc2CbcParameters rc2Params = new Rc2CbcParameters(alg.IV, alg.KeySize);
using (AsnWriter writer = AsnSerializer.Serialize(rc2Params, AsnEncodingRules.DER))
{
parameterBytes = writer.Encode();
}
}
else
{
parameterBytes = EncodeOctetString(alg.IV);
}
byte[] toEncrypt = contentInfo.Content;
if (contentInfo.ContentType.Value == Oids.Pkcs7Data)
{
toEncrypt = EncodeOctetString(toEncrypt);
}
return encryptor.OneShot(toEncrypt);
}
}
}
}

View File

@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Security.Cryptography;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
public override Exception CreateRecipientsNotFoundException()
{
return new CryptographicException(SR.Cryptography_Cms_RecipientNotFound);
}
public override Exception CreateRecipientInfosAfterEncryptException()
{
return CreateInvalidMessageTypeException();
}
public override Exception CreateDecryptAfterEncryptException()
{
return CreateInvalidMessageTypeException();
}
public override Exception CreateDecryptTwiceException()
{
return CreateInvalidMessageTypeException();
}
private static Exception CreateInvalidMessageTypeException()
{
// Windows CRYPT_E_INVALID_MSG_TYPE
return new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
}
}
}

View File

@@ -0,0 +1,94 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Pkcs.Asn1;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
private sealed class ManagedKeyAgreePal : KeyAgreeRecipientInfoPal
{
private readonly KeyAgreeRecipientInfoAsn _asn;
private readonly int _index;
internal ManagedKeyAgreePal(KeyAgreeRecipientInfoAsn asn, int index)
{
_asn = asn;
_index = index;
}
public override byte[] EncryptedKey =>
_asn.RecipientEncryptedKeys[_index].EncryptedKey.ToArray();
public override AlgorithmIdentifier KeyEncryptionAlgorithm =>
_asn.KeyEncryptionAlgorithm.ToPresentationObject();
public override SubjectIdentifier RecipientIdentifier =>
new SubjectIdentifier(
_asn.RecipientEncryptedKeys[_index].Rid.IssuerAndSerialNumber,
_asn.RecipientEncryptedKeys[_index].Rid.RKeyId?.SubjectKeyIdentifier);
public override int Version => _asn.Version;
public override DateTime Date
{
get
{
KeyAgreeRecipientIdentifierAsn rid = _asn.RecipientEncryptedKeys[_index].Rid;
if (rid.RKeyId == null)
{
throw new InvalidOperationException(SR.Cryptography_Cms_Key_Agree_Date_Not_Available);
}
if (rid.RKeyId.Date == null)
{
// Compatibility with Windows/NetFX.
return DateTime.FromFileTimeUtc(0);
}
return rid.RKeyId.Date.Value.LocalDateTime;
}
}
public override SubjectIdentifierOrKey OriginatorIdentifierOrKey =>
_asn.Originator.ToSubjectIdentifierOrKey();
public override CryptographicAttributeObject OtherKeyAttribute
{
get
{
KeyAgreeRecipientIdentifierAsn rid = _asn.RecipientEncryptedKeys[_index].Rid;
if (rid.RKeyId == null)
{
// Yes, "date" (Windows compat)
throw new InvalidOperationException(SR.Cryptography_Cms_Key_Agree_Date_Not_Available);
}
if (rid.RKeyId.Other == null)
{
return null;
}
Oid oid = new Oid(rid.RKeyId.Other.Value.KeyAttrId);
byte[] rawData = Array.Empty<byte>();
if (rid.RKeyId.Other.Value.KeyAttr != null)
{
rawData = rid.RKeyId.Other.Value.KeyAttr.Value.ToArray();
}
Pkcs9AttributeObject pkcs9AttributeObject = new Pkcs9AttributeObject(oid, rawData);
AsnEncodedDataCollection values = new AsnEncodedDataCollection(pkcs9AttributeObject);
return new CryptographicAttributeObject(oid, values);
}
}
}
}
}

View File

@@ -0,0 +1,179 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Buffers;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Pkcs.Asn1;
using System.Security.Cryptography.X509Certificates;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
private static readonly byte[] s_rsaPkcsParameters = { 0x05, 0x00 };
private static readonly byte[] s_rsaOaepSha1Parameters = { 0x30, 0x00 };
private sealed class ManagedKeyTransPal : KeyTransRecipientInfoPal
{
private readonly KeyTransRecipientInfoAsn _asn;
internal ManagedKeyTransPal(KeyTransRecipientInfoAsn asn)
{
_asn = asn;
}
public override byte[] EncryptedKey =>
_asn.EncryptedKey.ToArray();
public override AlgorithmIdentifier KeyEncryptionAlgorithm =>
_asn.KeyEncryptionAlgorithm.ToPresentationObject();
public override SubjectIdentifier RecipientIdentifier =>
new SubjectIdentifier(_asn.Rid.IssuerAndSerialNumber, _asn.Rid.SubjectKeyIdentifier);
public override int Version => _asn.Version;
internal byte[] DecryptCek(X509Certificate2 cert, out Exception exception)
{
RSAEncryptionPadding encryptionPadding;
ReadOnlyMemory<byte>? parameters = _asn.KeyEncryptionAlgorithm.Parameters;
switch (_asn.KeyEncryptionAlgorithm.Algorithm.Value)
{
case Oids.Rsa:
if (parameters != null &&
!parameters.Value.Span.SequenceEqual(s_rsaPkcsParameters))
{
exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
return null;
}
encryptionPadding = RSAEncryptionPadding.Pkcs1;
break;
case Oids.RsaOaep:
if (parameters != null &&
!parameters.Value.Span.SequenceEqual(s_rsaOaepSha1Parameters))
{
exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
return null;
}
encryptionPadding = RSAEncryptionPadding.OaepSHA1;
break;
default:
exception = new CryptographicException(
SR.Cryptography_Cms_UnknownAlgorithm,
_asn.KeyEncryptionAlgorithm.Algorithm.Value);
return null;
}
byte[] cek = null;
int cekLength = 0;
try
{
using (RSA rsa = cert.GetRSAPrivateKey())
{
if (rsa == null)
{
exception = new CryptographicException(SR.Cryptography_Cms_Signing_RequiresPrivateKey);
return null;
}
#if netcoreapp
cek = ArrayPool<byte>.Shared.Rent(rsa.KeySize / 8);
if (!rsa.TryDecrypt(_asn.EncryptedKey.Span, cek, encryptionPadding, out cekLength))
{
Debug.Fail("TryDecrypt wanted more space than the key size");
exception = new CryptographicException();
return null;
}
exception = null;
return new Span<byte>(cek, 0, cekLength).ToArray();
#else
exception = null;
return rsa.Decrypt(_asn.EncryptedKey.Span.ToArray(), encryptionPadding);
#endif
}
}
catch (CryptographicException e)
{
exception = e;
return null;
}
finally
{
if (cek != null)
{
Array.Clear(cek, 0, cekLength);
ArrayPool<byte>.Shared.Return(cek);
}
}
}
}
private static KeyTransRecipientInfoAsn MakeKtri(
byte[] cek,
CmsRecipient recipient,
out bool v0Recipient)
{
KeyTransRecipientInfoAsn ktri = new KeyTransRecipientInfoAsn();
if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier)
{
ktri.Version = 2;
ktri.Rid.SubjectKeyIdentifier = recipient.Certificate.GetSubjectKeyIdentifier();
}
else if (recipient.RecipientIdentifierType == SubjectIdentifierType.IssuerAndSerialNumber)
{
byte[] serial = recipient.Certificate.GetSerialNumber();
Array.Reverse(serial);
IssuerAndSerialNumberAsn iasn = new IssuerAndSerialNumberAsn
{
Issuer = recipient.Certificate.IssuerName.RawData,
SerialNumber = serial,
};
ktri.Rid.IssuerAndSerialNumber = iasn;
}
else
{
throw new CryptographicException(
SR.Cryptography_Cms_Invalid_Subject_Identifier_Type,
recipient.RecipientIdentifierType.ToString());
}
RSAEncryptionPadding padding;
switch (recipient.Certificate.GetKeyAlgorithm())
{
case Oids.RsaOaep:
padding = RSAEncryptionPadding.OaepSHA1;
ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.RsaOaep, Oids.RsaOaep);
ktri.KeyEncryptionAlgorithm.Parameters = s_rsaOaepSha1Parameters;
break;
default:
padding = RSAEncryptionPadding.Pkcs1;
ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.Rsa, Oids.Rsa);
ktri.KeyEncryptionAlgorithm.Parameters = s_rsaPkcsParameters;
break;
}
using (RSA rsa = recipient.Certificate.GetRSAPublicKey())
{
ktri.EncryptedKey = rsa.Encrypt(cek, padding);
}
v0Recipient = (ktri.Version == 0);
return ktri;
}
}
}

View File

@@ -0,0 +1,176 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Pkcs.Asn1;
using System.Security.Cryptography.X509Certificates;
namespace Internal.Cryptography.Pal.AnyOS
{
internal sealed partial class ManagedPkcsPal : PkcsPal
{
public override void AddCertsFromStoreForDecryption(X509Certificate2Collection certs)
{
certs.AddRange(Helpers.GetStoreCertificates(StoreName.My, StoreLocation.CurrentUser, openExistingOnly: false));
try
{
// This store exists on macOS, but not Linux
certs.AddRange(
Helpers.GetStoreCertificates(StoreName.My, StoreLocation.LocalMachine, openExistingOnly: false));
}
catch (CryptographicException)
{
}
}
public override byte[] GetSubjectKeyIdentifier(X509Certificate2 certificate)
{
return certificate.GetSubjectKeyIdentifier();
}
public override T GetPrivateKeyForSigning<T>(X509Certificate2 certificate, bool silent)
{
return GetPrivateKey<T>(certificate);
}
public override T GetPrivateKeyForDecryption<T>(X509Certificate2 certificate, bool silent)
{
return GetPrivateKey<T>(certificate);
}
private T GetPrivateKey<T>(X509Certificate2 certificate) where T : AsymmetricAlgorithm
{
if (typeof(T) == typeof(RSA))
return (T)(object)certificate.GetRSAPrivateKey();
if (typeof(T) == typeof(ECDsa))
return (T)(object)certificate.GetECDsaPrivateKey();
#if netcoreapp
if (typeof(T) == typeof(DSA))
return (T)(object)certificate.GetDSAPrivateKey();
#endif
Debug.Fail($"Unknown key type requested: {typeof(T).FullName}");
return null;
}
private static SymmetricAlgorithm OpenAlgorithm(AlgorithmIdentifierAsn contentEncryptionAlgorithm)
{
SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm.Algorithm);
if (alg is RC2)
{
if (contentEncryptionAlgorithm.Parameters == null)
{
// Windows issues CRYPT_E_BAD_DECODE
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
Rc2CbcParameters rc2Params = AsnSerializer.Deserialize<Rc2CbcParameters>(
contentEncryptionAlgorithm.Parameters.Value,
AsnEncodingRules.BER);
alg.KeySize = rc2Params.GetEffectiveKeyBits();
alg.IV = rc2Params.Iv.ToArray();
}
else
{
if (contentEncryptionAlgorithm.Parameters == null)
{
// Windows issues CRYPT_E_BAD_DECODE
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
AsnReader reader = new AsnReader(contentEncryptionAlgorithm.Parameters.Value, AsnEncodingRules.BER);
if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> primitiveBytes))
{
alg.IV = primitiveBytes.ToArray();
}
else
{
byte[] iv = new byte[alg.BlockSize / 8];
if (!reader.TryCopyOctetStringBytes(iv, out int bytesWritten) ||
bytesWritten != iv.Length)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
alg.IV = iv;
}
}
return alg;
}
private static SymmetricAlgorithm OpenAlgorithm(AlgorithmIdentifier algorithmIdentifier)
{
SymmetricAlgorithm alg = OpenAlgorithm(algorithmIdentifier.Oid);
if (alg is RC2)
{
if (algorithmIdentifier.KeyLength != 0)
{
alg.KeySize = algorithmIdentifier.KeyLength;
}
else
{
alg.KeySize = KeyLengths.Rc2_128Bit;
}
}
return alg;
}
private static SymmetricAlgorithm OpenAlgorithm(Oid algorithmIdentifier)
{
Debug.Assert(algorithmIdentifier != null);
SymmetricAlgorithm alg;
switch (algorithmIdentifier.Value)
{
case Oids.Rc2Cbc:
#pragma warning disable CA5351
alg = RC2.Create();
#pragma warning restore CA5351
break;
case Oids.DesCbc:
#pragma warning disable CA5351
alg = DES.Create();
#pragma warning restore CA5351
break;
case Oids.TripleDesCbc:
#pragma warning disable CA5350
alg = TripleDES.Create();
#pragma warning restore CA5350
break;
case Oids.Aes128Cbc:
alg = Aes.Create();
alg.KeySize = 128;
break;
case Oids.Aes192Cbc:
alg = Aes.Create();
alg.KeySize = 192;
break;
case Oids.Aes256Cbc:
alg = Aes.Create();
alg.KeySize = 256;
break;
default:
throw new CryptographicException(SR.Cryptography_Cms_UnknownAlgorithm, algorithmIdentifier.Value);
}
// These are the defaults, but they're restated here for clarity.
alg.Padding = PaddingMode.PKCS7;
alg.Mode = CipherMode.CBC;
return alg;
}
}
}

View File

@@ -2,220 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Buffers;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using Internal.Cryptography.Pal.AnyOS;
namespace Internal.Cryptography
{
internal abstract partial class PkcsPal
{
private static PkcsPal s_instance = new ManagedPkcsPal();
private class ManagedPkcsPal : PkcsPal
{
public override byte[] Encrypt(
CmsRecipientCollection recipients,
ContentInfo contentInfo,
AlgorithmIdentifier contentEncryptionAlgorithm,
X509Certificate2Collection originatorCerts,
CryptographicAttributeObjectCollection unprotectedAttributes)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override DecryptorPal Decode(
byte[] encodedMessage,
out int version,
out ContentInfo contentInfo,
out AlgorithmIdentifier contentEncryptionAlgorithm,
out X509Certificate2Collection originatorCerts,
out CryptographicAttributeObjectCollection unprotectedAttributes)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override byte[] EncodeOctetString(byte[] octets)
{
// Write using DER to support the most readers.
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
{
writer.WriteOctetString(octets);
return writer.Encode();
}
}
public override byte[] DecodeOctetString(byte[] encodedOctets)
{
// Read using BER because the CMS specification says the encoding is BER.
AsnReader reader = new AsnReader(encodedOctets, AsnEncodingRules.BER);
const int ArbitraryStackLimit = 256;
Span<byte> tmp = stackalloc byte[ArbitraryStackLimit];
// Use stackalloc 0 so data can later hold a slice of tmp.
ReadOnlySpan<byte> data = stackalloc byte[0];
byte[] poolBytes = null;
try
{
if (!reader.TryGetPrimitiveOctetStringBytes(out var contents))
{
if (reader.TryCopyOctetStringBytes(tmp, out int bytesWritten))
{
data = tmp.Slice(0, bytesWritten);
}
else
{
poolBytes = ArrayPool<byte>.Shared.Rent(reader.PeekContentBytes().Length);
if (!reader.TryCopyOctetStringBytes(poolBytes, out bytesWritten))
{
Debug.Fail("TryCopyOctetStringBytes failed with a provably-large-enough buffer");
throw new CryptographicException();
}
data = new ReadOnlySpan<byte>(poolBytes, 0, bytesWritten);
}
}
else
{
data = contents.Span;
}
if (reader.HasData)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
return data.ToArray();
}
finally
{
if (poolBytes != null)
{
Array.Clear(poolBytes, 0, data.Length);
ArrayPool<byte>.Shared.Return(poolBytes);
}
}
}
public override byte[] EncodeUtcTime(DateTime utcTime)
{
// Write using DER to support the most readers.
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
{
// Sending the DateTime through ToLocalTime here will cause the right normalization
// of DateTimeKind.Unknown.
//
// Local => Local (noop) => UTC (in WriteUtcTime) (adjust, correct)
// UTC => Local (adjust) => UTC (adjust back, correct)
// Unknown => Local (adjust) => UTC (adjust "back", add Z marker; matches Windows)
writer.WriteUtcTime(utcTime.ToLocalTime());
return writer.Encode();
}
}
public override DateTime DecodeUtcTime(byte[] encodedUtcTime)
{
// Read using BER because the CMS specification says the encoding is BER.
AsnReader reader = new AsnReader(encodedUtcTime, AsnEncodingRules.BER);
DateTimeOffset value = reader.GetUtcTime();
if (reader.HasData)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
return value.UtcDateTime;
}
public override string DecodeOid(byte[] encodedOid)
{
Span<byte> emptyInvalidOid = stackalloc byte[2];
emptyInvalidOid[0] = 0x06;
emptyInvalidOid[1] = 0x00;
// Windows compat.
if (emptyInvalidOid.SequenceEqual(encodedOid))
{
return string.Empty;
}
// Read using BER because the CMS specification says the encoding is BER.
AsnReader reader = new AsnReader(encodedOid, AsnEncodingRules.BER);
string value = reader.ReadObjectIdentifierAsString();
if (reader.HasData)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
return value;
}
public override Oid GetEncodedMessageType(byte[] encodedMessage)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override void AddCertsFromStoreForDecryption(X509Certificate2Collection certs)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override Exception CreateRecipientsNotFoundException()
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override Exception CreateRecipientInfosAfterEncryptException()
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override Exception CreateDecryptAfterEncryptException()
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override Exception CreateDecryptTwiceException()
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
}
public override byte[] GetSubjectKeyIdentifier(X509Certificate2 certificate)
{
return certificate.GetSubjectKeyIdentifier();
}
public override T GetPrivateKeyForSigning<T>(X509Certificate2 certificate, bool silent)
{
return GetPrivateKey<T>(certificate);
}
public override T GetPrivateKeyForDecryption<T>(X509Certificate2 certificate, bool silent)
{
return GetPrivateKey<T>(certificate);
}
private T GetPrivateKey<T>(X509Certificate2 certificate) where T : AsymmetricAlgorithm
{
if (typeof(T) == typeof(RSA))
return (T)(object)certificate.GetRSAPrivateKey();
if (typeof(T) == typeof(ECDsa))
return (T)(object)certificate.GetECDsaPrivateKey();
#if netcoreapp
if (typeof(T) == typeof(DSA))
return (T)(object)certificate.GetDSAPrivateKey();
#endif
Debug.Fail($"Unknown key type requested: {typeof(T).FullName}");
return null;
}
}
private static readonly PkcsPal s_instance = new ManagedPkcsPal();
}
}

View File

@@ -359,7 +359,7 @@ namespace Internal.Cryptography.Pal.Windows
throw new CryptographicException();
}
int provType = BinaryPrimitives.ReadMachineEndian<int>(stackSpan.Slice(0, size));
int provType = MemoryMarshal.Read<int>(stackSpan.Slice(0, size));
size = stackSpan.Length;
if (!Interop.Advapi32.CryptGetProvParam(handle, CryptProvParam.PP_KEYSET_TYPE, stackSpan, ref size))
@@ -373,7 +373,7 @@ namespace Internal.Cryptography.Pal.Windows
throw new CryptographicException();
}
int keysetType = BinaryPrimitives.ReadMachineEndian<int>(stackSpan.Slice(0, size));
int keysetType = MemoryMarshal.Read<int>(stackSpan.Slice(0, size));
// Only CRYPT_MACHINE_KEYSET is described as coming back, but be defensive.
CspProviderFlags provFlags =

View File

@@ -0,0 +1,3 @@
# These members don't belong in netstandard reference because of type unification with netfx (the members are new in net472).
MembersMustExist : Member 'System.Security.Cryptography.Pkcs.SignerInfo.GetSignature()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'System.Security.Cryptography.Pkcs.SignerInfo.SignatureAlgorithm.get()' does not exist in the implementation but it does exist in the contract.

View File

@@ -199,6 +199,12 @@
<data name="Cryptography_Cms_NoSignerAtIndex" xml:space="preserve">
<value>The signed cryptographic message does not have a signer for the specified signer index.</value>
</data>
<data name="Cryptography_Cms_RecipientNotFound" xml:space="preserve">
<value>The enveloped-data message does not contain the specified recipient.</value>
</data>
<data name="Cryptography_Cms_RecipientType_NotSupported" xml:space="preserve">
<value>The recipient type '{0}' is not supported for encryption or decryption on this platform.</value>
</data>
<data name="Cryptography_Cms_Sign_Empty_Content" xml:space="preserve">
<value>Cannot create CMS signature for empty content.</value>
</data>
@@ -244,6 +250,21 @@
<data name="Cryptography_Pkcs_PssParametersSaltMismatch" xml:space="preserve">
<value>PSS salt size {0} is not supported by this platform with hash algorithm {1}.</value>
</data>
<data name="Cryptography_TimestampReq_BadNonce" xml:space="preserve">
<value>The response from the timestamping server did not match the request nonce.</value>
</data>
<data name="Cryptography_TimestampReq_BadResponse" xml:space="preserve">
<value>The response from the timestamping server was not understood.</value>
</data>
<data name="Cryptography_TimestampReq_Failure" xml:space="preserve">
<value>The timestamping server did not grant the request. The request status is '{0}' with failure info '{1}'.</value>
</data>
<data name="Cryptography_TimestampReq_NoCertFound" xml:space="preserve">
<value>The timestamping request required the TSA certificate in the response, but it was not found.</value>
</data>
<data name="Cryptography_TimestampReq_UnexpectedCertFound" xml:space="preserve">
<value>The timestamping request required the TSA certificate not be included in the response, but certificates were present.</value>
</data>
<data name="InvalidOperation_DuplicateItemNotAllowed" xml:space="preserve">
<value>Duplicate items are not allowed in the collection.</value>
</data>

View File

@@ -175,7 +175,30 @@
</ItemGroup>
<!-- Internal types (platform: AnyOS) -->
<ItemGroup Condition="'$(TargetsWindows)' != 'true' AND '$(IsPartialFacadeAssembly)' != 'true'">
<Compile Include="Internal\Cryptography\Pal\AnyOS\AsnHelpers.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Asn.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Decode.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Decrypt.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Encrypt.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Exceptions.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.KeyAgree.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.KeyTrans.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\PkcsPal.AnyOS.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\EncryptedContentInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\EnvelopedDataAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\KeyAgreeRecipientIdentifierAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\KeyAgreeRecipientInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\KeyTransRecipientInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\OriginatorIdentifierOrKeyAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\OriginatorInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\OriginatorPublicKeyAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\OtherKeyAttributeAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rc2CbcParameters.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientEncryptedKeyAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientIdentifierAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientKeyIdentifier.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<Reference Include="mscorlib" />
@@ -225,11 +248,19 @@
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\CertificateChoiceAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\ContentInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\EncapsulatedContentInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\GeneralName.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\IssuerAndSerialNumberAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\MessageImprint.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\PssParamsAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161Accuracy.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161TimeStampReq.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161TimeStampResp.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161TstInfo.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\SignedDataAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\SignerIdentifierAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\SignerInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\SigningCertificateAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\X509ExtensionAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.ECDsa.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.RSA.cs" />
@@ -242,6 +273,10 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.DSA.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Rfc3161RequestResponseStatus.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Rfc3161TimestampRequest.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Rfc3161TimestampToken.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Rfc3161TimestampTokenInfo.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

Some files were not shown because too many files have changed in this diff Show More