Imported Upstream version 5.4.0.167

Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-08-21 15:34:15 +00:00
parent e49d6f06c0
commit 536cd135cc
12856 changed files with 563812 additions and 223249 deletions

View File

@@ -2,7 +2,8 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.2.0.0</AssemblyVersion>
<AssemblyVersion>4.2.1.0</AssemblyVersion>
<AssemblyKey>MSFT</AssemblyKey>
<IsNETCoreApp>true</IsNETCoreApp>
<IsUAP>true</IsUAP>
</PropertyGroup>

View File

@@ -18,13 +18,32 @@ namespace Microsoft.Win32.SafeHandles
namespace System.Security.Cryptography.X509Certificates
{
public sealed partial class CertificateRequest
{
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.ECDsa key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { }
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.RSA key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.RSASignaturePadding padding) { }
public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.X509Certificates.PublicKey publicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { }
public CertificateRequest(string subjectName, System.Security.Cryptography.ECDsa key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { }
public CertificateRequest(string subjectName, System.Security.Cryptography.RSA key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.RSASignaturePadding padding) { }
public System.Collections.ObjectModel.Collection<System.Security.Cryptography.X509Certificates.X509Extension> CertificateExtensions { get { throw null; } }
public System.Security.Cryptography.HashAlgorithmName HashAlgorithm { get { throw null; } }
public System.Security.Cryptography.X509Certificates.PublicKey PublicKey { get { throw null; } }
public System.Security.Cryptography.X509Certificates.X500DistinguishedName SubjectName { get { throw null; } }
public System.Security.Cryptography.X509Certificates.X509Certificate2 Create(System.Security.Cryptography.X509Certificates.X500DistinguishedName issuerName, System.Security.Cryptography.X509Certificates.X509SignatureGenerator generator, System.DateTimeOffset notBefore, System.DateTimeOffset notAfter, byte[] serialNumber) { throw null; }
public System.Security.Cryptography.X509Certificates.X509Certificate2 Create(System.Security.Cryptography.X509Certificates.X509Certificate2 issuerCertificate, System.DateTimeOffset notBefore, System.DateTimeOffset notAfter, byte[] serialNumber) { throw null; }
public System.Security.Cryptography.X509Certificates.X509Certificate2 CreateSelfSigned(System.DateTimeOffset notBefore, System.DateTimeOffset notAfter) { throw null; }
public byte[] CreateSigningRequest() { throw null; }
public byte[] CreateSigningRequest(System.Security.Cryptography.X509Certificates.X509SignatureGenerator signatureGenerator) { throw null; }
}
public static partial class DSACertificateExtensions
{
public static System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.DSA privateKey) { throw null; }
public static System.Security.Cryptography.DSA GetDSAPrivateKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }
public static System.Security.Cryptography.DSA GetDSAPublicKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }
}
public static partial class ECDsaCertificateExtensions
{
public static System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.ECDsa privateKey) { throw null; }
public static System.Security.Cryptography.ECDsa GetECDsaPrivateKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }
public static System.Security.Cryptography.ECDsa GetECDsaPublicKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }
}
@@ -47,6 +66,7 @@ namespace System.Security.Cryptography.X509Certificates
}
public static partial class RSACertificateExtensions
{
public static System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.RSA privateKey) { throw null; }
public static System.Security.Cryptography.RSA GetRSAPrivateKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }
public static System.Security.Cryptography.RSA GetRSAPublicKey(this System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }
}
@@ -66,6 +86,16 @@ namespace System.Security.Cryptography.X509Certificates
TrustedPeople = 7,
TrustedPublisher = 8,
}
public sealed partial class SubjectAlternativeNameBuilder
{
public SubjectAlternativeNameBuilder() { }
public void AddDnsName(string dnsName) { }
public void AddEmailAddress(string emailAddress) { }
public void AddIpAddress(System.Net.IPAddress ipAddress) { }
public void AddUri(System.Uri uri) { }
public void AddUserPrincipalName(string upn) { }
public System.Security.Cryptography.X509Certificates.X509Extension Build(bool critical=false) { throw null; }
}
public sealed partial class X500DistinguishedName : System.Security.Cryptography.AsnEncodedData
{
public X500DistinguishedName(byte[] encodedDistinguishedName) { }
@@ -501,6 +531,16 @@ namespace System.Security.Cryptography.X509Certificates
Offline = 2,
Online = 1,
}
public abstract partial class X509SignatureGenerator
{
protected X509SignatureGenerator() { }
public System.Security.Cryptography.X509Certificates.PublicKey PublicKey { get { throw null; } }
protected abstract System.Security.Cryptography.X509Certificates.PublicKey BuildPublicKey();
public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForECDsa(System.Security.Cryptography.ECDsa key) { throw null; }
public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForRSA(System.Security.Cryptography.RSA key, System.Security.Cryptography.RSASignaturePadding signaturePadding) { throw null; }
public abstract byte[] GetSignatureAlgorithmIdentifier(System.Security.Cryptography.HashAlgorithmName hashAlgorithm);
public abstract byte[] SignData(byte[] data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm);
}
public sealed partial class X509Store : System.IDisposable
{
public X509Store() { }
@@ -508,9 +548,12 @@ namespace System.Security.Cryptography.X509Certificates
public X509Store(System.Security.Cryptography.X509Certificates.StoreLocation storeLocation) { }
public X509Store(System.Security.Cryptography.X509Certificates.StoreName storeName) { }
public X509Store(System.Security.Cryptography.X509Certificates.StoreName storeName, System.Security.Cryptography.X509Certificates.StoreLocation storeLocation) { }
public X509Store(System.Security.Cryptography.X509Certificates.StoreName storeName, System.Security.Cryptography.X509Certificates.StoreLocation storeLocation, System.Security.Cryptography.X509Certificates.OpenFlags flags) { }
public X509Store(string storeName) { }
public X509Store(string storeName, System.Security.Cryptography.X509Certificates.StoreLocation storeLocation) { }
public X509Store(string storeName, System.Security.Cryptography.X509Certificates.StoreLocation storeLocation, System.Security.Cryptography.X509Certificates.OpenFlags flags) { }
public System.Security.Cryptography.X509Certificates.X509Certificate2Collection Certificates { get { throw null; } }
public bool IsOpen { get { throw null; } }
public System.Security.Cryptography.X509Certificates.StoreLocation Location { get { throw null; } }
public string Name { get { throw null; } }
public System.IntPtr StoreHandle { get { throw null; } }

View File

@@ -12,6 +12,7 @@
<Compile Include="System.Security.Cryptography.X509Certificates.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Net.Primitives\ref\System.Net.Primitives.csproj" />
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Runtime.InteropServices\ref\System.Runtime.InteropServices.csproj" />
<ProjectReference Include="..\..\System.Collections.NonGeneric\ref\System.Collections.NonGeneric.csproj" />
@@ -20,4 +21,4 @@
<ProjectReference Include="..\..\System.Security.Cryptography.Primitives\ref\System.Security.Cryptography.Primitives.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -0,0 +1,120 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace Internal.Cryptography
{
internal static class EncodingHelpers
{
internal static byte[][] WrapAsSegmentedForSequence(this byte[] derData)
{
// ConstructSegmentedSequence understands triplets, but doesn't care they're valid,
// so lift this up into a "triplet".
return new[] { Array.Empty<byte>(), Array.Empty<byte>(), derData };
}
internal static void ValidateSignatureAlgorithm(byte[] signatureAlgorithm)
{
Debug.Assert(signatureAlgorithm != null);
// AlgorithmIdentifier ::= SEQUENCE { OBJECT IDENTIFIER, ANY }
DerSequenceReader validator = new DerSequenceReader(signatureAlgorithm);
validator.ReadOidAsString();
if (validator.HasData)
{
validator.ValidateAndSkipDerValue();
}
if (validator.HasData)
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
internal static byte[][] SegmentedEncodeSubjectPublicKeyInfo(this PublicKey publicKey)
{
if (publicKey == null)
throw new ArgumentNullException(nameof(publicKey));
if (publicKey.Oid == null ||
string.IsNullOrEmpty(publicKey.Oid.Value) ||
publicKey.EncodedKeyValue == null)
{
throw new CryptographicException(SR.Cryptography_InvalidPublicKey_Object);
}
// SubjectPublicKeyInfo::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// subjectPublicKey BIT STRING
// }
//
// AlgorithmIdentifier::= SEQUENCE {
// algorithm OBJECT IDENTIFIER,
// parameters ANY DEFINED BY algorithm OPTIONAL
// }
byte[][] algorithmIdentifier;
if (publicKey.EncodedParameters == null)
{
algorithmIdentifier = DerEncoder.ConstructSegmentedSequence(
DerEncoder.SegmentedEncodeOid(publicKey.Oid));
}
else
{
DerSequenceReader validator =
DerSequenceReader.CreateForPayload(publicKey.EncodedParameters.RawData);
validator.ValidateAndSkipDerValue();
if (validator.HasData)
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
algorithmIdentifier = DerEncoder.ConstructSegmentedSequence(
DerEncoder.SegmentedEncodeOid(publicKey.Oid),
publicKey.EncodedParameters.RawData.WrapAsSegmentedForSequence());
}
return DerEncoder.ConstructSegmentedSequence(
algorithmIdentifier,
DerEncoder.SegmentedEncodeBitString(
publicKey.EncodedKeyValue.RawData));
}
internal static byte[][] SegmentedEncodedX509Extension(this X509Extension extension)
{
if (extension.Critical)
{
return DerEncoder.ConstructSegmentedSequence(
DerEncoder.SegmentedEncodeOid(extension.Oid),
DerEncoder.SegmentedEncodeBoolean(extension.Critical),
DerEncoder.SegmentedEncodeOctetString(extension.RawData));
}
return DerEncoder.ConstructSegmentedSequence(
DerEncoder.SegmentedEncodeOid(extension.Oid),
DerEncoder.SegmentedEncodeOctetString(extension.RawData));
}
internal static byte[][] SegmentedEncodeAttributeSet(this IEnumerable<X501Attribute> attributes)
{
List<byte[][]> encodedAttributes = new List<byte[][]>();
foreach (X501Attribute attribute in attributes)
{
encodedAttributes.Add(
DerEncoder.ConstructSegmentedSequence(
DerEncoder.SegmentedEncodeOid(attribute.Oid),
DerEncoder.ConstructSegmentedPresortedSet(
attribute.RawData.WrapAsSegmentedForSequence())));
}
return DerEncoder.ConstructSegmentedSet(encodedAttributes.ToArray());
}
}
}

View File

@@ -125,6 +125,14 @@ namespace Internal.Cryptography
return true;
}
internal static void AddRange<T>(this ICollection<T> coll, IEnumerable<T> newData)
{
foreach (T datum in newData)
{
coll.Add(datum);
}
}
//
// The following group of helpers emulates the non-public Calendar.IsValidDay() method used by X509Certificate.ToString(bool).
//
@@ -151,4 +159,27 @@ namespace Internal.Cryptography
}
}
}
internal struct PinAndClear : IDisposable
{
private byte[] _data;
private System.Runtime.InteropServices.GCHandle _gcHandle;
internal static PinAndClear Track(byte[] data)
{
return new PinAndClear
{
_gcHandle = System.Runtime.InteropServices.GCHandle.Alloc(
data,
System.Runtime.InteropServices.GCHandleType.Pinned),
_data = data,
};
}
public void Dispose()
{
Array.Clear(_data, 0, _data.Length);
_gcHandle.Free();
}
}
}

