You've already forked linux-packaging-mono
Imported Upstream version 4.3.2.467
Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
This commit is contained in:
@@ -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))]
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,9 @@
|
||||
// ==--==
|
||||
|
||||
using System;
|
||||
#if FEATURE_CORESYSTEM
|
||||
using System.Core;
|
||||
#endif
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@@ -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);
|
||||
|
@@ -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 &&
|
||||
|
@@ -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) {
|
||||
|
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,4 +16,4 @@ namespace System.Security.Cryptography {
|
||||
/// </summary>
|
||||
Rfc4050
|
||||
}
|
||||
}
|
||||
}
|
@@ -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>
|
||||
|
508
external/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs
vendored
Normal file
508
external/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,4 +14,4 @@ namespace System.Security {
|
||||
Application = 0x00000002,
|
||||
ApplicationAndDeployment = Deployment | Application
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user