Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/libraries/Common/src/System/Security/Cryptography/Oids.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,23 @@ internal static partial class Oids
internal const string MsPkcs12MachineKeySet = "1.3.6.1.4.1.311.17.2";

// Key wrap algorithms
internal const string Aes128Wrap = "2.16.840.1.101.3.4.1.5";
internal const string Aes192Wrap = "2.16.840.1.101.3.4.1.25";
internal const string Aes256Wrap = "2.16.840.1.101.3.4.1.45";
internal const string CmsRc2Wrap = "1.2.840.113549.1.9.16.3.7";
internal const string Cms3DesWrap = "1.2.840.113549.1.9.16.3.6";

// Key derivation algorithms
internal const string HkdfWithSha256 = "1.2.840.113549.1.9.16.3.28";
internal const string HkdfWithSha384 = "1.2.840.113549.1.9.16.3.29";
internal const string HkdfWithSha512 = "1.2.840.113549.1.9.16.3.30";
internal const string HkdfWithSha3_256 = "1.2.840.113549.1.9.16.3.33";
internal const string HkdfWithSha3_384 = "1.2.840.113549.1.9.16.3.34";
internal const string HkdfWithSha3_512 = "1.2.840.113549.1.9.16.3.35";

// OtherRecipientInfo types
internal const string IdSmimeOriKem = "1.2.840.113549.1.9.16.13.3";