View File

@@ -36,5 +36,8 @@ namespace Internal.Cryptography
ECDsa GetECDsaPrivateKey();
string GetNameInfo(X509NameType nameType, bool forIssuer);
void AppendPrivateKeyInfo(StringBuilder sb);
ICertificatePal CopyWithPrivateKey(DSA privateKey);
ICertificatePal CopyWithPrivateKey(ECDsa privateKey);
ICertificatePal CopyWithPrivateKey(RSA privateKey);
}
}

View File

@@ -2,12 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.Security.Cryptography;
namespace Internal.Cryptography
{
//
@@ -31,8 +25,23 @@ namespace Internal.Cryptography
public const string CertPolicyConstraints = "2.5.29.36";
public const string EnhancedKeyUsage = "2.5.29.37";
public const string InhibitAnyPolicyExtension = "2.5.29.54";
public const string Sha256 = "2.16.840.1.101.3.4.2.1";
public const string Sha384 = "2.16.840.1.101.3.4.2.2";
public const string Sha512 = "2.16.840.1.101.3.4.2.3";
public const string EccCurveSecp384r1 = "1.3.132.0.34";
public const string EccCurveSecp521r1 = "1.3.132.0.35";
public const string Ecc = "1.2.840.10045.2.1";
public const string EccCurveSecp256r1 = "1.2.840.10045.3.1.7";
public const string ECDsaSha256 = "1.2.840.10045.4.3.2";
public const string ECDsaSha384 = "1.2.840.10045.4.3.3";
public const string ECDsaSha512 = "1.2.840.10045.4.3.4";
public const string RsaRsa = "1.2.840.113549.1.1.1";
public const string Mgf1 = "1.2.840.113549.1.1.8";
public const string RsaSsaPss = "1.2.840.113549.1.1.10";
public const string RsaPkcs1Sha256 = "1.2.840.113549.1.1.11";
public const string RsaPkcs1Sha384 = "1.2.840.113549.1.1.12";
public const string RsaPkcs1Sha512 = "1.2.840.113549.1.1.13";
public const string Pkcs9ExtensionRequest = "1.2.840.113549.1.9.14";
public const string DsaDsa = "1.2.840.10040.4.1";
public const string EmailAddress = "1.2.840.113549.1.9.1";
public const string EnrollCertTypeExtension = "1.3.6.1.4.1.311.20.2";

View File

@@ -59,7 +59,9 @@ namespace Internal.Cryptography.Pal
{
Debug.Assert(cert.Pal != null);
return FromHandle(cert.Handle);
ICertificatePal pal = FromHandle(cert.Handle);
GC.KeepAlive(cert); // ensure cert's safe handle isn't finalized while raw handle is in use
return pal;
}
public static ICertificatePal FromBlob(
@@ -153,6 +155,9 @@ namespace Internal.Cryptography.Pal
internal sealed class AppleCertificatePal : ICertificatePal
{
private SafeSecIdentityHandle _identityHandle;
// Do not give out this reference, it's only needed in certain cases to prevent temporary keychains
// from being deleted.
private SafeSecKeyRefHandle _privateKeyHolder;
private SafeSecCertificateHandle _certHandle;
private CertificateData _certData;
private bool _readCertData;
@@ -176,9 +181,11 @@ namespace Internal.Cryptography.Pal
{
_certHandle?.Dispose();
_identityHandle?.Dispose();
_privateKeyHolder?.Dispose();
_certHandle = null;
_identityHandle = null;
_privateKeyHolder = null;
}
internal SafeSecCertificateHandle CertificateHandle => _certHandle;
@@ -358,21 +365,6 @@ namespace Internal.Cryptography.Pal
}
}
public AsymmetricAlgorithm GetPrivateKey()
{
switch (KeyAlgorithm)
{
case Oids.RsaRsa:
return GetRSAPrivateKey();
case Oids.DsaDsa:
return GetDSAPrivateKey();
case Oids.Ecc:
return GetECDsaPrivateKey();
}
throw new NotSupportedException(SR.NotSupported_KeyAlgorithm);
}
public RSA GetRSAPrivateKey()
{
if (_identityHandle == null)
@@ -409,6 +401,103 @@ namespace Internal.Cryptography.Pal
return new ECDsaImplementation.ECDsaSecurityTransforms(publicKey, privateKey);
}
private void HoldPrivateKey()
{
_privateKeyHolder = Interop.AppleCrypto.X509GetPrivateKeyFromIdentity(_identityHandle);
Debug.Assert(!_privateKeyHolder.IsInvalid);
}
public ICertificatePal CopyWithPrivateKey(DSA privateKey)
{
var typedKey = privateKey as DSAImplementation.DSASecurityTransforms;
if (typedKey != null)
{
return CopyWithPrivateKey(typedKey.GetKeys());
}
DSAParameters dsaParameters = privateKey.ExportParameters(true);
using (PinAndClear.Track(dsaParameters.X))
using (typedKey = new DSAImplementation.DSASecurityTransforms())
{
typedKey.ImportParameters(dsaParameters);
return CopyWithPrivateKey(typedKey.GetKeys());
}
}
public ICertificatePal CopyWithPrivateKey(ECDsa privateKey)
{
var typedKey = privateKey as ECDsaImplementation.ECDsaSecurityTransforms;
if (typedKey != null)
{
return CopyWithPrivateKey(typedKey.GetKeys());
}
ECParameters ecParameters = privateKey.ExportParameters(true);
using (PinAndClear.Track(ecParameters.D))
using (typedKey = new ECDsaImplementation.ECDsaSecurityTransforms())
{
typedKey.ImportParameters(ecParameters);
return CopyWithPrivateKey(typedKey.GetKeys());
}
}
public ICertificatePal CopyWithPrivateKey(RSA privateKey)
{
var typedKey = privateKey as RSAImplementation.RSASecurityTransforms;
if (typedKey != null)
{
return CopyWithPrivateKey(typedKey.GetKeys());
}
RSAParameters rsaParameters = privateKey.ExportParameters(true);
using (PinAndClear.Track(rsaParameters.D))
using (PinAndClear.Track(rsaParameters.P))
using (PinAndClear.Track(rsaParameters.Q))
using (PinAndClear.Track(rsaParameters.DP))
using (PinAndClear.Track(rsaParameters.DQ))
using (PinAndClear.Track(rsaParameters.InverseQ))
using (typedKey = new RSAImplementation.RSASecurityTransforms())
{
typedKey.ImportParameters(rsaParameters);
return CopyWithPrivateKey(typedKey.GetKeys());
}
}
private ICertificatePal CopyWithPrivateKey(SecKeyPair keyPair)
{
if (keyPair.PrivateKey == null)
{
// Both Windows and Linux/OpenSSL are unaware if they bound a public or private key.
// Here, we do know. So throw if we can't do what they asked.
throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
}
SafeKeychainHandle keychain = Interop.AppleCrypto.SecKeychainItemCopyKeychain(keyPair.PrivateKey);
if (keychain.IsInvalid)
{
keychain = Interop.AppleCrypto.CreateTemporaryKeychain();
}
using (keychain)
{
SafeSecIdentityHandle identityHandle = Interop.AppleCrypto.X509CopyWithPrivateKey(
_certHandle,
keyPair.PrivateKey,
keychain);
AppleCertificatePal newPal = new AppleCertificatePal(identityHandle);
newPal.HoldPrivateKey();
return newPal;
}
}
public string GetNameInfo(X509NameType nameType, bool forIssuer)
{
// Algorithm behaviors (pseudocode). When forIssuer is true, replace "Subject" with "Issuer" and

View File

@@ -14,11 +14,17 @@ namespace Internal.Cryptography.Pal
{
internal sealed class SecTrustChainPal : IChainPal
{
private const X509ChainStatusFlags RevocationRelevantFlags =
X509ChainStatusFlags.RevocationStatusUnknown |
X509ChainStatusFlags.Revoked |
X509ChainStatusFlags.OfflineRevocation;
private Stack<SafeHandle> _extraHandles;
private SafeX509ChainHandle _chainHandle;
public X509ChainElement[] ChainElements { get; private set; }
public X509ChainStatus[] ChainStatus { get; private set; }
private DateTime _verificationTime;
private X509RevocationMode _revocationMode;
internal SecTrustChainPal()
{
@@ -30,9 +36,10 @@ namespace Internal.Cryptography.Pal
internal void OpenTrustHandle(
ICertificatePal leafCert,
X509Certificate2Collection extraStore,
bool checkRevocation)
X509RevocationMode revocationMode)
{
SafeCreateHandle policiesArray = PreparePoliciesArray(checkRevocation);
_revocationMode = revocationMode;
SafeCreateHandle policiesArray = PreparePoliciesArray(revocationMode != X509RevocationMode.NoCheck);
SafeCreateHandle certsArray = PrepareCertsArray(leafCert, extraStore);
int osStatus;
@@ -173,7 +180,8 @@ namespace Internal.Cryptography.Pal
DateTime verificationTime,
bool allowNetwork,
OidCollection applicationPolicy,
OidCollection certificatePolicy)
OidCollection certificatePolicy,
X509RevocationFlag revocationFlag)
{
int osStatus;
@@ -199,7 +207,8 @@ namespace Internal.Cryptography.Pal
throw new CryptographicException();
}
Tuple<X509Certificate2, int>[] elements = ParseResults(_chainHandle);
Tuple<X509Certificate2, int>[] elements = ParseResults(_chainHandle, _revocationMode);
Debug.Assert(elements.Length > 0);
if (!IsPolicyMatch(elements, applicationPolicy, certificatePolicy))
{
@@ -210,10 +219,13 @@ namespace Internal.Cryptography.Pal
currentValue.Item2 | (int)X509ChainStatusFlags.NotValidForUsage);
}
FixupRevocationStatus(elements, revocationFlag);
BuildAndSetProperties(elements);
}
private static Tuple<X509Certificate2,int>[] ParseResults(SafeX509ChainHandle chainHandle)
private static Tuple<X509Certificate2, int>[] ParseResults(
SafeX509ChainHandle chainHandle,
X509RevocationMode revocationMode)
{
long elementCount = Interop.AppleCrypto.X509ChainGetChainSize(chainHandle);
var elements = new Tuple<X509Certificate2, int>[elementCount];
@@ -238,7 +250,7 @@ namespace Internal.Cryptography.Pal
X509Certificate2 cert = new X509Certificate2(certHandle);
FixupStatus(cert, ref dwStatus);
FixupStatus(cert, revocationMode, ref dwStatus);
elements[elementIdx] = Tuple.Create(cert, dwStatus);
}
@@ -302,7 +314,47 @@ namespace Internal.Cryptography.Pal
ChainStatus = rollupElement.ChainElementStatus;
}
private static void FixupStatus(X509Certificate2 cert, ref int dwStatus)
private static void FixupRevocationStatus(
Tuple<X509Certificate2, int>[] elements,
X509RevocationFlag revocationFlag)
{
if (revocationFlag == X509RevocationFlag.ExcludeRoot)
{
// When requested
int idx = elements.Length - 1;
Tuple<X509Certificate2, int> element = elements[idx];
X509ChainStatusFlags statusFlags = (X509ChainStatusFlags)element.Item2;
// Apple will terminate the chain at the first "root" or "trustAsRoot" certificate
// it finds, which it refers to as "anchors". We'll consider a "trustAsRoot" cert
// as a root for the purposes of ExcludeRoot. So as long as the last element doesn't
// have PartialChain consider it the root.
if ((statusFlags & X509ChainStatusFlags.PartialChain) == 0)
{
statusFlags &= ~RevocationRelevantFlags;
elements[idx] = Tuple.Create(element.Item1, (int)statusFlags);
}
}
else if (revocationFlag == X509RevocationFlag.EndCertificateOnly)
{
// In Windows the EndCertificateOnly flag (CERT_CHAIN_REVOCATION_CHECK_END_CERT) will apply
// to a root if that's the only element, so we'll do the same.
// Start at element 1, and move to the end.
for (int i = 1; i < elements.Length; i++)
{
Tuple<X509Certificate2, int> element = elements[i];
X509ChainStatusFlags statusFlags = (X509ChainStatusFlags)element.Item2;
statusFlags &= ~RevocationRelevantFlags;
elements[i] = Tuple.Create(element.Item1, (int)statusFlags);
}
}
}
private static void FixupStatus(
X509Certificate2 cert,
X509RevocationMode revocationMode,
ref int dwStatus)
{
X509ChainStatusFlags flags = (X509ChainStatusFlags)dwStatus;
@@ -318,6 +370,15 @@ namespace Internal.Cryptography.Pal
dwStatus = (int)flags;
}
}
if (revocationMode == X509RevocationMode.NoCheck)
{
// Clear any revocation-related flags if NoCheck was requested, since
// the OS may use cached results opportunistically.
flags &= ~RevocationRelevantFlags;
dwStatus = (int)flags;
}
}
private static X509ChainStatusFlags FindUntrustedRootReason(X509Certificate2 cert)
@@ -501,14 +562,18 @@ namespace Internal.Cryptography.Pal
// or off (and AIA fetching doesn't work). And once an SSL policy is used, or revocation is
// being checked, the value is on anyways.
const bool allowNetwork = true;
bool checkRevocation = revocationMode != X509RevocationMode.NoCheck;
SecTrustChainPal chainPal = new SecTrustChainPal();
try
{
chainPal.OpenTrustHandle(cert, extraStore, checkRevocation);
chainPal.Execute(verificationTime, allowNetwork, applicationPolicy, certificatePolicy);
chainPal.OpenTrustHandle(cert, extraStore, revocationMode);
chainPal.Execute(
verificationTime,
allowNetwork,
applicationPolicy,
certificatePolicy,
revocationFlag);
}
catch
{

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
@@ -57,7 +58,9 @@ namespace Internal.Cryptography.Pal
protected override X509Certificate2 CloneCertificate(X509Certificate2 cert)
{
return new X509Certificate2(cert.Handle);
var clone = new X509Certificate2(cert.Handle);
GC.KeepAlive(cert); // ensure cert's safe handle isn't finalized while raw handle is in use
return clone;
}
}
}

