Imported Upstream version 4.3.2.467

Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
This commit is contained in:
Xamarin Public Jenkins
2016-02-22 11:00:01 -05:00
parent f302175246
commit f3e3aab35a
4097 changed files with 122406 additions and 82300 deletions

View File

@@ -5,4 +5,4 @@
// ==--==
// moved to mscorlib.dll
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.Aes))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.Aes))]

View File

@@ -6,6 +6,9 @@
using System;
using System.Collections.Generic;
#if FEATURE_CORESYSTEM
using System.Core;
#endif
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@@ -67,7 +70,7 @@ namespace System.Security.Cryptography {
/// Value of the symmetric key used for encryption / decryption
/// </summary>
public override byte[] Key {
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
get {
Contract.Ensures(m_key != null && !m_key.IsInvalid && !m_key.IsClosed);
@@ -84,7 +87,7 @@ namespace System.Security.Cryptography {
return keyValue;
}
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
set {
Contract.Ensures(m_key != null && !m_key.IsInvalid && !m_key.IsClosed);
@@ -120,7 +123,7 @@ namespace System.Security.Cryptography {
public override int KeySize {
get { return base.KeySize; }
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
set {
base.KeySize = value;
@@ -136,7 +139,7 @@ namespace System.Security.Cryptography {
/// Create an object to perform AES decryption with the current key and IV
/// </summary>
/// <returns></returns>
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
public override ICryptoTransform CreateDecryptor() {
Contract.Ensures(Contract.Result<ICryptoTransform>() != null);
@@ -151,7 +154,7 @@ namespace System.Security.Cryptography {
/// <summary>
/// Create an object to perform AES decryption with the given key and IV
/// </summary>
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
public override ICryptoTransform CreateDecryptor(byte[] key, byte[] iv) {
Contract.Ensures(Contract.Result<ICryptoTransform>() != null);
@@ -197,7 +200,7 @@ namespace System.Security.Cryptography {
/// <summary>
/// Create an object to do AES encryption with the current key and IV
/// </summary>
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
public override ICryptoTransform CreateEncryptor() {
Contract.Ensures(Contract.Result<ICryptoTransform>() != null);
@@ -217,7 +220,7 @@ namespace System.Security.Cryptography {
/// <summary>
/// Create an object to do AES encryption with the given key and IV
/// </summary>
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
public override ICryptoTransform CreateEncryptor(byte[] key, byte[] iv) {
Contract.Ensures(Contract.Result<ICryptoTransform>() != null);
@@ -263,7 +266,7 @@ namespace System.Security.Cryptography {
/// <summary>
/// Release any CAPI handles we're holding onto
/// </summary>
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
protected override void Dispose(bool disposing) {
Contract.Ensures(!disposing || m_key == null || m_key.IsClosed);
Contract.Ensures(!disposing || m_cspHandle == null || m_cspHandle.IsClosed);
@@ -360,7 +363,7 @@ namespace System.Security.Cryptography {
/// <summary>
/// Generate a new random key
/// </summary>
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
public override void GenerateKey() {
Contract.Ensures(m_key != null && !m_key.IsInvalid & !m_key.IsClosed);
@@ -393,7 +396,7 @@ namespace System.Security.Cryptography {
/// <summary>
/// Generate a random initialization vector
/// </summary>
[System.Security.SecurityCritical]
[System.Security.SecuritySafeCritical]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
public override void GenerateIV() {
Contract.Ensures(IVValue != null && IVValue.Length == BlockSizeValue / 8);

View File

@@ -13,8 +13,31 @@ using System.Runtime.InteropServices;
using System.Diagnostics.Contracts;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Security.Cryptography.X509Certificates;
namespace System.Security.Cryptography {
internal enum AsymmetricPaddingMode {
/// <summary>
/// No padding
/// </summary>
None = 1, // BCRYPT_PAD_NONE
/// <summary>
/// PKCS #1 padding
/// </summary>
Pkcs1 = 2, // BCRYPT_PAD_PKCS1
/// <summary>
/// Optimal Asymmetric Encryption Padding
/// </summary>
Oaep = 4, // BCRYPT_PAD_OAEP
/// <summary>
/// Probabilistic Signature Scheme padding
/// </summary>
Pss = 8 // BCRYPT_PAD_PSS
}
/// <summary>
/// Native interop with CNG's BCrypt layer. Native definitions can be found in bcrypt.h
/// </summary>
@@ -34,6 +57,29 @@ namespace System.Security.Cryptography {
public const string Sha256 = "SHA256"; // BCRYPT_SHA256_ALGORITHM
public const string Sha384 = "SHA384"; // BCRYPT_SHA384_ALGORITHM
public const string Sha512 = "SHA512"; // BCRYPT_SHA512_ALGORITHM
internal const string Rsa = "RSA"; // BCRYPT_RSA_ALGORITHM
}
/// <summary>
/// Well known key blob tyes
/// </summary>
internal static class KeyBlobType {
//During Win8 Windows introduced BCRYPT_PUBLIC_KEY_BLOB L"PUBLICBLOB"
//and #define BCRYPT_PRIVATE_KEY_BLOB L"PRIVATEBLOB". We should use the
//same on ProjectN and ProjectK
internal const string RsaFullPrivateBlob = "RSAFULLPRIVATEBLOB"; // BCRYPT_RSAFULLPRIVATE_BLOB
internal const string RsaPrivateBlob = "RSAPRIVATEBLOB"; // BCRYPT_RSAPRIVATE_BLOB
internal const string RsaPublicBlob = "RSAPUBLICBLOB"; // BCRYPT_PUBLIC_KEY_BLOB
}
[StructLayout(LayoutKind.Sequential)]
internal struct BCRYPT_RSAKEY_BLOB {
internal KeyBlobMagicNumber Magic;
internal int BitLength;
internal int cbPublicExp;
internal int cbModulus;
internal int cbPrime1;
internal int cbPrime2;
}
/// <summary>
@@ -61,7 +107,35 @@ namespace System.Security.Cryptography {
ECDHPublicP521 = 0x354B4345, // BCRYPT_ECDH_PUBLIC_P521_MAGIC
ECDsaPublicP256 = 0x31534345, // BCRYPT_ECDSA_PUBLIC_P256_MAGIC
ECDsaPublicP384 = 0x33534345, // BCRYPT_ECDSA_PUBLIC_P384_MAGIC
ECDsaPublicP521 = 0x35534345 // BCRYPT_ECDSA_PUBLIC_P521_MAGIC
ECDsaPublicP521 = 0x35534345, // BCRYPT_ECDSA_PUBLIC_P521_MAGIC
RsaPublic = 0x31415352, // BCRYPT_RSAPUBLIC_MAGIC
RsaPrivate = 0x32415352, // BCRYPT_RSAPRIVATE_MAGIC
RsaFullPrivateMagic = 0x33415352, //BCRYPT_RSAFULLPRIVATE_MAGIC
KeyDataBlob = 0x4d42444b // BCRYPT_KEY_DATA_BLOB_MAGIC
}
[StructLayout(LayoutKind.Sequential)]
internal struct BCRYPT_OAEP_PADDING_INFO {
[MarshalAs(UnmanagedType.LPWStr)]
internal string pszAlgId;
internal IntPtr pbLabel;
internal int cbLabel;
}
[StructLayout(LayoutKind.Sequential)]
internal struct BCRYPT_PKCS1_PADDING_INFO {
[MarshalAs(UnmanagedType.LPWStr)]
internal string pszAlgId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct BCRYPT_PSS_PADDING_INFO {
[MarshalAs(UnmanagedType.LPWStr)]
internal string pszAlgId;
internal int cbSalt;
}
/// <summary>
@@ -73,6 +147,9 @@ namespace System.Security.Cryptography {
public const string Tls = "TLS_PRF"; // BCRYPT_KDF_TLS_PRF
}
internal const string BCRYPT_ECCPUBLIC_BLOB = "ECCPUBLICBLOB";
internal const string BCRYPT_ECCPRIVATE_BLOB = "ECCPRIVATEBLOB";
/// <summary>
/// Well known BCrypt provider names
/// </summary>
@@ -163,6 +240,22 @@ namespace System.Security.Cryptography {
string pszAlgId, // BCryptAlgorithm
string pszImplementation, // ProviderNames
int dwFlags);
[DllImport("bcrypt.dll", SetLastError = true)]
internal static extern ErrorCode BCryptExportKey([In]SafeBCryptKeyHandle hKey,
[In]IntPtr hExportKey,
[In][MarshalAs(UnmanagedType.LPWStr)] string pszBlobType,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
[In]int cbOutput,
[In]ref int pcbResult,
[In] int dwFlags);
[DllImport("Crypt32.dll", SetLastError = true)]
internal static extern int CryptImportPublicKeyInfoEx2([In] uint dwCertEncodingType,
[In] ref X509Native.CERT_PUBLIC_KEY_INFO pInfo,
[In] int dwFlags,
[In] IntPtr pvAuxInfo,
[Out] out SafeBCryptKeyHandle phKey);
}
//
@@ -326,5 +419,40 @@ namespace System.Security.Cryptography {
return algorithmHandle;
}
[SecuritySafeCritical]
internal static SafeBCryptKeyHandle ImportAsymmetricPublicKey(X509Native.CERT_PUBLIC_KEY_INFO certPublicKeyInfo, int dwFlag) {
SafeBCryptKeyHandle keyHandle = null;
int error = UnsafeNativeMethods.CryptImportPublicKeyInfoEx2(
X509Native.X509_ASN_ENCODING,
ref certPublicKeyInfo,
dwFlag,
IntPtr.Zero,
out keyHandle);
if (error == 0) {
throw new CryptographicException(Marshal.GetLastWin32Error());
}
return keyHandle;
}
[SecuritySafeCritical]
internal static byte[] ExportBCryptKey(SafeBCryptKeyHandle hKey, string blobType) {
byte[] keyBlob = null;
int length = 0;
ErrorCode error = UnsafeNativeMethods.BCryptExportKey(hKey, IntPtr.Zero, blobType, null, 0, ref length, 0);
if (error != ErrorCode.BufferToSmall && error != ErrorCode.Success)
{
throw new CryptographicException(Marshal.GetLastWin32Error());
}
keyBlob = new byte[length];
error = UnsafeNativeMethods.BCryptExportKey(hKey, IntPtr.Zero, blobType, keyBlob, length, ref length, 0);
if (error != ErrorCode.Success) {
throw new CryptographicException(Marshal.GetLastWin32Error());
}
return keyBlob;
}
}
}

View File

@@ -5,6 +5,9 @@
// ==--==
using System;
#if FEATURE_CORESYSTEM
using System.Core;
#endif
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;

View File

@@ -28,7 +28,8 @@ namespace System.Security.Cryptography {
private static volatile CngAlgorithm s_sha256;
private static volatile CngAlgorithm s_sha384;
private static volatile CngAlgorithm s_sha512;
private static volatile CngAlgorithm s_rsa;
private string m_algorithm;
public CngAlgorithm(string algorithm) {
@@ -99,6 +100,16 @@ namespace System.Security.Cryptography {
// Well known algorithms
//
public static CngAlgorithm Rsa {
get {
Contract.Ensures(Contract.Result<CngAlgorithm>() != null);
if (s_rsa == null) {
s_rsa = new CngAlgorithm(BCryptNative.AlgorithmName.Rsa);
}
return s_rsa;
}
}
public static CngAlgorithm ECDiffieHellmanP256 {
get {
Contract.Ensures(Contract.Result<CngAlgorithm>() != null);

View File

@@ -126,10 +126,19 @@ namespace System.Security.Cryptography {
Contract.Assert(m_keyHandle != null);
bool foundProperty;
byte[] ephemeralProperty = NCryptNative.GetProperty(m_keyHandle,
NCryptNative.KeyPropertyName.ClrIsEphemeral,
CngPropertyOptions.CustomProperty,
out foundProperty);
byte[] ephemeralProperty = null;
try {
ephemeralProperty = NCryptNative.GetProperty(m_keyHandle,
NCryptNative.KeyPropertyName.ClrIsEphemeral,
CngPropertyOptions.CustomProperty,
out foundProperty);
}
catch (CryptographicException) {
// Third party Key providers, and Windows PCP KSP won't recognize this property;
// and Win32 layer does not enforce error return contract.
// Therefore, they can return whatever error code they think appropriate.
return false;
}
return foundProperty &&
ephemeralProperty != null &&

View File

@@ -26,7 +26,11 @@ namespace System.Security.Cryptography {
//
public static new ECDiffieHellman Create() {
#if MONO
throw new NotImplementedException ();
#else
return Create(typeof(ECDiffieHellmanCng).FullName);
#endif
}
public static new ECDiffieHellman Create(string algorithm) {

View File

@@ -5,6 +5,7 @@
// ==--==
using System;
using System.IO;
namespace System.Security.Cryptography {
/// <summary>
@@ -25,7 +26,11 @@ namespace System.Security.Cryptography {
//
public static new ECDsa Create() {
#if MONO
throw new NotImplementedException ();
#else
return Create(typeof(ECDsaCng).FullName);
#endif
}
public static new ECDsa Create(string algorithm) {
@@ -40,7 +45,97 @@ namespace System.Security.Cryptography {
// Signature operations
//
// ECDsa does not encode the algorithm identifier into the signature blob, therefore SignHash and VerifyHash
// do not need the HashAlgorithmName value, only SignData and VerifyData do.
public abstract byte[] SignHash(byte[] hash);
public abstract bool VerifyHash(byte[] hash, byte[] signature);
protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) {
throw DerivedClassMustOverride();
}
protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) {
throw DerivedClassMustOverride();
}
public virtual byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) {
if (data == null) {
throw new ArgumentNullException("data");
}
return SignData(data, 0, data.Length, hashAlgorithm);
}
public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) {
if (data == null) { throw new ArgumentNullException("data"); }
if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException("offset"); }
if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException("count"); }
if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
byte[] hash = HashData(data, offset, count, hashAlgorithm);
return SignHash(hash);
}
public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm) {
if (data == null) {
throw new ArgumentNullException("data");
}
if (String.IsNullOrEmpty(hashAlgorithm.Name)) {
throw HashAlgorithmNameNullOrEmpty();
}
byte[] hash = HashData(data, hashAlgorithm);
return SignHash(hash);
}
public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm) {
if (data == null) {
throw new ArgumentNullException("data");
}
return VerifyData(data, 0, data.Length, signature, hashAlgorithm);
}
public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm) {
if (data == null) {
throw new ArgumentNullException("data");
}
if (offset < 0 || offset > data.Length) {
throw new ArgumentOutOfRangeException("offset");
}
if (count < 0 || count > data.Length - offset) {
throw new ArgumentOutOfRangeException("count");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
if (String.IsNullOrEmpty(hashAlgorithm.Name)) {
throw HashAlgorithmNameNullOrEmpty();
}
byte[] hash = HashData(data, offset, count, hashAlgorithm);
return VerifyHash(hash, signature);
}
public bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm) {
if (data == null) {
throw new ArgumentNullException("data");
}
if (signature == null) {
throw new ArgumentNullException("signature");
}
if (String.IsNullOrEmpty(hashAlgorithm.Name)) {
throw HashAlgorithmNameNullOrEmpty();
}
byte[] hash = HashData(data, hashAlgorithm);
return VerifyHash(hash, signature);
}
private static Exception DerivedClassMustOverride() {
return new NotImplementedException(SR.GetString(SR.NotSupported_SubclassOverride));
}
internal static Exception HashAlgorithmNameNullOrEmpty() {
return new ArgumentException(SR.GetString(SR.Cryptography_HashAlgorithmNameNullOrEmpty), "hashAlgorithm");
}
}
}

View File

@@ -375,5 +375,37 @@ namespace System.Security.Cryptography {
return NCryptNative.VerifySignature(keyHandle, hash, signature);
}
}
/// <summary>
/// Helper property to get the NCrypt key handle
/// </summary>
private SafeNCryptKeyHandle KeyHandle {
[SecuritySafeCritical]
get { return Key.Handle; }
}
protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) {
// we're sealed and the base should have checked this before calling us
Debug.Assert(data != null);
Debug.Assert(offset >= 0 && offset <= data.Length);
Debug.Assert(count >= 0 && count <= data.Length - offset);
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
using (BCryptHashAlgorithm hasher = new BCryptHashAlgorithm(new CngAlgorithm(hashAlgorithm.Name), BCryptNative.ProviderName.MicrosoftPrimitiveProvider)) {
hasher.HashCore(data, offset, count);
return hasher.HashFinal();
}
}
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) {
// we're sealed and the base should have checked this before calling us
Debug.Assert(data != null);
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
using (BCryptHashAlgorithm hasher = new BCryptHashAlgorithm(new CngAlgorithm(hashAlgorithm.Name), BCryptNative.ProviderName.MicrosoftPrimitiveProvider)) {
hasher.HashStream(data);
return hasher.HashFinal();
}
}
}
}

View File

@@ -16,4 +16,4 @@ namespace System.Security.Cryptography {
/// </summary>
Rfc4050
}
}
}

View File

@@ -129,7 +129,8 @@ namespace System.Security.Cryptography {
BadSignature = unchecked((int)0x80090006), // NTE_BAD_SIGNATURE
NotFound = unchecked((int)0x80090011), // NTE_NOT_FOUND
KeyDoesNotExist = unchecked((int)0x80090016), // NTE_BAD_KEYSET
BufferTooSmall = unchecked((int)0x80090028) // NTE_BUFFER_TOO_SMALL
BufferTooSmall = unchecked((int)0x80090028), // NTE_BUFFER_TOO_SMALL
NoMoreItems = unchecked((int)0x8009002a) // NTE_NO_MORE_ITEMS
}
/// <summary>
@@ -380,8 +381,137 @@ namespace System.Security.Cryptography {
[MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
int cbSignature,
int dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
[In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pPaddingInfo,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
int cbHashValue,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
int cbSignature,
[Out] out int pcbResult,
AsymmetricPaddingMode dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
[In] ref BCryptNative.BCRYPT_PSS_PADDING_INFO pPaddingInfo,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
int cbHashValue,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
int cbSignature,
[Out] out int pcbResult,
AsymmetricPaddingMode dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
[In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pPaddingInfo,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
int cbHashValue,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
int cbSignature,
AsymmetricPaddingMode dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
[In] ref BCryptNative.BCRYPT_PSS_PADDING_INFO pPaddingInfo,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
int cbHashValue,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
int cbSignature,
AsymmetricPaddingMode dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
int cbInput,
[In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
int cbOutput,
[Out] out int pcbResult,
AsymmetricPaddingMode dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
int cbInput,
[In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
int cbOutput,
[Out] out int pcbResult,
AsymmetricPaddingMode dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
int cbInput,
[In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
int cbOutput,
[Out] out int pcbResult,
AsymmetricPaddingMode dwFlags);
[DllImport("ncrypt.dll")]
internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
[In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
int cbInput,
[In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
int cbOutput,
[Out] out int pcbResult,
AsymmetricPaddingMode dwFlags);
}
/// <summary>
/// Adapter to wrap specific NCryptDecrypt P/Invokes with specific padding info
/// </summary>
[SecuritySafeCritical]
private delegate ErrorCode NCryptDecryptor<T>(SafeNCryptKeyHandle hKey,
byte[] pbInput,
int cbInput,
ref T pvPadding,
byte[] pbOutput,
int cbOutput,
out int pcbResult,
AsymmetricPaddingMode dwFlags);
/// <summary>
/// Adapter to wrap specific NCryptEncrypt P/Invokes with specific padding info
/// </summary>
[SecuritySafeCritical]
private delegate ErrorCode NCryptEncryptor<T>(SafeNCryptKeyHandle hKey,
byte[] pbInput,
int cbInput,
ref T pvPadding,
byte[] pbOutput,
int cbOutput,
out int pcbResult,
AsymmetricPaddingMode dwFlags);
/// <summary>
/// Adapter to wrap specific NCryptSignHash P/Invokes with a specific padding info
/// </summary>
[SecuritySafeCritical]
private delegate ErrorCode NCryptHashSigner<T>(SafeNCryptKeyHandle hKey,
ref T pvPaddingInfo,
byte[] pbHashValue,
int cbHashValue,
byte[] pbSignature,
int cbSignature,
out int pcbResult,
AsymmetricPaddingMode dwFlags);
/// <summary>
/// Adapter to wrap specific NCryptVerifySignature P/Invokes with a specific padding info
/// </summary>
[SecuritySafeCritical]
private delegate ErrorCode NCryptSignatureVerifier<T>(SafeNCryptKeyHandle hKey,
ref T pvPaddingInfo,
byte[] pbHashValue,
int cbHashValue,
byte[] pbSignature,
int cbSignature,
AsymmetricPaddingMode dwFlags) where T : struct;
//
// Utility and wrapper functions
//
@@ -389,6 +519,340 @@ namespace System.Security.Cryptography {
private static volatile bool s_haveNcryptSupported;
private static volatile bool s_ncryptSupported;
/// <summary>
/// Generic decryption method, wrapped by decryption calls for specific padding modes
/// </summary>
[SecuritySafeCritical]
private static byte[] DecryptData<T>(SafeNCryptKeyHandle key,
byte[] data,
ref T paddingInfo,
AsymmetricPaddingMode paddingMode,
NCryptDecryptor<T> decryptor) where T : struct {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
Debug.Assert(data != null, "data != null");
Debug.Assert(decryptor != null, "decryptor != null");
// Figure out how big of a buffer is needed to store the decrypted data
int decryptedSize = 0;
ErrorCode error = decryptor(key,
data,
data.Length,
ref paddingInfo,
null,
0,
out decryptedSize,
paddingMode);
if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
throw new CryptographicException((int)error);
}
// Do the decryption
byte[] decrypted = new byte[decryptedSize];
error = decryptor(key,
data,
data.Length,
ref paddingInfo,
decrypted,
decrypted.Length,
out decryptedSize,
paddingMode);
if (error != ErrorCode.Success) {
throw new CryptographicException((int)error);
}
// Sometimes decryptedSize can be less than the allocated buffer size
// So resize the array to the actual returned plaintext
Array.Resize(ref decrypted, decryptedSize);
return decrypted;
}
/// <summary>
/// Decrypt data using PKCS1 padding
/// </summary>
[SecuritySafeCritical]
internal static byte[] DecryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
return DecryptData(key,
data,
ref pkcs1Info,
AsymmetricPaddingMode.Pkcs1,
UnsafeNativeMethods.NCryptDecrypt);
}
/// <summary>
/// Decrypt data using OAEP padding
/// </summary>
[SecuritySafeCritical]
internal static byte[] DecryptDataOaep(SafeNCryptKeyHandle key,
byte[] data,
string hashAlgorithm) {
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
oaepInfo.pszAlgId = hashAlgorithm;
return DecryptData(key,
data,
ref oaepInfo,
AsymmetricPaddingMode.Oaep,
UnsafeNativeMethods.NCryptDecrypt);
}
/// <summary>
/// Generic encryption method, wrapped by decryption calls for specific padding modes
/// </summary>
[SecuritySafeCritical]
private static byte[] EncryptData<T>(SafeNCryptKeyHandle key,
byte[] data,
ref T paddingInfo,
AsymmetricPaddingMode paddingMode,
NCryptEncryptor<T> encryptor) where T : struct {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
Debug.Assert(data != null, "data != null");
Debug.Assert(encryptor != null, "encryptor != null");
// Figure out how big of a buffer is to encrypt the data
int encryptedSize = 0;
ErrorCode error = encryptor(key,
data,
data.Length,
ref paddingInfo,
null,
0,
out encryptedSize,
paddingMode);
if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
throw new CryptographicException((int)error);
}
// Do the encryption
byte[] encrypted = new byte[encryptedSize];
error = encryptor(key,
data,
data.Length,
ref paddingInfo,
encrypted,
encrypted.Length,
out encryptedSize,
paddingMode);
if (error != ErrorCode.Success) {
throw new CryptographicException((int)error);
}
return encrypted;
}
/// <summary>
/// Encrypt data using OAEP padding
/// </summary>
[SecuritySafeCritical]
internal static byte[] EncryptDataOaep(SafeNCryptKeyHandle key,
byte[] data,
string hashAlgorithm) {
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
oaepInfo.pszAlgId = hashAlgorithm;
return EncryptData(key,
data,
ref oaepInfo,
AsymmetricPaddingMode.Oaep,
UnsafeNativeMethods.NCryptEncrypt);
}
/// <summary>
/// Encrypt data using PKCS1 padding
/// </summary>
[SecuritySafeCritical]
internal static byte[] EncryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
return EncryptData(key,
data,
ref pkcs1Info,
AsymmetricPaddingMode.Pkcs1,
UnsafeNativeMethods.NCryptEncrypt);
}
/// <summary>
/// Generic signature method, wrapped by signature calls for specific padding modes
/// </summary>
[SecuritySafeCritical]
private static byte[] SignHash<T>(SafeNCryptKeyHandle key,
byte[] hash,
ref T paddingInfo,
AsymmetricPaddingMode paddingMode,
NCryptHashSigner<T> signer) where T : struct {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsInvalid && !key.IsClosed, "!key.IsInvalid && !key.IsClosed");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(signer != null, "signer != null");
// Figure out how big the signature is
int signatureSize = 0;
ErrorCode error = signer(key,
ref paddingInfo,
hash,
hash.Length,
null,
0,
out signatureSize,
paddingMode);
if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
throw new CryptographicException((int)error);
}
// Sign the hash
byte[] signature = new byte[signatureSize];
error = signer(key,
ref paddingInfo,
hash,
hash.Length,
signature,
signature.Length,
out signatureSize,
paddingMode);
if (error != ErrorCode.Success) {
throw new CryptographicException((int)error);
}
return signature;
}
/// <summary>
/// Sign a hash, using PKCS1 padding
/// </summary>
[SecuritySafeCritical]
internal static byte[] SignHashPkcs1(SafeNCryptKeyHandle key,
byte[] hash,
string hashAlgorithm) {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
pkcs1Info.pszAlgId = hashAlgorithm;
return SignHash(key,
hash,
ref pkcs1Info,
AsymmetricPaddingMode.Pkcs1,
UnsafeNativeMethods.NCryptSignHash);
}
/// <summary>
/// Sign a hash, using PSS padding
/// </summary>
[SecuritySafeCritical]
internal static byte[] SignHashPss(SafeNCryptKeyHandle key,
byte[] hash,
string hashAlgorithm,
int saltBytes) {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
Debug.Assert(saltBytes >= 0, "saltBytes >= 0");
BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
pssInfo.pszAlgId = hashAlgorithm;
pssInfo.cbSalt = saltBytes;
return SignHash(key,
hash,
ref pssInfo,
AsymmetricPaddingMode.Pss,
UnsafeNativeMethods.NCryptSignHash);
}
/// <summary>
/// Generic signature verification method, wrapped by verification calls for specific padding modes
/// </summary>
[SecuritySafeCritical]
private static bool VerifySignature<T>(SafeNCryptKeyHandle key,
byte[] hash,
byte[] signature,
ref T paddingInfo,
AsymmetricPaddingMode paddingMode,
NCryptSignatureVerifier<T> verifier) where T : struct {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(signature != null, "signature != null");
Debug.Assert(verifier != null, "verifier != null");
ErrorCode error = verifier(key,
ref paddingInfo,
hash,
hash.Length,
signature,
signature.Length,
paddingMode);
if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
throw new CryptographicException((int)error);
}
return error == ErrorCode.Success;
}
/// <summary>
/// Verify the signature of a hash using PKCS #1 padding
/// </summary>
[SecuritySafeCritical]
internal static bool VerifySignaturePkcs1(SafeNCryptKeyHandle key,
byte[] hash,
string hashAlgorithm,
byte[] signature) {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
Debug.Assert(signature != null, "signature != null");
BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
pkcs1Info.pszAlgId = hashAlgorithm;
return VerifySignature(key,
hash,
signature,
ref pkcs1Info,
AsymmetricPaddingMode.Pkcs1,
UnsafeNativeMethods.NCryptVerifySignature);
}
/// <summary>
/// Verify the signature of a hash using PSS padding
/// </summary>
[SecuritySafeCritical]
internal static bool VerifySignaturePss(SafeNCryptKeyHandle key,
byte[] hash,
string hashAlgorithm,
int saltBytes,
byte[] signature) {
Debug.Assert(key != null, "key != null");
Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
Debug.Assert(hash != null, "hash != null");
Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
Debug.Assert(signature != null, "signature != null");
BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
pssInfo.pszAlgId = hashAlgorithm;
pssInfo.cbSalt = saltBytes;
return VerifySignature(key,
hash,
signature,
ref pssInfo,
AsymmetricPaddingMode.Pss,
UnsafeNativeMethods.NCryptVerifySignature);
}
/// <summary>
/// Determine if NCrypt is supported on the current machine
/// </summary>
@@ -484,9 +948,7 @@ namespace System.Security.Cryptography {
if (error != ErrorCode.Success) {
throw new CryptographicException((int)error);
}
// Key handles are no longer valid after deleting
key.Dispose();
key.SetHandleAsInvalid();
}
/// <summary>

File diff suppressed because it is too large Load Diff

View File

@@ -31,7 +31,7 @@ namespace System.Security.Cryptography {
InvalidTimePeriodNesting = unchecked((int)0x800b0102), // CERT_E_VALIDITYPERIODNESTING
InvalidCertificateRole = unchecked((int)0x800b0103), // CERT_E_ROLE
PathLengthConstraintViolated = unchecked((int)0x800b0104), // CERT_E_PATHLENCONST
UnknownCriticalExtension = unchecked((int)0x800b0105), // CERT_E_
UnknownCriticalExtension = unchecked((int)0x800b0105), // CERT_E_CRITICAL
CertificateUsageNotAllowed = unchecked((int)0x800b0106), // CERT_E_PURPOSE
IssuerChainingError = unchecked((int)0x800b0107), // CERT_E_ISSUERCHAINING
CertificateMalformed = unchecked((int)0x800b0108), // CERT_E_MALFORMED
@@ -47,4 +47,4 @@ namespace System.Security.Cryptography {
InvalidCertificatePolicy = unchecked((int)0x800b0113), // CERT_E_INVALID_POLICY
InvalidCertificateName = unchecked((int)0x800b0114) // CERT_E_INVALID_NAME
}
}
}

View File

@@ -0,0 +1,129 @@
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace System.Security.Cryptography.X509Certificates
{
/// <summary>
/// Provides extension methods for retrieving <see cref="ECDsa" /> implementations for the
/// public and private keys of a <see cref="X509Certificate2" />.
/// </summary>
public static class ECDsaCertificateExtensions
{
/// <summary>
/// Gets the <see cref="ECDsa" /> private key from the certificate or null if
/// the certificate does not have an ECDsa private key.
/// </summary>
[SecuritySafeCritical]
public static ECDsa GetECDsaPrivateKey(this X509Certificate2 certificate)
{
if (certificate == null) { throw new ArgumentNullException("certificate"); }
//Check cert for private key and confirm it is ECDSA cert
if (!certificate.HasPrivateKey || !IsECDsa(certificate)) { return null; }
using (SafeCertContextHandle certificateContext = X509Native.GetCertificateContext(certificate))
using (SafeNCryptKeyHandle privateKeyHandle = X509Native.TryAcquireCngPrivateKey(certificateContext))
{
CngKey key = CngKey.Open(privateKeyHandle, CngKeyHandleOpenOptions.None);
return new ECDsaCng(key);
}
}
/// <summary>
/// Gets the <see cref="ECDsa" /> public key from the certificate or null if the certificate does not have an ECDsa public key.
/// </summary>
[SecuritySafeCritical]
public static ECDsa GetECDsaPublicKey(this X509Certificate2 certificate)
{
if (certificate == null) { throw new ArgumentNullException("certificate"); }
if (!IsECDsa(certificate)) { return null; }
SafeCertContextHandle safeCertContext = X509Native.GetCertificateContext(certificate);
IntPtr certHandle = safeCertContext.DangerousGetHandle();
//Read the public key blob from the certificate
X509Native.CERT_CONTEXT pCertContext = (X509Native.CERT_CONTEXT)Marshal.PtrToStructure(certHandle, typeof(X509Native.CERT_CONTEXT));
IntPtr pSubjectPublicKeyInfo = new IntPtr((long)pCertContext.pCertInfo +
(long)Marshal.OffsetOf(typeof(X509Native.CERT_INFO), "SubjectPublicKeyInfo"));
X509Native.CERT_PUBLIC_KEY_INFO certPublicKeyInfo = (X509Native.CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(pSubjectPublicKeyInfo,
typeof(X509Native.CERT_PUBLIC_KEY_INFO));
CngKey key;
//Import the public key blob to BCRYPT_KEY_HANDLE
using (SafeBCryptKeyHandle bcryptKeyHandle = BCryptNative.ImportAsymmetricPublicKey(certPublicKeyInfo, 0))
{
if (bcryptKeyHandle.IsInvalid)
{
throw new CryptographicException("SR.GetString(SR.Cryptography_OpenInvalidHandle)");
}
key = BCryptHandleToNCryptHandle(bcryptKeyHandle);
}
GC.KeepAlive(safeCertContext);
return new ECDsaCng(key);
}
/// <summary>
/// Method take BCrypt handle as input and returns the CNGKey
/// </summary>
/// <param name="bcryptKeyHandle">Accepts BCrypt Handle</param>
/// <returns>Returns CNG key with NCrypt Handle</returns>
private static CngKey BCryptHandleToNCryptHandle(SafeBCryptKeyHandle bcryptKeyHandle)
{
byte[] keyBlob = BCryptNative.ExportBCryptKey(bcryptKeyHandle, BCryptNative.BCRYPT_ECCPUBLIC_BLOB);
//Now Import the key blob as NCRYPT_KEY_HANDLE
CngKey Key = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob);
return Key;
}
/// <summary>
/// Check if the certificate contains ECDsa key or ECDH / ECMQV key.
/// </summary>
/// <param name="certificate">Certificate object</param>
/// <returns>true if ECDsa key. False otherwise</returns>
private static bool IsECDsa(X509Certificate2 certificate)
{
string algName = certificate.PublicKey.Oid.FriendlyName;
string value = certificate.PublicKey.Oid.Value;
//At this point check OID. If it matches for ECC certs
//then go to extensions and find out difference between ECDSA and ECDH certs
if (value != X509Native.szOID_ECC_PUBLIC_KEY) { return false; }
else
{
//Following section is built based on RFC
//http://www.ietf.org/rfc/rfc5280.txt and
//http://www.rfc-archive.org/getrfc.php?rfc=5480. This RFC, section 3 describes when
// key can be ECDSA or ECDH or ECMQV.
foreach (X509Extension extension in certificate.Extensions)
{
//Check Key Usage OID value
if (extension.Oid.Value == "2.5.29.15")
{
X509KeyUsageExtension ext = (X509KeyUsageExtension)extension;
if (!(ext.KeyUsages.HasFlag(X509KeyUsageFlags.KeyAgreement)))
{
//If this does not have KeyAgreement flag present, it cannot be ECDH or ECMQV key as KeyAgreement
// is mandatory flag for ECDH or ECMQV. In that case, at this point, it is safe to assume it is ECDSA
return true;
}
//If key has any of the following flag then it cannot be ECDH or ECMQV. Assume
//it is ECDSA.
if (ext.KeyUsages.HasFlag(X509KeyUsageFlags.DigitalSignature) ||
ext.KeyUsages.HasFlag(X509KeyUsageFlags.NonRepudiation) ||
ext.KeyUsages.HasFlag(X509KeyUsageFlags.KeyCertSign) ||
ext.KeyUsages.HasFlag(X509KeyUsageFlags.CrlSign))
{
return true;
}
else
{
return false;
}
}
}
}
//If key usage extension is not present in the certificate assume ECDSA
return true;
}
}
}

View File

@@ -0,0 +1,106 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace System.Security.Cryptography.X509Certificates
{
/// <summary>
/// Provides extension methods for retrieving <see cref="RSA" /> implementations for the
/// public and private keys of a <see cref="X509Certificate2" />.
/// </summary>
public static class RSACertificateExtensions
{
/// <summary>
/// Gets the <see cref="RSA" /> public key from the certificate or null if the certificate does not have an RSA public key.
/// </summary>
[SecuritySafeCritical]
public static RSA GetRSAPublicKey(this X509Certificate2 certificate)
{
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
if (!IsRSA(certificate))
{
return null;
}
PublicKey publicKey = certificate.PublicKey;
AsnEncodedData asn = publicKey.EncodedKeyValue;
IntPtr structType = new IntPtr(CapiNative.CNG_RSA_PUBLIC_KEY_BLOB);
SafeLocalAllocHandle cngBlobHandle;
uint cngBlobLength;
bool result = CapiNative.DecodeObject(structType, asn.RawData, out cngBlobHandle, out cngBlobLength);
if (!result)
{
throw new CryptographicException(Marshal.GetLastWin32Error());
}
byte[] cngBlob = new byte[cngBlobLength];
using (cngBlobHandle)
{
Marshal.Copy(cngBlobHandle.DangerousGetHandle(), cngBlob, 0, cngBlob.Length);
}
CngKey key = CngKey.Import(cngBlob, CngKeyBlobFormat.GenericPublicBlob);
return new RSACng(key);
}
/// <summary>
/// Gets the <see cref="RSA" /> private key from the certificate or null if the certificate does not have an RSA private key.
/// </summary>
[SecuritySafeCritical]
public static RSA GetRSAPrivateKey(this X509Certificate2 certificate)
{
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
if (!certificate.HasPrivateKey || !IsRSA(certificate))
{
return null;
}
using (SafeCertContextHandle certificateContext = X509Native.GetCertificateContext(certificate))
using (SafeNCryptKeyHandle privateKeyHandle = X509Native.TryAcquireCngPrivateKey(certificateContext))
{
if (privateKeyHandle == null)
{
// fall back to CAPI if we cannot acquire the key using CNG.
return (RSA)certificate.PrivateKey;
}
CngKey key = CngKey.Open(privateKeyHandle, CngKeyHandleOpenOptions.None);
return new RSACng(key);
}
}
private static bool IsRSA(X509Certificate2 certificate)
{
uint algorithmId = OidToAlgorithmId(certificate.PublicKey.Oid);
switch (algorithmId)
{
case CapiNative.CALG_RSA_SIGN:
case CapiNative.CALG_RSA_KEYX:
return true;
default:
return false;
}
}
private static uint OidToAlgorithmId(Oid oid)
{
using (SafeLocalAllocHandle oidHandle = X509Utils.StringToAnsiPtr(oid.Value))
{
CapiNative.CRYPT_OID_INFO oidInfo = CapiNative.CryptFindOIDInfo(CapiNative.CRYPT_OID_INFO_OID_KEY, oidHandle, 0);
return oidInfo.Algid;
}
}
}
}

View File

@@ -5,18 +5,161 @@
// ==--==
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
namespace System.Security.Cryptography.X509Certificates {
internal static partial class X509Native {
/// <summary>
/// Determine if a certificate has a specific property
/// </summary>
[SecuritySafeCritical]
internal static bool HasCertificateProperty(SafeCertContextHandle certificateContext,
CertificateProperty property) {
Debug.Assert(certificateContext != null, "certificateContext != null");
Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid,
"!certificateContext.IsClosed && !certificateContext.IsInvalid");
byte[] buffer = null;
int bufferSize = 0;
bool gotProperty = UnsafeNativeMethods.CertGetCertificateContextProperty(certificateContext,
property,
buffer,
ref bufferSize);
return gotProperty ||
(ErrorCode)Marshal.GetLastWin32Error() == ErrorCode.MoreData;
}
/// <summary>
/// Get the NCrypt handle to the private key of a certificate
/// or null if the private key cannot be acquired by NCrypt.
/// </summary>
[SecuritySafeCritical]
internal static SafeNCryptKeyHandle TryAcquireCngPrivateKey(SafeCertContextHandle certificateContext) {
Debug.Assert(certificateContext != null, "certificateContext != null");
Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid,
"!certificateContext.IsClosed && !certificateContext.IsInvalid");
bool freeKey = true;
SafeNCryptKeyHandle privateKey = null;
RuntimeHelpers.PrepareConstrainedRegions();
try {
int keySpec = 0;
if (!UnsafeNativeMethods.CryptAcquireCertificatePrivateKey(certificateContext,
AcquireCertificateKeyOptions.AcquireOnlyNCryptKeys,
IntPtr.Zero,
out privateKey,
out keySpec,
out freeKey)) {
return null;
}
return privateKey;
}
finally {
// If we're not supposed to release they key handle, then we need to bump the reference count
// on the safe handle to correspond to the reference that Windows is holding on to. This will
// prevent the CLR from freeing the object handle.
//
// This is certainly not the ideal way to solve this problem - it would be better for
// SafeNCryptKeyHandle to maintain an internal bool field that we could toggle here and
// have that suppress the release when the CLR calls the ReleaseHandle override. However, that
// field does not currently exist, so we'll use this hack instead.
if (privateKey != null && !freeKey) {
bool addedRef = false;
privateKey.DangerousAddRef(ref addedRef);
}
}
}
/// <summary>
/// Get an arbitrary property of a certificate
/// </summary>
[SecuritySafeCritical]
internal static byte[] GetCertificateProperty(SafeCertContextHandle certificateContext,
CertificateProperty property) {
Debug.Assert(certificateContext != null, "certificateContext != null");
Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid,
"!certificateContext.IsClosed && !certificateContext.IsInvalid");
byte[] buffer = null;
int bufferSize = 0;
if (!UnsafeNativeMethods.CertGetCertificateContextProperty(certificateContext,
property,
buffer,
ref bufferSize)) {
ErrorCode errorCode = (ErrorCode)Marshal.GetLastWin32Error();
if (errorCode != ErrorCode.MoreData) {
throw new CryptographicException((int)errorCode);
}
}
buffer = new byte[bufferSize];
if (!UnsafeNativeMethods.CertGetCertificateContextProperty(certificateContext,
property,
buffer,
ref bufferSize)) {
throw new CryptographicException(Marshal.GetLastWin32Error());
}
return buffer;
}
/// <summary>
/// Get a property of a certificate formatted as a structure
/// </summary>
[SecurityCritical]
internal static T GetCertificateProperty<T>(SafeCertContextHandle certificateContext,
CertificateProperty property) where T : struct {
Debug.Assert(certificateContext != null, "certificateContext != null");
Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid,
"!certificateContext.IsClosed && !certificateContext.IsInvalid");
byte[] rawProperty = GetCertificateProperty(certificateContext, property);
Debug.Assert(rawProperty.Length >= Marshal.SizeOf(typeof(T)), "Property did not return expected structure");
unsafe {
fixed (byte* pRawProperty = &rawProperty[0]) {
return (T)Marshal.PtrToStructure(new IntPtr(pRawProperty), typeof(T));
}
}
}
/// <summary>
/// Duplicate the certificate context into a safe handle
/// </summary>
[SecuritySafeCritical]
internal static SafeCertContextHandle DuplicateCertContext(IntPtr context) {
Debug.Assert(context != IntPtr.Zero);
return UnsafeNativeMethods.CertDuplicateCertificateContext(context);
}
// Gets a SafeHandle for the X509 certificate. The caller owns the returned handle and should dispose of it. It
// can be used independently of the lifetime of the original X509Certificate.
[SecuritySafeCritical]
internal static SafeCertContextHandle GetCertificateContext(X509Certificate certificate) {
SafeCertContextHandle certificateContext = DuplicateCertContext(certificate.Handle);
// Make sure to keep the X509Certificate object alive until after its certificate context is
// duplicated, otherwise it could end up being closed out from underneath us before we get a
// chance to duplicate the handle.
GC.KeepAlive(certificate);
return certificateContext;
}
}
/// <summary>
/// Native interop layer for X509 certificate and Authenticode functions. Native definitions can be
/// found in wincrypt.h or msaxlapi.h
/// </summary>
internal static class X509Native {
internal static partial class X509Native {
/// <summary>
/// Flags for CertVerifyAuthenticodeLicense
/// </summary>
@@ -31,6 +174,103 @@ namespace System.Security.Cryptography.X509Certificates {
TrustMicrosoftRootOnly = 0x00000020 // AXL_TRUST_MICROSOFT_ROOT_ONLY
}
internal const uint X509_ASN_ENCODING = 0x00000001;
internal const string szOID_ECC_PUBLIC_KEY = "1.2.840.10045.2.1"; //Copied from Windows header file
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CERT_CONTEXT {
internal uint dwCertEncodingType;
internal IntPtr pbCertEncoded;
internal uint cbCertEncoded;
internal IntPtr pCertInfo;
internal IntPtr hCertStore;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CERT_PUBLIC_KEY_INFO {
internal CRYPT_ALGORITHM_IDENTIFIER Algorithm;
internal CRYPT_BIT_BLOB PublicKey;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CERT_INFO {
internal uint dwVersion;
internal CRYPTOAPI_BLOB SerialNumber;
internal CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
internal CRYPTOAPI_BLOB Issuer;
internal FILETIME NotBefore;
internal FILETIME NotAfter;
internal CRYPTOAPI_BLOB Subject;
internal CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
internal CRYPT_BIT_BLOB IssuerUniqueId;
internal CRYPT_BIT_BLOB SubjectUniqueId;
internal uint cExtension;
internal IntPtr rgExtension; // PCERT_EXTENSION
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CRYPT_ALGORITHM_IDENTIFIER {
[MarshalAs(UnmanagedType.LPStr)]
internal string pszObjId;
internal CRYPTOAPI_BLOB Parameters;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CRYPT_BIT_BLOB {
internal uint cbData;
internal IntPtr pbData;
internal uint cUnusedBits;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CRYPTOAPI_BLOB {
internal uint cbData;
internal IntPtr pbData;
}
/// <summary>
/// Flags for the CryptAcquireCertificatePrivateKey API
/// </summary>
internal enum AcquireCertificateKeyOptions {
None = 0x00000000,
AcquireOnlyNCryptKeys = 0x00040000, // CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG
}
/// <summary>
/// Well known certificate property IDs
/// </summary>
internal enum CertificateProperty {
KeyProviderInfo = 2, // CERT_KEY_PROV_INFO_PROP_ID
KeyContext = 5, // CERT_KEY_CONTEXT_PROP_ID
}
/// <summary>
/// Error codes returned from X509 APIs
/// </summary>
internal enum ErrorCode {
Success = 0x00000000, // ERROR_SUCCESS
MoreData = 0x000000ea, // ERROR_MORE_DATA
}
[StructLayout(LayoutKind.Sequential)]
internal struct CRYPT_KEY_PROV_INFO {
[MarshalAs(UnmanagedType.LPWStr)]
internal string pwszContainerName;
[MarshalAs(UnmanagedType.LPWStr)]
internal string pwszProvName;
internal int dwProvType;
internal int dwFlags;
internal int cProvParam;
internal IntPtr rgProvParam; // PCRYPT_KEY_PROV_PARAM
internal int dwKeySpec;
}
[StructLayout(LayoutKind.Sequential)]
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public struct AXL_AUTHENTICODE_SIGNER_INFO {
@@ -96,6 +336,60 @@ namespace System.Security.Cryptography.X509Certificates {
AxlVerificationFlags dwFlags,
[In, Out] ref AXL_AUTHENTICODE_SIGNER_INFO pSignerInfo,
[In, Out] ref AXL_AUTHENTICODE_TIMESTAMPER_INFO pTimestamperInfo);
[DllImport("crypt32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CertGetCertificateContextProperty(SafeCertContextHandle pCertContext,
CertificateProperty dwPropId,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] pvData,
[In, Out] ref int pcbData);
[DllImport("crypt32.dll")]
internal static extern SafeCertContextHandle CertDuplicateCertificateContext(IntPtr certContext); // CERT_CONTEXT *
[DllImport("crypt32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CryptAcquireCertificatePrivateKey(SafeCertContextHandle pCert,
AcquireCertificateKeyOptions dwFlags,
IntPtr pvReserved, // void *
[Out] out SafeNCryptKeyHandle phCryptProvOrNCryptKey,
[Out] out int dwKeySpec,
[Out, MarshalAs(UnmanagedType.Bool)] out bool pfCallerFreeProvOrNCryptKey);
}
}
internal sealed class SafeCertContextHandle : SafeHandleZeroOrMinusOneIsInvalid
{
[SecuritySafeCritical]
private SafeCertContextHandle() : base(true) { }
// 0 is an Invalid Handle
[SecuritySafeCritical]
internal SafeCertContextHandle(IntPtr handle)
: base(true)
{
SetHandle(handle);
}
internal static SafeCertContextHandle InvalidHandle
{
[SecuritySafeCritical]
get { return new SafeCertContextHandle(IntPtr.Zero); }
}
[DllImport("Crypt32.dll", SetLastError = true),
ResourceExposure(ResourceScope.None)]
//#if !FEATURE_CORESYSTEM
// [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
//#endif
private static extern bool CertFreeCertificateContext(IntPtr pCertContext);
#if FEATURE_CORESYSTEM
[SecurityCritical]
#endif
[SecuritySafeCritical]
override protected bool ReleaseHandle()
{
return CertFreeCertificateContext(handle);
}
}
}

View File

@@ -14,4 +14,4 @@ namespace System.Security {
Application = 0x00000002,
ApplicationAndDeployment = Deployment | Application
}
}
}