{
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)
- {
- return DecodeOctetStringCore(encodedOctets);
- }
-
- public static byte[] DecodeOctetStringCore(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.TryReadPrimitiveOctetStringBytes(out var contents))
- {
- if (reader.TryCopyOctetStringBytes(tmp, out int bytesWritten))
- {
- data = tmp.Slice(0, bytesWritten);
- }
- else
- {
- poolBytes = CryptoPool.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;
- }
-
- reader.ThrowIfNotEmpty();
-
- return data.ToArray();
- }
- finally
- {
- if (poolBytes != null)
- {
- CryptoPool.Return(poolBytes, data.Length);
- }
- }
- }
-
- public override byte[] EncodeUtcTime(DateTime utcTime)
- {
- const int maxLegalYear = 2049;
- // 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(), maxLegalYear);
- }
- else
- {
- writer.WriteUtcTime(utcTime, maxLegalYear);
- }
-
- 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.ReadUtcTime();
- reader.ThrowIfNotEmpty();
- 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();
- reader.ThrowIfNotEmpty();
- return value;
- }
-
public override Oid GetEncodedMessageType(byte[] encodedMessage)
{
AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
}
else
{
- parameterBytes = EncodeOctetString(alg.IV);
+ parameterBytes = PkcsHelpers.EncodeOctetString(alg.IV);
}
byte[] toEncrypt = contentInfo.Content;
byte[] encodedContent;
if (contentInfo.ContentType.Value.Equals(Oids.Pkcs7Data, StringComparison.OrdinalIgnoreCase))
{
- unsafe
- {
- byte[] content = contentInfo.Content;
- fixed (byte* pContent = content)
- {
- DATA_BLOB blob = new DATA_BLOB((IntPtr)pContent, (uint)(content.Length));
- encodedContent = Interop.Crypt32.CryptEncodeObjectToByteArray(CryptDecodeObjectStructType.X509_OCTET_STRING, &blob);
- }
- }
+ encodedContent = PkcsHelpers.EncodeOctetString(contentInfo.Content);
}
else
{
return DecryptorPalWindows.Decode(encodedMessage, out version, out contentInfo, out contentEncryptionAlgorithm, out originatorCerts, out unprotectedAttributes);
}
- public sealed override byte[] EncodeOctetString(byte[] octets)
- {
- unsafe
- {
- fixed (byte* pOctets = octets)
- {
- DATA_BLOB blob = new DATA_BLOB((IntPtr)pOctets, (uint)(octets.Length));
- return Interop.Crypt32.CryptEncodeObjectToByteArray(CryptDecodeObjectStructType.X509_OCTET_STRING, &blob);
- }
- }
- }
-
- public sealed override byte[] DecodeOctetString(byte[] encodedOctets)
- {
- using (SafeHandle sh = Interop.Crypt32.CryptDecodeObjectToMemory(CryptDecodeObjectStructType.X509_OCTET_STRING, encodedOctets))
- {
- unsafe
- {
- DATA_BLOB blob = *(DATA_BLOB*)(sh.DangerousGetHandle());
- return blob.ToByteArray();
- }
- }
- }
-
- public sealed override byte[] EncodeUtcTime(DateTime utcTime)
- {
- long ft;
- try
- {
- ft = utcTime.ToFileTimeUtc();
- }
- catch (ArgumentException ex)
- {
- throw new CryptographicException(ex.Message, ex);
- }
-
- unsafe
- {
- return Interop.Crypt32.CryptEncodeObjectToByteArray(CryptDecodeObjectStructType.PKCS_UTC_TIME, &ft);
- }
- }
-
- public sealed override DateTime DecodeUtcTime(byte[] encodedUtcTime)
- {
- long signingTime = 0;
- unsafe
- {
- fixed (byte* pEncodedUtcTime = encodedUtcTime)
- {
- int cbSize = sizeof(long);
- if (!Interop.Crypt32.CryptDecodeObject(CryptDecodeObjectStructType.PKCS_UTC_TIME, (IntPtr)pEncodedUtcTime, encodedUtcTime.Length, &signingTime, ref cbSize))
- throw Marshal.GetLastWin32Error().ToCryptographicException();
- }
- }
- return DateTime.FromFileTimeUtc(signingTime);
- }
-
- public sealed override string DecodeOid(byte[] encodedOid)
- {
- using (SafeHandle sh = Interop.Crypt32.CryptDecodeObjectToMemory(CryptDecodeObjectStructType.X509_OBJECT_IDENTIFIER, encodedOid))
- {
- unsafe
- {
- IntPtr pOidValue = *(IntPtr*)(sh.DangerousGetHandle());
- string contentType = pOidValue.ToStringAnsi();
- return contentType;
- }
- }
- }
-
public sealed override Oid GetEncodedMessageType(byte[] encodedMessage)
{
using (SafeCryptMsgHandle hCryptMsg = Interop.Crypt32.CryptMsgOpenToDecode(MsgEncodingType.All, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
}
}
- public static ReadOnlyMemory<byte> DecodeOctetString(ReadOnlyMemory<byte> encodedOctetString)
+ public static ReadOnlyMemory<byte> DecodeOctetStringAsMemory(ReadOnlyMemory<byte> encodedOctetString)
{
AsnReader reader = new AsnReader(encodedOctetString, AsnEncodingRules.BER);
throw new CryptographicException();
}
+ public static byte[] DecodeOctetString(ReadOnlyMemory<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.TryReadPrimitiveOctetStringBytes(out var contents))
+ {
+ if (reader.TryCopyOctetStringBytes(tmp, out int bytesWritten))
+ {
+ data = tmp.Slice(0, bytesWritten);
+ }
+ else
+ {
+ poolBytes = CryptoPool.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;
+ }
+
+ reader.ThrowIfNotEmpty();
+
+ return data.ToArray();
+ }
+ finally
+ {
+ if (poolBytes != null)
+ {
+ CryptoPool.Return(poolBytes, data.Length);
+ }
+ }
+ }
+
+ public static 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();
+ }
+ }
+
+ private static readonly byte[] s_invalidEmptyOid = { 0x06, 0x00 };
+
+ public static byte[] EncodeUtcTime(DateTime utcTime)
+ {
+ const int maxLegalYear = 2049;
+ // 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(), maxLegalYear);
+ }
+ else
+ {
+ writer.WriteUtcTime(utcTime, maxLegalYear);
+ }
+
+ return writer.Encode();
+ }
+ catch (ArgumentException ex)
+ {
+ throw new CryptographicException(ex.Message, ex);
+ }
+ }
+ }
+
+ public static 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.ReadUtcTime();
+ reader.ThrowIfNotEmpty();
+ return value.UtcDateTime;
+ }
+
+ public static 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();
+ reader.ThrowIfNotEmpty();
+ return value;
+ }
+
public static bool TryGetRsaOaepEncryptionPadding(
ReadOnlyMemory<byte>? parameters,
out RSAEncryptionPadding rsaEncryptionPadding,
/// </summary>
public abstract DecryptorPal Decode(byte[] encodedMessage, out int version, out ContentInfo contentInfo, out AlgorithmIdentifier contentEncryptionAlgorithm, out X509Certificate2Collection originatorCerts, out CryptographicAttributeObjectCollection unprotectedAttributes);
- //
- // Encoders and decoders. These should be moved out of the Pal once we have a managed DER encoder/decoder api.
- //
- public abstract byte[] EncodeOctetString(byte[] octets);
- public abstract byte[] DecodeOctetString(byte[] encodedOctets);
-
- public abstract byte[] EncodeUtcTime(DateTime utcTime);
- public abstract DateTime DecodeUtcTime(byte[] encodedUtcTime);
-
- public abstract string DecodeOid(byte[] encodedOid);
-
/// <summary>
/// Implements the ContentInfo.GetContentType() behavior.
/// </summary>
Oids.Pkcs12CertBag,
EncodeBagValue(
Oids.Pkcs12X509CertBagType,
- PkcsPal.Instance.EncodeOctetString(cert.RawData)),
+ PkcsHelpers.EncodeOctetString(cert.RawData)),
skipCopy: true)
{
_decoded = CertBagAsn.Decode(EncodedBagValue, AsnEncodingRules.BER);
throw new InvalidOperationException(SR.Cryptography_Pkcs12_CertBagNotX509);
}
- return new X509Certificate2(PkcsHelpers.DecodeOctetString(_decoded.CertValue).ToArray());
+ return new X509Certificate2(PkcsHelpers.DecodeOctetString(_decoded.CertValue));
}
private static byte[] EncodeBagValue(Oid certificateType, ReadOnlyMemory<byte> encodedCertificate)
if (pfx.AuthSafe.ContentType == Oids.Pkcs7Data)
{
- authSafeBytes = PkcsHelpers.DecodeOctetString(pfx.AuthSafe.Content);
+ authSafeBytes = PkcsHelpers.DecodeOctetStringAsMemory(pfx.AuthSafe.Content);
if (pfx.MacData.HasValue)
{
break;
case Oids.Pkcs7Data:
ConfidentialityMode = Pkcs12ConfidentialityMode.None;
- _bags = ReadBags(PkcsHelpers.DecodeOctetString(contentInfoAsn.Content));
+ _bags = ReadBags(PkcsHelpers.DecodeOctetStringAsMemory(contentInfoAsn.Content));
break;
default:
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
if (rawData == null)
return null;
- string contentTypeValue = PkcsPal.Instance.DecodeOid(rawData);
+ string contentTypeValue = PkcsHelpers.DecodeOid(rawData);
return new Oid(contentTypeValue);
}
if (rawData == null)
return null;
- byte[] octets = PkcsPal.Instance.DecodeOctetString(rawData);
+ byte[] octets = PkcsHelpers.DecodeOctetString(rawData);
return octets.OctetStringToUnicode();
}
throw new ArgumentNullException(nameof(documentDescription));
byte[] octets = documentDescription.UnicodeToOctetString();
- return PkcsPal.Instance.EncodeOctetString(octets);
+ return PkcsHelpers.EncodeOctetString(octets);
}
private volatile string _lazyDocumentDescription = null;
if (rawData == null)
return null;
- byte[] octets = PkcsPal.Instance.DecodeOctetString(rawData);
+ byte[] octets = PkcsHelpers.DecodeOctetString(rawData);
return octets.OctetStringToUnicode();
}
throw new ArgumentNullException(nameof(documentName));
byte[] octets = documentName.UnicodeToOctetString();
- return PkcsPal.Instance.EncodeOctetString(octets);
+ return PkcsHelpers.EncodeOctetString(octets);
}
private volatile string _lazyDocumentName = null;
// See the LICENSE file in the project root for more information.
using System.Security.Cryptography.Asn1;
-using Internal.Cryptography.Pal.AnyOS;
+using Internal.Cryptography;
namespace System.Security.Cryptography.Pkcs
{
return null;
}
- return ManagedPkcsPal.DecodeOctetStringCore(rawData);
+ return PkcsHelpers.DecodeOctetString(rawData);
}
}
}
if (rawData == null)
return null;
- return PkcsPal.Instance.DecodeOctetString(rawData);
+ return PkcsHelpers.DecodeOctetString(rawData);
}
private volatile byte[] _lazyMessageDigest = null;
if (rawData == null)
return default(DateTime);
- return PkcsPal.Instance.DecodeUtcTime(rawData);
+ return PkcsHelpers.DecodeUtcTime(rawData);
}
private static byte[] Encode(DateTime signingTime)
{
- return PkcsPal.Instance.EncodeUtcTime(signingTime);
+ return PkcsHelpers.EncodeUtcTime(signingTime);
}
private DateTime? _lazySigningTime = default(DateTime?);