View File

@@ -90,7 +90,9 @@ namespace Internal.Cryptography.Pal
}
}
return Interop.AppleCrypto.X509ExportPfx(certHandles, password);
byte[] exported = Interop.AppleCrypto.X509ExportPfx(certHandles, password);
GC.KeepAlive(_certs); // ensure certs' safe handles aren't finalized while raw handles are in use
return exported;
}
private byte[] ExportPkcs7()

View File

@@ -123,11 +123,12 @@ namespace Internal.Cryptography.Pal
if ((openFlags & OpenFlags.OpenExistingOnly) == OpenFlags.OpenExistingOnly)
throw new CryptographicException(SR.Cryptography_X509_StoreNotFound);
throw new PlatformNotSupportedException(
SR.Format(
SR.Cryptography_X509_StoreCannotCreate,
storeName,
storeLocation));
string message = SR.Format(
SR.Cryptography_X509_StoreCannotCreate,
storeName,
storeLocation);
throw new CryptographicException(message, new PlatformNotSupportedException(message));
}
private static void ReadCollection(SafeCFArrayHandle matches, HashSet<X509Certificate2> collection)

View File

@@ -49,10 +49,17 @@ namespace Internal.Cryptography.Pal
verificationTime = verificationTime.ToLocalTime();
}
// Until we support the Disallowed store, ensure it's empty (which is done by the ctor)
using (new X509Store(StoreName.Disallowed, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
{
}
TimeSpan remainingDownloadTime = timeout;
using (var leaf = new X509Certificate2(cert.Handle))
{
GC.KeepAlive(cert); // ensure cert's safe handle isn't finalized while raw handle is in use
var downloaded = new HashSet<X509Certificate2>();
var systemTrusted = new HashSet<X509Certificate2>();
@@ -66,7 +73,6 @@ namespace Internal.Cryptography.Pal
IChainPal chain = OpenSslX509ChainProcessor.BuildChain(
leaf,
candidates,
downloaded,
systemTrusted,
applicationPolicy,
certificatePolicy,

View File

@@ -48,19 +48,9 @@ namespace Internal.Cryptography.Pal
throw new CryptographicException(SR.Arg_EmptyOrNullString);
}
string directoryName = GetDirectoryName(storeName);
Debug.Assert(!X509Store.DisallowedStoreName.Equals(storeName, StringComparison.OrdinalIgnoreCase));
if (s_userStoreRoot == null)
{
// Do this here instead of a static field initializer so that
// the static initializer isn't capable of throwing the "home directory not found"
// exception.
s_userStoreRoot = PersistedFiles.GetUserFeatureDirectory(
X509Persistence.CryptographyFeatureName,
X509Persistence.X509StoresSubFeatureName);
}
_storePath = Path.Combine(s_userStoreRoot, directoryName);
_storePath = GetStorePath(storeName);
if (0 != (openFlags & OpenFlags.OpenExistingOnly))
{
@@ -283,6 +273,23 @@ namespace Internal.Cryptography.Pal
throw new CryptographicException(SR.Cryptography_X509_StoreNoFileAvailable);
}
private static string GetStorePath(string storeName)
{
string directoryName = GetDirectoryName(storeName);
if (s_userStoreRoot == null)
{
// Do this here instead of a static field initializer so that
// the static initializer isn't capable of throwing the "home directory not found"
// exception.
s_userStoreRoot = PersistedFiles.GetUserFeatureDirectory(
X509Persistence.CryptographyFeatureName,
X509Persistence.X509StoresSubFeatureName);
}
return Path.Combine(s_userStoreRoot, directoryName);
}
private static string GetDirectoryName(string storeName)
{
Debug.Assert(storeName != null);
@@ -379,10 +386,87 @@ namespace Internal.Cryptography.Pal
new IOException(error.GetErrorMessage(), error.RawErrno));
}
Debug.Assert(Interop.Sys.FStat(stream.SafeFileHandle, out stat) == 0);
Debug.Assert((stat.Mode & (int)requiredPermissions) == (int)requiredPermissions);
Debug.Assert((stat.Mode & (int)forbiddenPermissions) == 0);
// Verify the chmod applied.
if (Interop.Sys.FStat(stream.SafeFileHandle, out stat) != 0)
{
Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
throw new CryptographicException(
SR.Cryptography_FileStatusError,
new IOException(error.GetErrorMessage(), error.RawErrno));
}
if ((stat.Mode & (int)requiredPermissions) != (int)requiredPermissions ||
(stat.Mode & (int)forbiddenPermissions) != 0)
{
throw new CryptographicException(SR.Format(SR.Cryptography_InvalidFilePermissions, stream.Name));
}
}
}
internal sealed class UnsupportedDisallowedStore : IStorePal
{
private readonly bool _readOnly;
internal UnsupportedDisallowedStore(OpenFlags openFlags)
{
// ReadOnly is 0x00, so it is implicit unless either ReadWrite or MaxAllowed
// was requested.
OpenFlags writeFlags = openFlags & (OpenFlags.ReadWrite | OpenFlags.MaxAllowed);
if (writeFlags == OpenFlags.ReadOnly)
{
_readOnly = true;
}
string storePath = GetStorePath(X509Store.DisallowedStoreName);
try
{
if (Directory.Exists(storePath))
{
// If it has no files, leave it alone.
foreach (string filePath in Directory.EnumerateFiles(storePath))
{
string msg = SR.Format(SR.Cryptography_Unix_X509_DisallowedStoreNotEmpty, storePath);
throw new CryptographicException(msg, new PlatformNotSupportedException(msg));
}
}
}
catch (IOException)
{
// Suppress the exception, treat the store as empty.
}
}
public void Dispose()
{
// Nothing to do.
}
public void CloneTo(X509Certificate2Collection collection)
{
// Never show any data.
}
public void Add(ICertificatePal cert)
{
if (_readOnly)
{
throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
}
throw new CryptographicException(
SR.Cryptography_Unix_X509_NoDisallowedStore,
new PlatformNotSupportedException(SR.Cryptography_Unix_X509_NoDisallowedStore));
}
public void Remove(ICertificatePal cert)
{
// Remove never throws if it does no measurable work.
// Since CloneTo always says the store is empty, no measurable work is ever done.
}
SafeHandle IStorePal.SafeHandle { get; } = null;
}
}
}