// PKCS7 Content Types.
internal const string Pkcs7Data = "1.2.840.113549.1.7.1";
internal const string Pkcs7Signed = "1.2.840.113549.1.7.2";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ namespace System.Runtime.CompilerServices
/// </para>
/// </remarks>
/// <seealso cref="UnionAttribute" />
public interface IUnion
#if SYSTEM_PRIVATE_CORELIB
public
#else
internal
#endif
interface IUnion
{
/// <summary>
/// Gets the value contained in the union, or <see langword="null" /> if the union has no value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ namespace System.Runtime.CompilerServices
/// </remarks>
/// <seealso cref="IUnion" />
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
public sealed class UnionAttribute : Attribute
#if SYSTEM_PRIVATE_CORELIB
public
#else
internal
#endif
sealed class UnionAttribute : Attribute
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ public CmsRecipient(System.Security.Cryptography.Pkcs.SubjectIdentifierType reci
public CmsRecipient(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { }
public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate { get { throw null; } }
public System.Security.Cryptography.Pkcs.SubjectIdentifierType RecipientIdentifierType { get { throw null; } }
#if NET11_0_OR_GREATER
public static System.Security.Cryptography.Pkcs.CmsRecipient CreateForKeyEncapsulation(System.Security.Cryptography.Pkcs.SubjectIdentifierType recipientIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.ReadOnlySpan<byte> userKeyingMaterial) { throw null; }
public static System.Security.Cryptography.Pkcs.CmsRecipient CreateForKeyEncapsulation(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.ReadOnlySpan<byte> userKeyingMaterial) { throw null; }
#endif
}
public sealed partial class CmsRecipientCollection : System.Collections.ICollection, System.Collections.IEnumerable
{
Expand Down Expand Up @@ -120,6 +124,11 @@ public EnvelopedCms(System.Security.Cryptography.Pkcs.ContentInfo contentInfo, S
public int Version { get { throw null; } }
public void Decode(byte[] encodedMessage) { }
public void Decrypt() { }
#if NET11_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public void Decrypt(System.Security.Cryptography.Pkcs.KemRecipientInfo recipientInfo, System.Security.Cryptography.CompositeMLKem privateKey) { }
public void Decrypt(System.Security.Cryptography.Pkcs.KemRecipientInfo recipientInfo, System.Security.Cryptography.MLKem privateKey) { }
#endif
public void Decrypt(System.Security.Cryptography.Pkcs.RecipientInfo recipientInfo) { }
public void Decrypt(System.Security.Cryptography.Pkcs.RecipientInfo recipientInfo, System.Security.Cryptography.X509Certificates.X509Certificate2Collection extraStore) { }
public void Decrypt(System.Security.Cryptography.X509Certificates.X509Certificate2Collection extraStore) { }
Expand All @@ -138,6 +147,21 @@ internal KeyAgreeRecipientInfo() { }
public override System.Security.Cryptography.Pkcs.SubjectIdentifier RecipientIdentifier { get { throw null; } }
public override int Version { get { throw null; } }
}
#if NET11_0_OR_GREATER
public sealed partial class KemRecipientInfo : System.Security.Cryptography.Pkcs.RecipientInfo
{
internal KemRecipientInfo() { }
public override byte[] EncryptedKey { get { throw null; } }
public System.Security.Cryptography.Pkcs.AlgorithmIdentifier KeyEncapsulationAlgorithm { get { throw null; } }
public System.ReadOnlyMemory<byte> KeyEncapsulationCiphertext { get { throw null; } }
public System.Security.Cryptography.Pkcs.AlgorithmIdentifier KeyDerivationAlgorithm { get { throw null; } }
public override System.Security.Cryptography.Pkcs.AlgorithmIdentifier KeyEncryptionAlgorithm { get { throw null; } }
public int KeyEncryptionKeyLengthInBytes { get { throw null; } }
public override System.Security.Cryptography.Pkcs.SubjectIdentifier RecipientIdentifier { get { throw null; } }
public System.ReadOnlyMemory<byte>? UserKeyingMaterial { get { throw null; } }
public override int Version { get { throw null; } }
}
#endif
public sealed partial class KeyTransRecipientInfo : System.Security.Cryptography.Pkcs.RecipientInfo
{
internal KeyTransRecipientInfo() { }
Expand Down Expand Up @@ -231,6 +255,9 @@ public enum RecipientInfoType
Unknown = 0,
KeyTransport = 1,
KeyAgreement = 2,
#if NET11_0_OR_GREATER
KeyEncapsulation = 3,
#endif
}
public sealed partial class SignedCms
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal DecryptorPal(RecipientInfoCollection recipientInfos)
public abstract ContentInfo? TryDecrypt(
RecipientInfo recipientInfo,
X509Certificate2? cert,
AsymmetricAlgorithm? privateKey,
EnvelopedCmsKey privateKey,
X509Certificate2Collection originatorCerts,
X509Certificate2Collection extraStore,
out Exception? exception);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Security.Cryptography;

namespace Internal.Cryptography
{
internal union EnvelopedCmsKey(
RSA,
#if NET11_0_OR_GREATER
MLKem,
CompositeMLKem,
#endif
EnvelopedCmsKey.None)
{
internal sealed record None
{
internal static None Instance { get; } = new None();

private None()
{
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Security.Cryptography.Pkcs;

namespace Internal.Cryptography
{
internal abstract class KemRecipientInfoPal : RecipientInfoPal
{
internal abstract AlgorithmIdentifier KeyDerivationAlgorithm { get; }
internal abstract AlgorithmIdentifier KeyEncapsulationAlgorithm { get; }
internal abstract ReadOnlyMemory<byte> KeyEncapsulationCiphertext { get; }
internal abstract int KeyEncryptionKeyLengthInBytes { get; }
internal abstract ReadOnlyMemory<byte>? UserKeyingMaterial { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ public override DecryptorPal Decode(
new KeyAgreeRecipientInfo(new ManagedKeyAgreePal(recipientInfo.Kari.Value, i)));
}
}
else if (recipientInfo.Ori.HasValue)
{
#if NET11_0_OR_GREATER
if (recipientInfo.Ori.Value.OriType == Oids.IdSmimeOriKem)
{
KemRecipientInfoAsn kemRecipientInfo = KemRecipientInfoAsn.Decode(
recipientInfo.Ori.Value.OriValue,
AsnEncodingRules.BER);

recipientInfos.Add(new KemRecipientInfo(new ManagedKemRecipientInfoPal(kemRecipientInfo)));
continue;
}
#endif

throw new CryptographicException();
}
else
{
Debug.Fail($"{nameof(RecipientInfoAsn)} deserialized with an unknown recipient type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,53 +32,56 @@ public ManagedDecryptorPal(
public override unsafe ContentInfo? TryDecrypt(
RecipientInfo recipientInfo,
X509Certificate2? cert,
AsymmetricAlgorithm? privateKey,
EnvelopedCmsKey privateKey,
X509Certificate2Collection originatorCerts,
X509Certificate2Collection extraStore,
out Exception? exception)
{
// When encryptedContent is null Windows seems to decrypt the CEK first,
// then return a 0 byte answer.

Debug.Assert((cert != null) ^ (privateKey != null));
Debug.Assert((cert is not null) ^ (privateKey is not EnvelopedCmsKey.None));

byte[]? cek;

if (recipientInfo.Pal is ManagedKeyTransPal ktri)
{
RSA? key = privateKey as RSA;
RSA? key = privateKey is RSA rsa ? rsa : null;

if (privateKey != null && key == null)
if (privateKey is not EnvelopedCmsKey.None && key is null)
{
exception = new CryptographicException(SR.Cryptography_Cms_Ktri_RSARequired);
return null;
}

byte[]? cek = ktri.DecryptCek(cert, key, out exception);
// Pin CEK to prevent it from getting copied during heap compaction.
fixed (byte* pinnedCek = cek)
cek = ktri.DecryptCek(cert, key, out exception);
}
#if NET11_0_OR_GREATER
else if (recipientInfo.Pal is ManagedKemRecipientInfoPal kemRecipientInfo)
{
if (privateKey is CompositeMLKem compositeMLKem)
{
try
{
if (exception != null)
{
return null;
}

return TryDecryptCore(
cek!,
_envelopedData.EncryptedContentInfo.ContentType,
_envelopedData.EncryptedContentInfo.EncryptedContent,
_envelopedData.EncryptedContentInfo.ContentEncryptionAlgorithm,
out exception);
}
finally
{
if (cek != null)
{
Array.Clear(cek, 0, cek.Length);
}
}
cek = kemRecipientInfo.DecryptCek(compositeMLKem, out exception);
}
else if (privateKey is MLKem mlKem)
{
cek = kemRecipientInfo.DecryptCek(mlKem, out exception);
}
else if (privateKey is EnvelopedCmsKey.None)
{
Debug.Assert(cert is not null);
cek = kemRecipientInfo.DecryptCek(cert, out exception);
}
else
{
exception = new CryptographicException(
SR.Cryptography_Cms_RecipientType_NotSupported,
recipientInfo.Type.ToString());

return null;
}
}
#endif
else
{
exception = new CryptographicException(
Expand All @@ -87,6 +90,32 @@ public ManagedDecryptorPal(

return null;
}

// Pin CEK to prevent it from getting copied during heap compaction.
fixed (byte* pinnedCek = cek)
{
try
{
if (exception is not null)
{
return null;
}

return TryDecryptCore(
cek!,
_envelopedData.EncryptedContentInfo.ContentType,
_envelopedData.EncryptedContentInfo.EncryptedContent,
_envelopedData.EncryptedContentInfo.ContentEncryptionAlgorithm,
out exception);
}
finally
{
if (cek is not null)
{
CryptographicOperations.ZeroMemory(cek);
}
}
}
}

public static ContentInfo? TryDecryptCore(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public override unsafe byte[] Encrypt(
}
}

private byte[] Encrypt(
private static byte[] Encrypt(
CmsRecipientCollection recipients,
ContentInfo contentInfo,
AlgorithmIdentifier contentEncryptionAlgorithm,
Expand Down Expand Up @@ -102,12 +102,22 @@ private byte[] Encrypt(
envelopedData.RecipientInfos = new RecipientInfoAsn[recipients.Count];

bool allRecipientsVersion0 = true;
bool hasOtherRecipientInfo = false;

for (var i = 0; i < recipients.Count; i++)
{
CmsRecipient recipient = recipients[i];
bool v0Recipient;

#if NET11_0_OR_GREATER
if (PkcsHelpers.IsKeyEncapsulationAlgorithm(recipient.Certificate.GetKeyAlgorithm()))
{
envelopedData.RecipientInfos[i] = MakeKemRecipientInfo(cek, recipient);
hasOtherRecipientInfo = true;
continue;
}
#endif

envelopedData.RecipientInfos[i].Ktri = recipient.Certificate.GetKeyAlgorithm() switch
{
Oids.Rsa => MakeKtri(cek, recipient, out v0Recipient),
Expand All @@ -126,7 +136,7 @@ private byte[] Encrypt(
// 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)
// * Any ORI (other) recipients are present
// v2 (RFC 2630):
// * OriginatorInfo is present
// * Any RecipientInfo has a non-zero version number
Expand All @@ -135,7 +145,11 @@ private byte[] Encrypt(
// v0 (RFC 2315):
// * Anything not already matched

if (envelopedData.OriginatorInfo != null ||
if (hasOtherRecipientInfo)
{
envelopedData.Version = 3;
}
else if (envelopedData.OriginatorInfo != null ||
!allRecipientsVersion0 ||
envelopedData.UnprotectedAttributes != null)
{
Expand Down
Loading
Loading