/mcs/class/referencesource/System/security/system/security/cryptography/x509/x509certificate2.cs
C# | 1183 lines | 945 code | 161 blank | 77 comment | 136 complexity | 4d275f4bd2a963b13efc0cb91280314c MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
- // ==++==
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // ==--==
- //
- // X509Certificate2.cs
- //
- // 09/22/2002
- //
- namespace System.Security.Cryptography.X509Certificates {
- using System;
- using System.Diagnostics;
- using System.Diagnostics.CodeAnalysis;
- using System.IO;
- using System.Text;
- using System.Runtime.InteropServices;
- using System.Runtime.InteropServices.ComTypes;
- using System.Runtime.Serialization;
- using System.Security.Cryptography;
- using System.Security.Permissions;
- using System.Runtime.Versioning;
- using _FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
- public enum X509NameType {
- SimpleName = 0,
- EmailName,
- UpnName,
- DnsName,
- DnsFromAlternativeName,
- UrlName
- }
- public enum X509IncludeOption {
- None = 0,
- ExcludeRoot,
- EndCertOnly,
- WholeChain
- }
- public sealed class PublicKey {
- private AsnEncodedData m_encodedKeyValue;
- private AsnEncodedData m_encodedParameters;
- private Oid m_oid;
- private uint m_aiPubKey = 0;
- private byte[] m_cspBlobData = null;
- private AsymmetricAlgorithm m_key = null;
- private PublicKey() {}
- public PublicKey (Oid oid, AsnEncodedData parameters, AsnEncodedData keyValue) {
- m_oid = new Oid(oid);
- m_encodedParameters = new AsnEncodedData(parameters);
- m_encodedKeyValue = new AsnEncodedData(keyValue);
- }
- internal PublicKey (PublicKey publicKey) {
- m_oid = new Oid(publicKey.m_oid);
- m_encodedParameters = new AsnEncodedData(publicKey.m_encodedParameters);
- m_encodedKeyValue = new AsnEncodedData(publicKey.m_encodedKeyValue);
- }
- internal uint AlgorithmId {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_aiPubKey == 0)
- m_aiPubKey = X509Utils.OidToAlgId(m_oid.Value);
- return m_aiPubKey;
- }
- }
- private byte[] CspBlobData {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_cspBlobData == null)
- DecodePublicKeyObject(AlgorithmId, m_encodedKeyValue.RawData, m_encodedParameters.RawData, out m_cspBlobData);
- return m_cspBlobData;
- }
- }
- public AsymmetricAlgorithm Key {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_key == null) {
- switch (AlgorithmId) {
- case CAPI.CALG_RSA_KEYX:
- case CAPI.CALG_RSA_SIGN:
- RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
- rsa.ImportCspBlob(CspBlobData);
- m_key = rsa;
- break;
- #if !FEATURE_CORESYSTEM
- case CAPI.CALG_DSS_SIGN:
- DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
- dsa.ImportCspBlob(CspBlobData);
- m_key = dsa;
- break;
- #endif
- default:
- throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));
- }
- }
- return m_key;
- }
- }
- public Oid Oid {
- get { return new Oid(m_oid); }
- }
- public AsnEncodedData EncodedKeyValue {
- get { return m_encodedKeyValue; }
- }
- public AsnEncodedData EncodedParameters {
- get { return m_encodedParameters; }
- }
- //
- // private static methods.
- //
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- private static void DecodePublicKeyObject(uint aiPubKey, byte[] encodedKeyValue, byte[] encodedParameters, out byte[] decodedData) {
- // Initialize the out parameter
- decodedData = null;
- IntPtr pszStructType = IntPtr.Zero;
- switch (aiPubKey) {
- case CAPI.CALG_DSS_SIGN:
- pszStructType = new IntPtr(CAPI.X509_DSS_PUBLICKEY);
- break;
- case CAPI.CALG_RSA_SIGN:
- case CAPI.CALG_RSA_KEYX:
- pszStructType = new IntPtr(CAPI.RSA_CSP_PUBLICKEYBLOB);
- break;
- case CAPI.CALG_DH_SF:
- case CAPI.CALG_DH_EPHEM:
- // We don't support DH for now
- throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));
- default:
- // We should never get here
- Debug.Assert(false);
- throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));
- }
- SafeLocalAllocHandle decodedKeyValue = null;
- uint cbDecodedKeyValue = 0;
- bool result = CAPI.DecodeObject(pszStructType,
- encodedKeyValue,
- out decodedKeyValue,
- out cbDecodedKeyValue);
- if (!result)
- throw new CryptographicException(Marshal.GetLastWin32Error());
- if ((uint) pszStructType == CAPI.RSA_CSP_PUBLICKEYBLOB) {
- decodedData = new byte[cbDecodedKeyValue];
- Marshal.Copy(decodedKeyValue.DangerousGetHandle(), decodedData, 0, decodedData.Length);
- } else if ((uint) pszStructType == CAPI.X509_DSS_PUBLICKEY) {
- // We need to decode the parameters as well
- SafeLocalAllocHandle decodedParameters = null;
- uint cbDecodedParameters = 0;
- result = CAPI.DecodeObject(new IntPtr(CAPI.X509_DSS_PARAMETERS),
- encodedParameters,
- out decodedParameters,
- out cbDecodedParameters);
- if (!result)
- throw new CryptographicException(Marshal.GetLastWin32Error());
- decodedData = ConstructDSSPubKeyCspBlob(decodedKeyValue, decodedParameters);
- decodedParameters.Dispose();
- }
- decodedKeyValue.Dispose();
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- private static byte[] ConstructDSSPubKeyCspBlob (SafeLocalAllocHandle decodedKeyValue,
- SafeLocalAllocHandle decodedParameters) {
- // The CAPI DSS public key representation consists of the following sequence:
- // - PUBLICKEYSTRUC
- // - DSSPUBKEY
- // - rgbP[cbKey]
- // - rgbQ[20]
- // - rgbG[cbKey]
- // - rgbY[cbKey]
- // - DSSSEED
- CAPI.CRYPTOAPI_BLOB pDssPubKey = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decodedKeyValue.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
- CAPI.CERT_DSS_PARAMETERS pDssParameters = (CAPI.CERT_DSS_PARAMETERS) Marshal.PtrToStructure(decodedParameters.DangerousGetHandle(), typeof(CAPI.CERT_DSS_PARAMETERS));
- uint cbKey = pDssParameters.p.cbData;
- if (cbKey == 0)
- throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);
- const uint DSS_Q_LEN = 20;
- uint cbKeyBlob = 8 /* sizeof(CAPI.BLOBHEADER) */ + 8 /* sizeof(CAPI.DSSPUBKEY) */ +
- cbKey + DSS_Q_LEN + cbKey + cbKey + 24 /* sizeof(CAPI.DSSSEED) */;
- MemoryStream keyBlob = new MemoryStream((int) cbKeyBlob);
- BinaryWriter bw = new BinaryWriter(keyBlob);
- // PUBLICKEYSTRUC
- bw.Write(CAPI.PUBLICKEYBLOB); // pPubKeyStruc->bType = PUBLICKEYBLOB
- bw.Write(CAPI.CUR_BLOB_VERSION); // pPubKeyStruc->bVersion = CUR_BLOB_VERSION
- bw.Write((short) 0); // pPubKeyStruc->reserved = 0;
- bw.Write(CAPI.CALG_DSS_SIGN); // pPubKeyStruc->aiKeyAlg = CALG_DSS_SIGN;
- // DSSPUBKEY
- bw.Write(CAPI.DSS_MAGIC); // pCspPubKey->magic = DSS_MAGIC; We are constructing a DSS1 Csp blob.
- bw.Write(cbKey * 8); // pCspPubKey->bitlen = cbKey * 8;
- // rgbP[cbKey]
- byte[] p = new byte[pDssParameters.p.cbData];
- Marshal.Copy(pDssParameters.p.pbData, p, 0, p.Length);
- bw.Write(p);
- // rgbQ[20]
- uint cb = pDssParameters.q.cbData;
- if (cb == 0 || cb > DSS_Q_LEN)
- throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);
- byte[] q = new byte[pDssParameters.q.cbData];
- Marshal.Copy(pDssParameters.q.pbData, q, 0, q.Length);
- bw.Write(q);
- if (DSS_Q_LEN > cb)
- bw.Write(new byte[DSS_Q_LEN - cb]);
- // rgbG[cbKey]
- cb = pDssParameters.g.cbData;
- if (cb == 0 || cb > cbKey)
- throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);
- byte[] g = new byte[pDssParameters.g.cbData];
- Marshal.Copy(pDssParameters.g.pbData, g, 0, g.Length);
- bw.Write(g);
- if (cbKey > cb)
- bw.Write(new byte[cbKey - cb]);
- // rgbY[cbKey]
- cb = pDssPubKey.cbData;
- if (cb == 0 || cb > cbKey)
- throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);
- byte[] y = new byte[pDssPubKey.cbData];
- Marshal.Copy(pDssPubKey.pbData, y, 0, y.Length);
- bw.Write(y);
- if (cbKey > cb)
- bw.Write(new byte[cbKey - cb]);
- // DSSSEED: set counter to 0xFFFFFFFF to indicate not available
- bw.Write(0xFFFFFFFF);
- bw.Write(new byte[20]);
- return keyBlob.ToArray();
- }
- }
- #if !FEATURE_CORESYSTEM
- [Serializable]
- #endif
- public class X509Certificate2 : X509Certificate {
- private int m_version;
- private DateTime m_notBefore;
- private DateTime m_notAfter;
- private AsymmetricAlgorithm m_privateKey;
- private PublicKey m_publicKey;
- private X509ExtensionCollection m_extensions;
- private Oid m_signatureAlgorithm;
- private X500DistinguishedName m_subjectName;
- private X500DistinguishedName m_issuerName;
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private SafeCertContextHandle m_safeCertContext = SafeCertContextHandle.InvalidHandle;
-
- private static int s_publicKeyOffset;
- //
- // public constructors
- //
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public X509Certificate2 () : base() {}
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public X509Certificate2 (byte[] rawData) : base (rawData) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public X509Certificate2 (byte[] rawData, string password) : base (rawData, password) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if !FEATURE_CORESYSTEM
- public X509Certificate2 (byte[] rawData, SecureString password) : base (rawData, password) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #endif
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public X509Certificate2 (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if !FEATURE_CORESYSTEM
- public X509Certificate2 (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #endif
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- [ResourceExposure(ResourceScope.Machine)]
- #if !FEATURE_CORESYSTEM
- [ResourceConsumption(ResourceScope.Machine)]
- #endif
- public X509Certificate2 (string fileName) : base (fileName) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- [ResourceExposure(ResourceScope.Machine)]
- #if !FEATURE_CORESYSTEM
- [ResourceConsumption(ResourceScope.Machine)]
- #endif
- public X509Certificate2 (string fileName, string password) : base (fileName, password) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if !FEATURE_CORESYSTEM
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- public X509Certificate2 (string fileName, SecureString password) : base (fileName, password) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #endif
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- [ResourceExposure(ResourceScope.Machine)]
- #if !FEATURE_CORESYSTEM
- [ResourceConsumption(ResourceScope.Machine)]
- #endif
- public X509Certificate2 (string fileName, string password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if !FEATURE_CORESYSTEM
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- public X509Certificate2 (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #endif
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- // Package protected constructor for creating a certificate from a PCCERT_CONTEXT
- [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
- public X509Certificate2 (IntPtr handle) : base (handle) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public X509Certificate2 (X509Certificate certificate) : base(certificate) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #if !FEATURE_CORESYSTEM
- [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- protected X509Certificate2(SerializationInfo info, StreamingContext context) : base(info, context) {
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- #endif
- public override string ToString() {
- return base.ToString(true);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public override string ToString(bool verbose) {
- if (verbose == false || m_safeCertContext.IsInvalid)
- return ToString();
- StringBuilder sb = new StringBuilder();
- string newLine = Environment.NewLine;
- string newLine2 = newLine + newLine;
- string newLinesp2 = newLine + " ";
- // Version
- sb.Append("[Version]");
- sb.Append(newLinesp2);
- sb.Append("V" + this.Version);
- // Subject
- sb.Append(newLine2);
- sb.Append("[Subject]");
- sb.Append(newLinesp2);
- sb.Append(this.SubjectName.Name);
- string simpleName = GetNameInfo(X509NameType.SimpleName, false);
- if (simpleName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("Simple Name: ");
- sb.Append(simpleName);
- }
- string emailName = GetNameInfo(X509NameType.EmailName, false);
- if (emailName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("Email Name: ");
- sb.Append(emailName);
- }
- string upnName = GetNameInfo(X509NameType.UpnName, false);
- if (upnName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("UPN Name: ");
- sb.Append(upnName);
- }
- string dnsName = GetNameInfo(X509NameType.DnsName, false);
- if (dnsName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("DNS Name: ");
- sb.Append(dnsName);
- }
- // Issuer
- sb.Append(newLine2);
- sb.Append("[Issuer]");
- sb.Append(newLinesp2);
- sb.Append(this.IssuerName.Name);
- simpleName = GetNameInfo(X509NameType.SimpleName, true);
- if (simpleName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("Simple Name: ");
- sb.Append(simpleName);
- }
- emailName = GetNameInfo(X509NameType.EmailName, true);
- if (emailName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("Email Name: ");
- sb.Append(emailName);
- }
- upnName = GetNameInfo(X509NameType.UpnName, true);
- if (upnName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("UPN Name: ");
- sb.Append(upnName);
- }
- dnsName = GetNameInfo(X509NameType.DnsName, true);
- if (dnsName.Length > 0) {
- sb.Append(newLinesp2);
- sb.Append("DNS Name: ");
- sb.Append(dnsName);
- }
- // Serial Number
- sb.Append(newLine2);
- sb.Append("[Serial Number]");
- sb.Append(newLinesp2);
- sb.Append(this.SerialNumber);
- // NotBefore
- sb.Append(newLine2);
- sb.Append("[Not Before]");
- sb.Append(newLinesp2);
- sb.Append(FormatDate(this.NotBefore));
- // NotAfter
- sb.Append(newLine2);
- sb.Append("[Not After]");
- sb.Append(newLinesp2);
- sb.Append(FormatDate(this.NotAfter));
- // Thumbprint
- sb.Append(newLine2);
- sb.Append("[Thumbprint]");
- sb.Append(newLinesp2);
- sb.Append(this.Thumbprint);
- // Signature Algorithm
- sb.Append(newLine2);
- sb.Append("[Signature Algorithm]");
- sb.Append(newLinesp2);
- sb.Append(this.SignatureAlgorithm.FriendlyName + "(" + this.SignatureAlgorithm.Value + ")");
- // Public Key
- sb.Append(newLine2);
- sb.Append("[Public Key]");
- // It could throw if it's some user-defined CryptoServiceProvider
- try {
- PublicKey pubKey = this.PublicKey;
- string temp = pubKey.Oid.FriendlyName;
- sb.Append(newLinesp2);
- sb.Append("Algorithm: ");
- sb.Append(temp);
- // So far, we only support RSACryptoServiceProvider & DSACryptoServiceProvider Keys
- try {
- temp = pubKey.Key.KeySize.ToString();
- sb.Append(newLinesp2);
- sb.Append("Length: ");
- sb.Append(temp);
- }
- catch (NotSupportedException) {
- }
- temp = pubKey.EncodedKeyValue.Format(true);
- sb.Append(newLinesp2);
- sb.Append("Key Blob: ");
- sb.Append(temp);
- temp = pubKey.EncodedParameters.Format(true);
- sb.Append(newLinesp2);
- sb.Append("Parameters: ");
- sb.Append(temp);
- }
- catch (CryptographicException) {
- }
- // Private key
- AppendPrivateKeyInfo(sb);
- // Extensions
- X509ExtensionCollection extensions = this.Extensions;
- if (extensions.Count > 0) {
- sb.Append(newLine2);
- sb.Append("[Extensions]");
- string temp;
- foreach (X509Extension extension in extensions) {
- try {
- temp = extension.Oid.FriendlyName;
- sb.Append(newLine);
- sb.Append("* " + temp);
- sb.Append("(" + extension.Oid.Value + "):");
- temp = extension.Format(true);
- sb.Append(newLinesp2);
- sb.Append(temp);
- }
- catch (CryptographicException) {
- }
- }
- }
- sb.Append(newLine);
- return sb.ToString();
- }
- public bool Archived {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- uint cbData = 0;
- return CAPI.CertGetCertificateContextProperty(m_safeCertContext,
- CAPI.CERT_ARCHIVED_PROP_ID,
- SafeLocalAllocHandle.InvalidHandle,
- ref cbData);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- set {
- SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
- if (value == true)
- ptr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))));
- if (!CAPI.CertSetCertificateContextProperty(m_safeCertContext,
- CAPI.CERT_ARCHIVED_PROP_ID,
- 0,
- ptr))
- throw new CryptographicException(Marshal.GetLastWin32Error());
- ptr.Dispose();
- }
- }
- public X509ExtensionCollection Extensions {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_extensions == null)
- m_extensions = new X509ExtensionCollection(m_safeCertContext);
- return m_extensions;
- }
- }
- public string FriendlyName {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
- uint cbData = 0;
- if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext,
- CAPI.CERT_FRIENDLY_NAME_PROP_ID,
- ptr,
- ref cbData))
- return String.Empty;
- ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData));
- if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext,
- CAPI.CERT_FRIENDLY_NAME_PROP_ID,
- ptr,
- ref cbData))
- return String.Empty;
- string friendlyName = Marshal.PtrToStringUni(ptr.DangerousGetHandle());
- ptr.Dispose();
- return friendlyName;
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- set {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (value == null)
- value = String.Empty;
- SetFriendlyNameExtendedProperty(m_safeCertContext, value);
- }
- }
- public X500DistinguishedName IssuerName {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_issuerName == null) {
- unsafe {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- m_issuerName = new X500DistinguishedName(pCertInfo.Issuer);
- }
- }
- return m_issuerName;
- }
- }
- public DateTime NotAfter {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_notAfter == DateTime.MinValue) {
- unsafe {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- long dt = (((long)(uint)pCertInfo.NotAfter.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotAfter.dwLowDateTime);
- m_notAfter = DateTime.FromFileTime(dt);
- }
- }
- return m_notAfter;
- }
- }
- public DateTime NotBefore {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_notBefore == DateTime.MinValue) {
- unsafe {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- long dt = (((long)(uint)pCertInfo.NotBefore.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotBefore.dwLowDateTime);
- m_notBefore = DateTime.FromFileTime(dt);
- }
- }
- return m_notBefore;
- }
- }
- public bool HasPrivateKey {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- uint cbData = 0;
- return CAPI.CertGetCertificateContextProperty(m_safeCertContext,
- CAPI.CERT_KEY_PROV_INFO_PROP_ID,
- SafeLocalAllocHandle.InvalidHandle,
- ref cbData);
- }
- }
- public AsymmetricAlgorithm PrivateKey {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (!this.HasPrivateKey)
- return null;
- if (m_privateKey == null) {
- CspParameters parameters = new CspParameters();
- if (!GetPrivateKeyInfo(m_safeCertContext, ref parameters))
- return null;
- // We never want to stomp over certificate private keys.
- parameters.Flags |= CspProviderFlags.UseExistingKey;
- switch (this.PublicKey.AlgorithmId) {
- case CAPI.CALG_RSA_KEYX:
- case CAPI.CALG_RSA_SIGN:
- m_privateKey = new RSACryptoServiceProvider(parameters);
- break;
- #if !FEATURE_CORESYSTEM
- case CAPI.CALG_DSS_SIGN:
- m_privateKey = new DSACryptoServiceProvider(parameters);
- break;
- #endif
- default:
- throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));
- }
- }
- return m_privateKey;
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety")]
- set {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- // we do not support keys in non-CAPI storage for now.
- ICspAsymmetricAlgorithm asymmetricAlgorithm = value as ICspAsymmetricAlgorithm;
- if (value != null && asymmetricAlgorithm == null)
- throw new NotSupportedException(SR.GetString(SR.NotSupported_InvalidKeyImpl));
- // A null value can be passed in to remove the link to the private key from the certificate.
- if (asymmetricAlgorithm != null) {
- if (asymmetricAlgorithm.CspKeyContainerInfo == null)
- throw new ArgumentException("CspKeyContainerInfo");
-
- // check that the public key in the certificate corresponds to the private key passed in.
- //
- // note that it should be legal to set a key which matches in every aspect but the usage
- // i.e. to use a CALG_RSA_KEYX private key to match a CALG_RSA_SIGN public key. A
- // PUBLICKEYBLOB is defined as:
- //
- // BLOBHEADER publickeystruc
- // RSAPUBKEY rsapubkey
- // BYTE modulus[rsapubkey.bitlen/8]
- //
- // To allow keys which differ by key usage only, we skip over the BLOBHEADER of the key,
- // and start comparing bytes at the RSAPUBKEY structure.
- if(s_publicKeyOffset == 0)
- s_publicKeyOffset = Marshal.SizeOf(typeof(CAPIBase.BLOBHEADER));
-
- ICspAsymmetricAlgorithm publicKey = this.PublicKey.Key as ICspAsymmetricAlgorithm;
- byte[] array1 = publicKey.ExportCspBlob(false);
- byte[] array2 = asymmetricAlgorithm.ExportCspBlob(false);
- if (array1 == null || array2 == null || array1.Length != array2.Length || array1.Length <= s_publicKeyOffset)
- throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch));
- for (int index = s_publicKeyOffset; index < array1.Length; index++) {
- if (array1[index] != array2[index])
- throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch));
- }
- }
- // Establish the link between the certificate and the key container.
- SetPrivateKeyProperty(m_safeCertContext, asymmetricAlgorithm);
- m_privateKey = value;
- }
- }
- public PublicKey PublicKey {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_publicKey == null) {
- string friendlyName = this.GetKeyAlgorithm();
- byte[] parameters = this.GetKeyAlgorithmParameters();
- byte[] keyValue = this.GetPublicKey();
- Oid oid = new Oid(friendlyName, OidGroup.PublicKeyAlgorithm, true);
- m_publicKey = new PublicKey(oid, new AsnEncodedData(oid, parameters), new AsnEncodedData(oid, keyValue));
- }
- return m_publicKey;
- }
- }
- public byte[] RawData {
- get {
- return GetRawCertData();
- }
- }
- public string SerialNumber {
- get {
- return GetSerialNumberString();
- }
- }
- public X500DistinguishedName SubjectName {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_subjectName == null) {
- unsafe {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- m_subjectName = new X500DistinguishedName(pCertInfo.Subject);
- }
- }
- return m_subjectName;
- }
- }
- public Oid SignatureAlgorithm {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_signatureAlgorithm == null)
- m_signatureAlgorithm = GetSignatureAlgorithm(m_safeCertContext);
- return m_signatureAlgorithm;
- }
- }
- public string Thumbprint {
- get {
- return GetCertHashString();
- }
- }
- public int Version {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- if (m_version == 0)
- m_version = (int) GetVersion(m_safeCertContext);
- return m_version;
- }
- }
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- public unsafe string GetNameInfo(X509NameType nameType, bool forIssuer) {
- uint issuerFlag = forIssuer ? CAPI.CERT_NAME_ISSUER_FLAG : 0;
- uint type = X509Utils.MapNameType(nameType);
- switch(type) {
- case CAPI.CERT_NAME_SIMPLE_DISPLAY_TYPE:
- return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type);
- case CAPI.CERT_NAME_EMAIL_TYPE:
- return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type);
- }
- string name = String.Empty;
- // If the type requested is not supported in downlevel platforms; we try to decode the alt name extension by hand.
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- IntPtr[] pAltName = new IntPtr[2];
- pAltName[0] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME : CAPI.szOID_SUBJECT_ALT_NAME,
- pCertInfo.cExtension,
- pCertInfo.rgExtension);
- pAltName[1] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME2 : CAPI.szOID_SUBJECT_ALT_NAME2,
- pCertInfo.cExtension,
- pCertInfo.rgExtension);
- for (int i = 0; i < pAltName.Length; i++) {
- if (pAltName[i] != IntPtr.Zero) {
- CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pAltName[i], typeof(CAPI.CERT_EXTENSION));
- byte[] rawData = new byte[extension.Value.cbData];
- Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
- uint cbDecoded = 0;
- SafeLocalAllocHandle decoded = null;
- // Decode the extension.
- SafeLocalAllocHandle ptr = X509Utils.StringToAnsiPtr(extension.pszObjId);
- bool result = CAPI.DecodeObject(ptr.DangerousGetHandle(),
- rawData,
- out decoded,
- out cbDecoded);
- ptr.Dispose();
- if (result) {
- CAPI.CERT_ALT_NAME_INFO altNameInfo = (CAPI.CERT_ALT_NAME_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_ALT_NAME_INFO));
- for (int index = 0; index < altNameInfo.cAltEntry; index++) {
- IntPtr pAltInfoPtr = new IntPtr((long) altNameInfo.rgAltEntry + index * Marshal.SizeOf(typeof(CAPI.CERT_ALT_NAME_ENTRY)));
- CAPI.CERT_ALT_NAME_ENTRY altNameEntry = (CAPI.CERT_ALT_NAME_ENTRY) Marshal.PtrToStructure(pAltInfoPtr, typeof(CAPI.CERT_ALT_NAME_ENTRY));
- switch(type) {
- case CAPI.CERT_NAME_UPN_TYPE:
- if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_OTHER_NAME) {
- CAPI.CERT_OTHER_NAME otherName = (CAPI.CERT_OTHER_NAME) Marshal.PtrToStructure(altNameEntry.Value.pOtherName, typeof(CAPI.CERT_OTHER_NAME));
- if (otherName.pszObjId == CAPI.szOID_NT_PRINCIPAL_NAME) {
- uint cbUpnName = 0;
- SafeLocalAllocHandle pUpnName = null;
- result = CAPI.DecodeObject(new IntPtr(CAPI.X509_UNICODE_ANY_STRING),
- X509Utils.PtrToByte(otherName.Value.pbData, otherName.Value.cbData),
- out pUpnName,
- out cbUpnName);
- if (result) {
- CAPI.CERT_NAME_VALUE nameValue = (CAPI.CERT_NAME_VALUE) Marshal.PtrToStructure(pUpnName.DangerousGetHandle(), typeof(CAPI.CERT_NAME_VALUE));
- if (X509Utils.IsCertRdnCharString(nameValue.dwValueType))
- name = Marshal.PtrToStringUni(nameValue.Value.pbData);
- pUpnName.Dispose();
- }
- }
- }
- break;
- case CAPI.CERT_NAME_DNS_TYPE:
- if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_DNS_NAME)
- name = Marshal.PtrToStringUni(altNameEntry.Value.pwszDNSName);
- break;
- case CAPI.CERT_NAME_URL_TYPE:
- if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_URL)
- name = Marshal.PtrToStringUni(altNameEntry.Value.pwszURL);
- break;
- }
- }
- decoded.Dispose();
- }
- }
- }
- if (nameType == X509NameType.DnsName) {
- // If no DNS name is found in the CERT_ALT_NAME extension, return the CommonName.
- // Commercial CAs such as Verisign don't include a SubjectAltName extension in the certificates they use for SSL server authentication.
- // Instead they use the CommonName in the subject RDN as the server's DNS name.
- if (name == null || name.Length == 0)
- name = CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, CAPI.CERT_NAME_ATTR_TYPE);
- }
- return name;
- }
- #if !FEATURE_CORESYSTEM
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
- [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
- [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
- public override void Import(byte[] rawData) {
- Reset();
- base.Import(rawData);
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
- [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
- [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
- public override void Import(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {
- Reset();
- base.Import(rawData, password, keyStorageFlags);
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
- [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
- [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
- public override void Import(byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) {
- Reset();
- base.Import(rawData, password, keyStorageFlags);
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
- [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
- [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- public override void Import(string fileName) {
- Reset();
- base.Import(fileName);
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
- [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
- [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- public override void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags) {
- Reset();
- base.Import(fileName, password, keyStorageFlags);
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
- [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
- [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- public override void Import(string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) {
- Reset();
- base.Import(fileName, password, keyStorageFlags);
- m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
- }
- [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
- [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
- [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
- public override void Reset () {
- m_version = 0;
- m_notBefore = DateTime.MinValue;
- m_notAfter = DateTime.MinValue;
- m_privateKey = null;
- m_publicKey = null;
- m_extensions = null;
- m_signatureAlgorithm = null;
- m_subjectName = null;
- m_issuerName = null;
- if (!m_safeCertContext.IsInvalid) {
- // Free the current certificate handle
- m_safeCertContext.Dispose();
- m_safeCertContext = SafeCertContextHandle.InvalidHandle;
- }
- base.Reset();
- }
- #endif // !FEATURE_CORESYSTEM
- public bool Verify () {
- if (m_safeCertContext.IsInvalid)
- throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
- int hr = X509Utils.VerifyCertificate(this.CertContext,
- null,
- null,
- X509RevocationMode.Online, // We default to online revocation check.
- X509RevocationFlag.ExcludeRoot,
- DateTime.Now,
- new TimeSpan(0, 0, 0), // default
- null,
- new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE),
- IntPtr.Zero);
- return (hr == CAPI.S_OK);
- }
- //
- // public static methods
- //
- public static X509ContentType GetCertContentType (byte[] rawData) {
- if (rawData == null || rawData.Length == 0)
- throw new ArgumentException(SR.GetString(SR.Arg_EmptyOrNullArray), "rawData");
- uint contentType = QueryCertBlobType(rawData);
- return X509Utils.MapContentType(contentType);
- }
- [ResourceExposure(ResourceScope.Machine)]
- #if !FEATURE_CORESYSTEM
- [ResourceConsumption(ResourceScope.Machine)]
- #endif
- public static X509ContentType GetCertContentType (string fileName) {
- if (fileName == null)
- throw new ArgumentNullException("fileName");
- string fullPath = Path.GetFullPath(fileName);
- #if !FEATURE_CORESYSTEM
- new FileIOPermission (FileIOPermissionAccess.Read, fullPath).Demand();
- #endif
- uint contentType = QueryCertFileType(fileName);
- return X509Utils.MapContentType(contentType);
- }
- //
- // Internal
- //
- internal SafeCertContextHandle CertContext {
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- get {
- return m_safeCertContext;
- }
- }
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- internal static bool GetPrivateKeyInfo (SafeCertContextHandle safeCertContext, ref CspParameters parameters) {
- SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
- uint cbData = 0;
- if (!CAPI.CertGetCertificateContextProperty(safeCertContext,
- CAPI.CERT_KEY_PROV_INFO_PROP_ID,
- ptr,
- ref cbData)) {
- int dwErrorCode = Marshal.GetLastWin32Error();
- if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND)
- return false;
- else
- throw new CryptographicException(Marshal.GetLastWin32Error());
- }
- ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData));
- if (!CAPI.CertGetCertificateContextProperty(safeCer