View File

@@ -92,6 +92,8 @@ namespace Internal.Cryptography.Pal
{
PushHandle(certPal.Handle, publicCerts);
}
GC.KeepAlive(certPal); // ensure reader's safe handle isn't finalized while raw handle is in use
}
else
{
@@ -120,6 +122,8 @@ namespace Internal.Cryptography.Pal
{
PushHandle(cert.Handle, publicCerts);
}
GC.KeepAlive(cert); // ensure cert's safe handle isn't finalized while raw handle is in use
}
}
@@ -175,6 +179,8 @@ namespace Internal.Cryptography.Pal
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
GC.KeepAlive(cert); // ensure cert's safe handle isn't finalized while raw handle is in use
}
return Interop.Crypto.OpenSslEncode(

View File

@@ -295,6 +295,78 @@ namespace Internal.Cryptography.Pal
return new ECDsaOpenSsl(_privateKey);
}
private ICertificatePal CopyWithPrivateKey(SafeEvpPKeyHandle privateKey)
{
// This could be X509Duplicate for a full clone, but since OpenSSL certificates
// are functionally immutable (unlike Windows ones) an UpRef is sufficient.
SafeX509Handle certHandle = Interop.Crypto.X509UpRef(_cert);
OpenSslX509CertificateReader duplicate = new OpenSslX509CertificateReader(certHandle);
duplicate.SetPrivateKey(privateKey);
return duplicate;
}
public ICertificatePal CopyWithPrivateKey(DSA privateKey)
{
DSAOpenSsl typedKey = privateKey as DSAOpenSsl;
if (typedKey != null)
{
return CopyWithPrivateKey((SafeEvpPKeyHandle)typedKey.DuplicateKeyHandle());
}
DSAParameters dsaParameters = privateKey.ExportParameters(true);
using (PinAndClear.Track(dsaParameters.X))
using (typedKey = new DSAOpenSsl(dsaParameters))
{
return CopyWithPrivateKey((SafeEvpPKeyHandle)typedKey.DuplicateKeyHandle());
}
}
public ICertificatePal CopyWithPrivateKey(ECDsa privateKey)
{
ECDsaOpenSsl typedKey = privateKey as ECDsaOpenSsl;
if (typedKey != null)
{
return CopyWithPrivateKey((SafeEvpPKeyHandle)typedKey.DuplicateKeyHandle());
}
ECParameters ecParameters = privateKey.ExportParameters(true);
using (PinAndClear.Track(ecParameters.D))
using (typedKey = new ECDsaOpenSsl())
{
typedKey.ImportParameters(ecParameters);
return CopyWithPrivateKey((SafeEvpPKeyHandle)typedKey.DuplicateKeyHandle());
}
}
public ICertificatePal CopyWithPrivateKey(RSA privateKey)
{
RSAOpenSsl typedKey = privateKey as RSAOpenSsl;
if (typedKey != null)
{
return CopyWithPrivateKey((SafeEvpPKeyHandle)typedKey.DuplicateKeyHandle());
}
RSAParameters rsaParameters = privateKey.ExportParameters(true);
using (PinAndClear.Track(rsaParameters.D))
using (PinAndClear.Track(rsaParameters.P))
using (PinAndClear.Track(rsaParameters.Q))
using (PinAndClear.Track(rsaParameters.DP))
using (PinAndClear.Track(rsaParameters.DQ))
using (PinAndClear.Track(rsaParameters.InverseQ))
using (typedKey = new RSAOpenSsl(rsaParameters))
{
return CopyWithPrivateKey((SafeEvpPKeyHandle)typedKey.DuplicateKeyHandle());
}
}
public string GetNameInfo(X509NameType nameType, bool forIssuer)
{
using (SafeBioHandle bioHandle = Interop.Crypto.GetX509NameInfo(_cert, (int)nameType, forIssuer))

View File

@@ -37,7 +37,6 @@ namespace Internal.Cryptography.Pal
public static IChainPal BuildChain(
X509Certificate2 leaf,
HashSet<X509Certificate2> candidates,
HashSet<X509Certificate2> downloaded,
HashSet<X509Certificate2> systemTrusted,
OidCollection applicationPolicy,
OidCollection certificatePolicy,
@@ -57,9 +56,11 @@ namespace Internal.Cryptography.Pal
// (If you need to think of it as an X509Store, it's a volatile memory store)
using (SafeX509StoreHandle store = Interop.Crypto.X509StoreCreate())
using (SafeX509StoreCtxHandle storeCtx = Interop.Crypto.X509StoreCtxCreate())
using (SafeX509StackHandle extraCerts = Interop.Crypto.NewX509Stack())
{
Interop.Crypto.CheckValidOpenSslHandle(store);
Interop.Crypto.CheckValidOpenSslHandle(storeCtx);
Interop.Crypto.CheckValidOpenSslHandle(extraCerts);
bool lookupCrl = revocationMode != X509RevocationMode.NoCheck;
@@ -67,9 +68,15 @@ namespace Internal.Cryptography.Pal
{
OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)cert.Pal;
if (!Interop.Crypto.X509StoreAddCert(store, pal.SafeHandle))
using (SafeX509Handle handle = Interop.Crypto.X509UpRef(pal.SafeHandle))
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
if (!Interop.Crypto.PushX509StackField(extraCerts, handle))
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
// Ownership was transferred to the cert stack.
handle.SetHandleAsInvalid();
}
if (lookupCrl)
@@ -95,9 +102,19 @@ namespace Internal.Cryptography.Pal
}
}
foreach (X509Certificate2 trustedCert in systemTrusted)
{
OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)trustedCert.Pal;
if (!Interop.Crypto.X509StoreAddCert(store, pal.SafeHandle))
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
}
SafeX509Handle leafHandle = ((OpenSslX509CertificateReader)leaf.Pal).SafeHandle;
if (!Interop.Crypto.X509StoreCtxInit(storeCtx, store, leafHandle))
if (!Interop.Crypto.X509StoreCtxInit(storeCtx, store, leafHandle, extraCerts))
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
@@ -144,22 +161,6 @@ namespace Internal.Cryptography.Pal
// Duplicate the certificate handle
X509Certificate2 elementCert = new X509Certificate2(elementCertPtr);
// If the last cert is self signed then it's the root cert, do any extra checks.
if (i == maybeRootDepth && IsSelfSigned(elementCert))
{
// If the root certificate was downloaded or the system
// doesn't trust it, it's untrusted.
if (downloaded.Contains(elementCert) ||
!systemTrusted.Contains(elementCert))
{
AddElementStatus(
Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_UNTRUSTED,
status,
overallStatus);
}
}
elements[i] = new X509ChainElement(elementCert, status.ToArray(), "");
}
}
@@ -416,8 +417,6 @@ namespace Internal.Cryptography.Pal
extraStore,
userIntermediateCerts,
systemIntermediateCerts,
userRootCerts,
systemRootCerts,
};
while (toProcess.Count > 0)
@@ -629,7 +628,7 @@ namespace Internal.Cryptography.Pal
internal int VerifyCallback(int ok, IntPtr ctx)
{
if (ok < 0)
if (ok != 0)
{
return ok;
}

View File

@@ -10,6 +10,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace Internal.Cryptography.Pal
{
@@ -136,14 +137,23 @@ namespace Internal.Cryptography.Pal
public static IStorePal FromSystemStore(string storeName, StoreLocation storeLocation, OpenFlags openFlags)
{
if (storeLocation != StoreLocation.LocalMachine)
if (storeLocation == StoreLocation.CurrentUser)
{
if (X509Store.DisallowedStoreName.Equals(storeName, StringComparison.OrdinalIgnoreCase))
{
return new DirectoryBasedStoreProvider.UnsupportedDisallowedStore(openFlags);
}
return new DirectoryBasedStoreProvider(storeName, openFlags);
}
Debug.Assert(storeLocation == StoreLocation.LocalMachine);
if ((openFlags & OpenFlags.ReadWrite) == OpenFlags.ReadWrite)
{
throw new PlatformNotSupportedException(SR.Cryptography_Unix_X509_MachineStoresReadOnly);
throw new CryptographicException(
SR.Cryptography_Unix_X509_MachineStoresReadOnly,
new PlatformNotSupportedException(SR.Cryptography_Unix_X509_MachineStoresReadOnly));
}
// The static store approach here is making an optimization based on not
@@ -160,17 +170,19 @@ namespace Internal.Cryptography.Pal
}
}
if (StringComparer.Ordinal.Equals("Root", storeName))
if (X509Store.RootStoreName.Equals(storeName, StringComparison.OrdinalIgnoreCase))
{
return s_machineRootStore;
}
if (StringComparer.Ordinal.Equals("CA", storeName))
if (X509Store.IntermediateCAStoreName.Equals(storeName, StringComparison.OrdinalIgnoreCase))
{
return s_machineIntermediateStore;
}
throw new PlatformNotSupportedException(SR.Cryptography_Unix_X509_MachineStoresRootOnly);
throw new CryptographicException(
SR.Cryptography_Unix_X509_MachineStoresRootOnly,
new PlatformNotSupportedException(SR.Cryptography_Unix_X509_MachineStoresRootOnly));
}
private static ILoaderPal SingleCertToLoaderPal(ICertificatePal singleCert)

View File

@@ -1,71 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// .NET Native (UWP) does not have access to the CspParameters type because it is in a non-UWP-compatible
// assembly. So these type definitions allow the code to continue to use the same data transport structure
// that it has for quite a while.
#if uap
using System;
namespace Internal.Cryptography.Pal
{
internal sealed partial class CertificatePal : IDisposable, ICertificatePal
{
[Flags]
private enum CspProviderFlags
{
// Note: UWP doesn't use any flags other than these, so they have been omitted.
NoFlags = 0x0000,
UseMachineKeyStore = 0x0001,
}
private sealed class CspParameters
{
public int ProviderType;
public string ProviderName;
public string KeyContainerName;
public int KeyNumber;
private int _flags;
/// <summary>
/// Flag property
/// </summary>
public CspProviderFlags Flags
{
get { return (CspProviderFlags)_flags; }
set
{
const int allFlags = 0x00FF; // this should change if more values are added to CspProviderFlags
int flags = (int)value;
if ((flags & ~allFlags) != 0)
{
throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, nameof(value)));
}
_flags = flags;
}
}
public CspParameters() : this(-1, null, null)
{
}
private CspParameters(int dwTypeIn, string strProviderNameIn, string strContainerNameIn) :
this(dwTypeIn, strProviderNameIn, strContainerNameIn, CspProviderFlags.NoFlags)
{
}
private CspParameters(int providerType, string providerName, string keyContainerName, CspProviderFlags flags)
{
ProviderType = providerType;
ProviderName = providerName;
KeyContainerName = keyContainerName;
KeyNumber = -1;
Flags = flags;
}
}
}
}
#endif // #if uap

View File

@@ -4,8 +4,10 @@
using System;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Win32.SafeHandles;
using Internal.Cryptography.Pal.Native;
@@ -80,6 +82,112 @@ namespace Internal.Cryptography.Pal
);
}
public ICertificatePal CopyWithPrivateKey(DSA dsa)
{
DSACng dsaCng = dsa as DSACng;
ICertificatePal clone = null;
if (dsaCng != null)
{
clone = CopyWithPersistedCngKey(dsaCng.Key);
if (clone != null)
{
return clone;
}
}
DSACryptoServiceProvider dsaCsp = dsa as DSACryptoServiceProvider;
if (dsaCsp != null)
{
clone = CopyWithPersistedCapiKey(dsaCsp.CspKeyContainerInfo);
if (clone != null)
{
return clone;
}
}
DSAParameters privateParameters = dsa.ExportParameters(true);
using (PinAndClear.Track(privateParameters.X))
using (DSACng clonedKey = new DSACng())
{
clonedKey.ImportParameters(privateParameters);
return CopyWithEphemeralKey(clonedKey.Key);
}
}
public ICertificatePal CopyWithPrivateKey(ECDsa ecdsa)
{
ECDsaCng ecdsaCng = ecdsa as ECDsaCng;
if (ecdsaCng != null)
{
ICertificatePal clone = CopyWithPersistedCngKey(ecdsaCng.Key);
if (clone != null)
{
return clone;
}
}
ECParameters privateParameters = ecdsa.ExportParameters(true);
using (PinAndClear.Track(privateParameters.D))
using (ECDsaCng clonedKey = new ECDsaCng())
{
clonedKey.ImportParameters(privateParameters);
return CopyWithEphemeralKey(clonedKey.Key);
}
}
public ICertificatePal CopyWithPrivateKey(RSA rsa)
{
RSACng rsaCng = rsa as RSACng;
ICertificatePal clone = null;
if (rsaCng != null)
{
clone = CopyWithPersistedCngKey(rsaCng.Key);
if (clone != null)
{
return clone;
}
}
RSACryptoServiceProvider rsaCsp = rsa as RSACryptoServiceProvider;
if (rsaCsp != null)
{
clone = CopyWithPersistedCapiKey(rsaCsp.CspKeyContainerInfo);
if (clone != null)
{
return clone;
}
}
RSAParameters privateParameters = rsa.ExportParameters(true);
using (PinAndClear.Track(privateParameters.D))
using (PinAndClear.Track(privateParameters.P))
using (PinAndClear.Track(privateParameters.Q))
using (PinAndClear.Track(privateParameters.DP))
using (PinAndClear.Track(privateParameters.DQ))
using (PinAndClear.Track(privateParameters.InverseQ))
using (RSACng clonedKey = new RSACng())
{
clonedKey.ImportParameters(privateParameters);
return CopyWithEphemeralKey(clonedKey.Key);
}
}
private T GetPrivateKey<T>(Func<CspParameters, T> createCsp, Func<CngKey, T> createCng) where T : AsymmetricAlgorithm
{
CngKeyHandleOpenOptions cngHandleOptions;
@@ -239,5 +347,259 @@ namespace Internal.Cryptography.Pal
}
}
}
private unsafe ICertificatePal CopyWithPersistedCngKey(CngKey cngKey)
{
if (string.IsNullOrEmpty(cngKey.KeyName))
{
return null;
}
// Make a new pal from bytes.
CertificatePal pal = (CertificatePal)FromBlob(RawData, SafePasswordHandle.InvalidHandle, X509KeyStorageFlags.PersistKeySet);
CngProvider provider = cngKey.Provider;
string keyName = cngKey.KeyName;
bool machineKey = cngKey.IsMachineKey;
// CAPI RSA_SIGN keys won't open correctly under CNG without the key number being specified, so
// check to see if we can figure out what key number it needs to re-open.
int keySpec = GuessKeySpec(provider, keyName, machineKey, cngKey.AlgorithmGroup);
CRYPT_KEY_PROV_INFO keyProvInfo = new CRYPT_KEY_PROV_INFO();
fixed (char* keyNamePtr = cngKey.KeyName)
fixed (char* provNamePtr = cngKey.Provider.Provider)
{
keyProvInfo.pwszContainerName = keyNamePtr;
keyProvInfo.pwszProvName = provNamePtr;
keyProvInfo.dwFlags = machineKey ? CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET : 0;
keyProvInfo.dwKeySpec = keySpec;
if (!Interop.crypt32.CertSetCertificateContextProperty(
pal._certContext,
CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID,
CertSetPropertyFlags.None,
&keyProvInfo))
{
pal.Dispose();
throw Marshal.GetLastWin32Error().ToCryptographicException();
}
}
return pal;
}
private static int GuessKeySpec(
CngProvider provider,
string keyName,
bool machineKey,
CngAlgorithmGroup algorithmGroup)
{
if (provider == CngProvider.MicrosoftSoftwareKeyStorageProvider ||
provider == CngProvider.MicrosoftSmartCardKeyStorageProvider)
{
// Well-known CNG providers, keySpec is 0.
return 0;
}
try
{
CngKeyOpenOptions options = machineKey ? CngKeyOpenOptions.MachineKey : CngKeyOpenOptions.None;
using (CngKey.Open(keyName, provider, options))
{
// It opened with keySpec 0, so use keySpec 0.
return 0;
}
}
catch (CryptographicException)
{
// While NTE_BAD_KEYSET is what we generally expect here for RSA, on Windows 7
// PROV_DSS produces NTE_BAD_PROV_TYPE, and PROV_DSS_DH produces NTE_NO_KEY.
//
// So we'll just try the CAPI fallback for any error code, and see what happens.
CspParameters cspParameters = new CspParameters
{
ProviderName = provider.Provider,
KeyContainerName = keyName,
Flags = CspProviderFlags.UseExistingKey,
KeyNumber = (int)KeyNumber.Signature,
};
if (machineKey)
{
cspParameters.Flags |= CspProviderFlags.UseMachineKeyStore;
}
int keySpec;
if (TryGuessKeySpec(cspParameters, algorithmGroup, out keySpec))
{
return keySpec;
}
throw;
}
}
private static bool TryGuessKeySpec(
CspParameters cspParameters,
CngAlgorithmGroup algorithmGroup,
out int keySpec)
{
if (algorithmGroup == CngAlgorithmGroup.Rsa)
{
return TryGuessRsaKeySpec(cspParameters, out keySpec);
}
if (algorithmGroup == CngAlgorithmGroup.Dsa)
{
return TryGuessDsaKeySpec(cspParameters, out keySpec);
}
keySpec = 0;
return false;
}
private static bool TryGuessRsaKeySpec(CspParameters cspParameters, out int keySpec)
{
// Try the AT_SIGNATURE spot in each of the 4 RSA provider type values,
// ideally one of them will work.
const int PROV_RSA_FULL = 1;
const int PROV_RSA_SIG = 2;
const int PROV_RSA_SCHANNEL = 12;
const int PROV_RSA_AES = 24;
// These are ordered in terms of perceived likeliness, given that the key
// is AT_SIGNATURE.
int[] provTypes =
{
PROV_RSA_FULL,
PROV_RSA_AES,
PROV_RSA_SCHANNEL,
// Nothing should be PROV_RSA_SIG, but if everything else has failed,
// just try this last thing.
PROV_RSA_SIG,
};
foreach (int provType in provTypes)
{
cspParameters.ProviderType = provType;
try
{
using (new RSACryptoServiceProvider(cspParameters))
{
{
keySpec = cspParameters.KeyNumber;
return true;
}
}
}
catch (CryptographicException)
{
}
}
Debug.Fail("RSA key did not open with KeyNumber 0 or AT_SIGNATURE");
keySpec = 0;
return false;
}
private static bool TryGuessDsaKeySpec(CspParameters cspParameters, out int keySpec)
{
const int PROV_DSS = 3;
const int PROV_DSS_DH = 13;
int[] provTypes =
{
PROV_DSS_DH,
PROV_DSS,
};
foreach (int provType in provTypes)
{
cspParameters.ProviderType = provType;
try
{
using (new DSACryptoServiceProvider(cspParameters))
{
{
keySpec = cspParameters.KeyNumber;
return true;
}
}
}
catch (CryptographicException)
{
}
}
Debug.Fail("DSA key did not open with KeyNumber 0 or AT_SIGNATURE");
keySpec = 0;
return false;
}
private unsafe ICertificatePal CopyWithPersistedCapiKey(CspKeyContainerInfo keyContainerInfo)
{
if (string.IsNullOrEmpty(keyContainerInfo.KeyContainerName))
{
return null;
}
// Make a new pal from bytes.
CertificatePal pal = (CertificatePal)FromBlob(RawData, SafePasswordHandle.InvalidHandle, X509KeyStorageFlags.PersistKeySet);
CRYPT_KEY_PROV_INFO keyProvInfo = new CRYPT_KEY_PROV_INFO();
fixed (char* keyName = keyContainerInfo.KeyContainerName)
fixed (char* provName = keyContainerInfo.ProviderName)
{
keyProvInfo.pwszContainerName = keyName;
keyProvInfo.pwszProvName = provName;
keyProvInfo.dwFlags = keyContainerInfo.MachineKeyStore ? CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET : 0;
keyProvInfo.dwProvType = keyContainerInfo.ProviderType;
keyProvInfo.dwKeySpec = (int)keyContainerInfo.KeyNumber;
if (!Interop.crypt32.CertSetCertificateContextProperty(
pal._certContext,
CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID,
CertSetPropertyFlags.None,
&keyProvInfo))
{
pal.Dispose();
throw Marshal.GetLastWin32Error().ToCryptographicException();
}
}
return pal;
}
private ICertificatePal CopyWithEphemeralKey(CngKey cngKey)
{
Debug.Assert(string.IsNullOrEmpty(cngKey.KeyName));
SafeNCryptKeyHandle handle = cngKey.Handle;
// Make a new pal from bytes.
CertificatePal pal = (CertificatePal)FromBlob(RawData, SafePasswordHandle.InvalidHandle, X509KeyStorageFlags.PersistKeySet);
if (!Interop.crypt32.CertSetCertificateContextProperty(
pal._certContext,
CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID,
CertSetPropertyFlags.CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
handle))
{
pal.Dispose();
throw Marshal.GetLastWin32Error().ToCryptographicException();
}
// The value was transferred to the certificate.
handle.SetHandleAsInvalid();
return pal;
}
}
}

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