1 //------------------------------------------------------------------------------
2 // <copyright file="_SecureChannel.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Net.Security {
8 using System.Diagnostics;
10 using System.Net.Sockets;
11 using System.Runtime.InteropServices;
12 using System.Security.Authentication.ExtendedProtection;
13 using System.Security.Cryptography;
14 using System.Security.Cryptography.X509Certificates;
16 using System.Threading;
17 using System.Security.Permissions;
18 using System.Globalization;
19 using System.ComponentModel;
20 using System.Security.Principal;
21 using System.Security;
22 using System.Collections;
25 // SecureChannel - a wrapper on SSPI based functionality,
26 // provides an additional abstraction layer over SSPI
27 // for the SSL Stream to utilize.
30 internal class SecureChannel {
31 //also used as a lock object
32 internal const string SecurityPackage = "Microsoft Unified Security Protocol Provider";
33 private static readonly object s_SyncObject = new object();
35 private const ContextFlags RequiredFlags =
36 ContextFlags.ReplayDetect |
37 ContextFlags.SequenceDetect |
38 ContextFlags.Confidentiality|
39 ContextFlags.AllocateMemory;
42 private const ContextFlags ServerRequiredFlags =
44 | ContextFlags.AcceptStream
45 // | ContextFlags.AcceptExtendedError
48 private const int ChainRevocationCheckExcludeRoot = 0x40000000;
50 // When reading a frame from the wire first read this many bytes for the header.
51 internal const int ReadHeaderSize = 5;
53 private static volatile X509Store s_MyCertStoreEx;
54 private static volatile X509Store s_MyMachineCertStoreEx;
56 private SafeFreeCredentials m_CredentialsHandle;
57 private SafeDeleteContext m_SecurityContext;
58 private ContextFlags m_Attributes;
59 private readonly string m_Destination;
60 private readonly string m_HostName;
62 private readonly bool m_ServerMode;
63 private readonly bool m_RemoteCertRequired;
64 private readonly SchProtocols m_ProtocolFlags;
65 private readonly EncryptionPolicy m_EncryptionPolicy;
66 private SslConnectionInfo m_ConnectionInfo;
68 private X509Certificate m_ServerCertificate;
69 private X509Certificate m_SelectedClientCertificate;
70 private bool m_IsRemoteCertificateAvailable;
72 private readonly X509CertificateCollection m_ClientCertificates;
73 private LocalCertSelectionCallback m_CertSelectionDelegate;
75 // These are the MAX encrypt buffer output sizes, not the actual sizes.
76 private int m_HeaderSize = 5; //ATTN must be set to at least 5 by default
77 private int m_TrailerSize = 16;
78 private int m_MaxDataSize = 16354;
80 private bool m_CheckCertRevocation;
81 private bool m_CheckCertName;
83 private bool m_RefreshCredentialNeeded;
86 internal SecureChannel(string hostname, bool serverMode, SchProtocols protocolFlags, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool remoteCertRequired, bool checkCertName,
87 bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy, LocalCertSelectionCallback certSelectionDelegate)
89 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::.ctor", "hostname:" + hostname + " #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)));
90 if (Logging.On) Logging.PrintInfo(Logging.Web, this, ".ctor", "hostname=" + hostname + ", #clientCertificates=" + ((clientCertificates == null) ? "0" : clientCertificates.Count.ToString(NumberFormatInfo.InvariantInfo)) + ", encryptionPolicy=" + encryptionPolicy);
91 SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPISecureChannel, SecurityPackage, true);
93 m_Destination = hostname;
95 GlobalLog.Assert(hostname != null, "SecureChannel#{0}::.ctor()|hostname == null", ValidationHelper.HashString(this));
96 m_HostName = hostname;
97 m_ServerMode = serverMode;
100 m_ProtocolFlags = (protocolFlags & SchProtocols.ServerMask);
102 m_ProtocolFlags = (protocolFlags & SchProtocols.ClientMask);
104 m_ServerCertificate = serverCertificate;
105 m_ClientCertificates = clientCertificates;
106 m_RemoteCertRequired = remoteCertRequired;
107 m_SecurityContext = null;
108 m_CheckCertRevocation = checkCertRevocationStatus;
109 m_CheckCertName = checkCertName;
110 m_CertSelectionDelegate = certSelectionDelegate;
111 m_RefreshCredentialNeeded = true;
112 m_EncryptionPolicy = encryptionPolicy;
113 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::.ctor");
117 // SecureChannel properties
119 // LocalServerCertificate - local certificate for server mode channel
120 // LocalClientCertificate - selected certificated used in the client channel mode otherwise null
121 // IsRemoteCertificateAvailable - true if the remote side has provided a certificate
122 // HeaderSize - Header & trailer sizes used in the TLS stream
125 internal X509Certificate LocalServerCertificate {
127 return m_ServerCertificate;
131 internal X509Certificate LocalClientCertificate {
133 return m_SelectedClientCertificate;
137 internal bool IsRemoteCertificateAvailable {
139 return m_IsRemoteCertificateAvailable;
144 unsafe static class UnmanagedCertificateContext
147 [StructLayout(LayoutKind.Sequential)]
148 private struct _CERT_CONTEXT {
149 internal Int32 dwCertEncodingType;
150 internal IntPtr pbCertEncoded;
151 internal Int32 cbCertEncoded;
152 internal IntPtr pCertInfo;
153 internal IntPtr hCertStore;
156 internal static X509Certificate2Collection GetStore(SafeFreeCertContext certContext)
158 X509Certificate2Collection result = new X509Certificate2Collection();
160 if (certContext.IsInvalid)
163 _CERT_CONTEXT context = (_CERT_CONTEXT)Marshal.PtrToStructure(certContext.DangerousGetHandle(), typeof(_CERT_CONTEXT));
165 if (context.hCertStore != IntPtr.Zero)
167 X509Store store = null;
169 store = new X509Store(context.hCertStore);
170 result = store.Certificates;
181 //This code extracts a remote certificate upon request.
182 //SECURITY: The scenario is allowed in semitrust
184 internal X509Certificate2 GetRemoteCertificate(out X509Certificate2Collection remoteCertificateStore)
186 remoteCertificateStore = null;
188 if (m_SecurityContext == null)
191 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::RemoteCertificate{get;}");
192 X509Certificate2 result = null;
193 SafeFreeCertContext remoteContext = null;
195 remoteContext = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.RemoteCertificate) as SafeFreeCertContext;
196 if (remoteContext != null && !remoteContext.IsInvalid) {
197 result = new X509Certificate2(remoteContext.DangerousGetHandle());
201 if (remoteContext != null) {
202 remoteCertificateStore = UnmanagedCertificateContext.GetStore(remoteContext);
203 remoteContext.Close();
207 if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true))));
208 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::RemoteCertificate{get;}", (result == null? "null" :result.Subject));
213 internal ChannelBinding GetChannelBinding(ChannelBindingKind kind)
215 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::GetChannelBindingToken", kind.ToString());
217 ChannelBinding result = null;
218 if (m_SecurityContext != null)
220 result = SSPIWrapper.QueryContextChannelBinding(GlobalSSPI.SSPISecureChannel, m_SecurityContext, (ContextAttribute)kind);
223 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::GetChannelBindingToken", ValidationHelper.HashString(result));
227 internal bool CheckCertRevocationStatus {
229 return m_CheckCertRevocation;
233 internal X509CertificateCollection ClientCertificates {
235 return m_ClientCertificates;
239 internal int HeaderSize {
245 internal int MaxDataSize {
247 return m_MaxDataSize;
251 internal SslConnectionInfo ConnectionInfo {
253 return m_ConnectionInfo;
257 internal bool IsValidContext {
259 return !(m_SecurityContext == null || m_SecurityContext.IsInvalid);
263 internal bool IsServer {
269 internal bool RemoteCertRequired {
271 return m_RemoteCertRequired;
275 internal void SetRefreshCredentialNeeded()
277 m_RefreshCredentialNeeded = true;
280 internal void Close() {
281 if (m_SecurityContext != null) {
282 m_SecurityContext.Close();
284 if (m_CredentialsHandle != null) {
285 m_CredentialsHandle.Close();
290 // SECURITY: we open a private key container on behalf of the caller
291 // and we require the caller to have permission associated with that operation.
292 // After discussing with X509Certificate2 owners decided to demand KeyContainerPermission (Open)
293 // At the same time we assert StorePermission on the caller frame since for consistency
294 // we cannot predict when it will be demanded (SSL session reuse feature)
296 X509Certificate2 EnsurePrivateKey(X509Certificate certificate)
298 if (certificate == null)
301 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_locating_private_key_for_certificate, certificate.ToString(true)));
304 X509Certificate2 certEx = certificate as X509Certificate2;
305 Type t = certificate.GetType();
306 string certHash = null;
308 // Protecting from X509Certificate2 derived classes
309 if (t != typeof(X509Certificate2) && t != typeof(X509Certificate))
311 if (certificate.Handle != IntPtr.Zero)
313 certEx = new X509Certificate2(certificate);
314 certHash = certEx.GetCertHashString();
319 certHash = certificate.GetCertHashString();
324 if (certEx.HasPrivateKey)
326 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_cert_is_of_type_2));
330 if ((object)certificate != (object) certEx)
335 // The certificate doesn't have a private key, so we need
336 // to open the store and search for it there. Demand the
337 // KeyContainerPermission with Open access before opening
338 // the store. If store.Open() or store.Cert.Find()
339 // demand the same permissions, then we should remove our
342 ExceptionHelper.KeyContainerPermissionOpen.Demand();
344 X509Certificate2Collection collectionEx;
346 // ELSE Try MY user and machine stores for private key check
347 // For server side mode MY machine store takes priority
348 X509Store store = EnsureStoreOpened(m_ServerMode);
351 collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false);
352 if (collectionEx.Count > 0 && collectionEx[0].PrivateKey != null)
354 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_found_cert_in_store, (m_ServerMode ? "LocalMachine" : "CurrentUser")));
355 return collectionEx[0];
359 store = EnsureStoreOpened(!m_ServerMode);
362 collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false);
363 if (collectionEx.Count > 0 && collectionEx[0].PrivateKey != null)
365 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_found_cert_in_store, (m_ServerMode ? "CurrentUser" : "LocalMachine")));
366 return collectionEx[0];
370 catch (CryptographicException) {
373 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_did_not_find_cert_in_store));
378 // Security: we temporarily reset thread token to open the cert store under process acount
380 [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
381 internal static X509Store EnsureStoreOpened(bool isMachineStore)
383 X509Store store = isMachineStore? s_MyMachineCertStoreEx: s_MyCertStoreEx;
385 lock (s_SyncObject) {
386 store = isMachineStore? s_MyMachineCertStoreEx: s_MyCertStoreEx;
388 // NOTE: that if this call fails we won't keep track and the next time we enter we will try to open the store again
389 StoreLocation storeLocation = isMachineStore? StoreLocation.LocalMachine: StoreLocation.CurrentUser;
390 store = new X509Store(StoreName.My, storeLocation);
393 // For v 1.1 compat We want to ensure the store is opened under the **process** acount.
396 using (WindowsIdentity.Impersonate(IntPtr.Zero))
398 store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
399 GlobalLog.Print("SecureChannel::EnsureStoreOpened() storeLocation:" + storeLocation + " returned store:" + store.GetHashCode().ToString("x"));
406 s_MyMachineCertStoreEx = store;
408 s_MyCertStoreEx = store;
412 catch (Exception exception) {
413 if (exception is CryptographicException || exception is SecurityException) {
414 GlobalLog.Assert("SecureChannel::EnsureStoreOpened()", "Failed to open cert store, location:" + storeLocation + " exception:" + exception);
417 if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_open_store_failed, storeLocation, exception));
428 // For the input type == X509Certificate2 cert the same ref
429 // For an older cert format clones it as X509Certificate2 and returns result
430 // For a derived type clones it as X509Certificate2 and returns result
432 static X509Certificate2 MakeEx(X509Certificate certificate)
434 if (certificate.GetType() == typeof(X509Certificate2))
435 return (X509Certificate2)certificate;
437 X509Certificate2 certificateEx = null;
439 if (certificate.Handle!=IntPtr.Zero) {
440 certificateEx = new X509Certificate2(certificate);
443 catch (SecurityException) {
445 catch (CryptographicException) {
447 return certificateEx;
451 // Used only by client SSL code, never returns null.
453 private string[] GetIssuers()
455 string[] issuers = new string[0];
459 IssuerListInfoEx issuerList = (IssuerListInfoEx)SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.IssuerListInfoEx);
462 if (issuerList.cIssuers>0) {
464 uint count = issuerList.cIssuers;
465 issuers = new string[issuerList.cIssuers];
466 _CERT_CHAIN_ELEMENT* pIL = (_CERT_CHAIN_ELEMENT*)issuerList.aIssuers.DangerousGetHandle();
467 for (int i =0; i<count; ++i) {
468 _CERT_CHAIN_ELEMENT* pIL2 = pIL + i;
469 uint size = pIL2->cbSize;
470 byte* ptr = (byte*)(pIL2->pCertContext);
471 byte[] x = new byte[size];
472 for (int j=0; j<size; j++) {
475 // Oid oid = new Oid();
476 // oid.Value = "1.3.6.1.5.5.7.3.2";
477 X500DistinguishedName x500DistinguishedName = new X500DistinguishedName(x);
478 issuers[i] = x500DistinguishedName.Name;
479 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::GetIssuers() IssuerListEx[" + i + "]:" + issuers[i]);
486 if (issuerList.aIssuers != null)
488 issuerList.aIssuers.Close();
495 AcquireCredentials - Attempts to find Client Credential
496 Information, that can be sent to the server. In our case,
497 this is only Client Certificates, that we have Credential Info.
500 case 0: Cert Selection delegate is present
501 Alwasys use its result as the client cert answer.
502 Try to use cached credential handle whenever feasible.
503 Do not use cached anonymous creds if the delegate has returned null
504 and the collection is not empty (allow responding with the cert later).
506 case 1: Certs collection is empty
507 Always use the same statically acquired anonymous SSL Credential
509 case 2: Before our Connection with the Server
510 If we have a cached credential handle keyed by first X509Certificate
511 **content** in the passed collection, then we use that cached
512 credential and hoping to restart a session.
514 Otherwise create a new anonymous (allow responding with the cert later).
516 case 3: After our Connection with the Server (ie during handshake or re-handshake)
517 The server has requested that we send it a Certificate then
518 we Enumerate a list of server sent Issuers trying to match against
519 our list of Certificates, the first match is sent to the server.
521 Once we got a cert we again try to match cached credential handle if possible.
522 This will not restart a session but helps miminizing the number of handles we create.
524 In the case of an error getting a Certificate or checking its private Key we fall back
525 to the behavior of having no certs, case 1
527 Returns: True if cached creds were used, false otherwise
531 //SECURITY: The permission assert is needed for Chain.Build and for certs enumeration.
532 // The user will see KeyContainerPermission demand in the case where the client
533 // cert as about to be used.
534 // Note: We call a user certificate selection delegate under permission
535 // assert but the signature of the delegate is unique so it's safe
537 [StorePermission(SecurityAction.Assert, Unrestricted=true)]
538 private bool AcquireClientCredentials(ref byte[] thumbPrint)
540 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials");
543 // Acquire possible Client Certificate information and set it on the handle
546 X509Certificate clientCertificate = null; // This is a candidate that can come from the user callback or be guessed when targeting a session restart
547 ArrayList filteredCerts = new ArrayList(); // This is an intermediate client certs collection that try to use if no selectedCert is available yet.
548 string[] issuers = null; // This is a list of issuers sent by the server, only valid is we do know what the server cert is.
550 bool sessionRestartAttempt = false; // if true and no cached creds we will use anonymous creds.
552 if (m_CertSelectionDelegate!=null)
555 issuers = GetIssuers();
557 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback");
559 X509Certificate2 remoteCert = null;
561 X509Certificate2Collection dummyCollection;
562 remoteCert = GetRemoteCertificate(out dummyCollection);
563 clientCertificate = m_CertSelectionDelegate(m_HostName, ClientCertificates, remoteCert, issuers);
566 if (remoteCert != null)
571 if (clientCertificate != null)
573 if (m_CredentialsHandle == null)
574 sessionRestartAttempt = true;
575 filteredCerts.Add(clientCertificate);
576 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_got_certificate_from_delegate));
580 // If ClientCertificates.Count != 0, how come we don't try to go through them and add them to the filtered certs, just like when there is no delegate????
581 if (ClientCertificates.Count == 0)
583 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_no_delegate_and_have_no_client_cert));
584 sessionRestartAttempt = true;
588 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_no_delegate_but_have_client_cert));
593 else if (m_CredentialsHandle == null && m_ClientCertificates != null && m_ClientCertificates.Count > 0)
595 // This is where we attempt to restart a session by picking the FIRST cert from the collection.
596 // Otheriwse (next elses) it is either server sending a client cert request or the session is renegotiated.
597 clientCertificate = ClientCertificates[0];
598 sessionRestartAttempt = true;
599 if (clientCertificate!=null)
600 filteredCerts.Add(clientCertificate);
601 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_attempting_restart_using_cert, (clientCertificate == null ? "null" : clientCertificate.ToString(true))));
603 else if (m_ClientCertificates!=null && m_ClientCertificates.Count > 0)
606 // This should be a server request for the client cert sent over currently anonyumous sessions.
609 issuers = GetIssuers();
614 if (issuers == null || issuers.Length == 0)
615 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_no_issuers_try_all_certs));
617 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_server_issuers_look_for_matching_certs, issuers.Length));
620 for (int i = 0; i < m_ClientCertificates.Count; ++i)
623 // make sure we add only if the cert matches one of the issuers
624 // If no issuers were sent and then try all client certs starting with the first one.
626 if (issuers != null && issuers.Length != 0)
628 X509Certificate2 certificateEx = null;
629 X509Chain chain = null;
631 certificateEx = MakeEx(m_ClientCertificates[i]);
632 if (certificateEx == null)
635 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer);
636 chain = new X509Chain();
638 chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
639 chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
640 chain.Build(certificateEx);
644 // We ignore any errors happened with chain.
645 // Consider: try to locate the "best" client cert that has no errors and the lognest validity internal
647 if (chain.ChainElements.Count > 0)
649 for (int ii=0; ii< chain.ChainElements.Count; ++ii)
651 string issuer = chain.ChainElements[ii].Certificate.Issuer;
652 found = Array.IndexOf(issuers, issuer)!=-1;
654 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials() matched:" + issuer);
657 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials() no match:" + issuer);
668 if (certificateEx != null && (object)certificateEx != (object)m_ClientCertificates[i])
669 certificateEx.Reset();
672 if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_selected_cert, m_ClientCertificates[i].ToString(true)));
673 filteredCerts.Add(m_ClientCertificates[i]);
677 bool cachedCred = false; // This is a return result from this method
678 X509Certificate2 selectedCert = null; // This is a final selected cert (ensured that it does have private key with it)
680 clientCertificate = null;
683 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_n_certs_after_filtering, filteredCerts.Count));
684 if (filteredCerts.Count != 0)
685 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_finding_matching_certs));
689 // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key.
690 // THEN anonymous (no client cert) credential will be used
692 // SECURITY: Accessing X509 cert Credential is disabled for semitrust
693 // We no longer need to demand for unmanaged code permissions.
694 // EnsurePrivateKey should do the right demand for us.
695 for (int i=0; i < filteredCerts.Count; ++i)
697 clientCertificate = filteredCerts[i] as X509Certificate;
698 if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
700 clientCertificate = null;
704 GlobalLog.Assert(((object) clientCertificate == (object) selectedCert) || clientCertificate.Equals(selectedCert), "AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'.");
706 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null? "null": selectedCert.Subject));
708 // Try to locate cached creds first.
710 // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type.
712 byte[] guessedThumbPrint = selectedCert == null? null: selectedCert.GetCertHash();
713 SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, m_ProtocolFlags, m_EncryptionPolicy);
715 // We can probably do some optimization here. If the selectedCert is returned by the delegate
716 // we can always go ahead and use the certificate to create our credential
717 // (Instead of going anonymous as we do here)
718 if (sessionRestartAttempt && cachedCredentialHandle == null && selectedCert != null)
720 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session.");
722 // (see VsWhidbey#363953) For some (probably good) reason IIS does not renegotiate a restarted session if client cert is needed.
723 // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate.
724 // The following block happens if client did specify a certificate but no cached creds were found in the cache
725 // Since we don't restart a session the server side can still challenge for a client cert.
726 if ((object)clientCertificate != (object)selectedCert)
727 selectedCert.Reset();
728 guessedThumbPrint = null;
730 clientCertificate = null;
733 if (cachedCredentialHandle != null)
735 if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_log_using_cached_credential));
736 m_CredentialsHandle = cachedCredentialHandle;
737 m_SelectedClientCertificate = clientCertificate;
742 SecureCredential.Flags flags = SecureCredential.Flags.ValidateManual | SecureCredential.Flags.NoDefaultCred;
743 if (!ServicePointManager.DisableStrongCrypto
744 && ((m_ProtocolFlags & (SchProtocols.Tls10 | SchProtocols.Tls11 | SchProtocols.Tls12)) != 0))
746 flags |= SecureCredential.Flags.UseStrongCrypto;
749 SecureCredential secureCredential = new SecureCredential(SecureCredential.CurrentVersion, selectedCert, flags, m_ProtocolFlags, m_EncryptionPolicy);
750 m_CredentialsHandle = AcquireCredentialsHandle(CredentialUse.Outbound, ref secureCredential);
751 thumbPrint = guessedThumbPrint; //delay it until here in case something above threw
752 m_SelectedClientCertificate = clientCertificate;
757 // an extra cert could have been created, dispose it now
758 if (selectedCert != null && (object)clientCertificate != (object)selectedCert)
759 selectedCert.Reset();
762 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), ValidationHelper.ToString(m_CredentialsHandle));
768 // Acquire Server Side Certificate information and set it on the class
771 //SECURITY: The permission assert is needed for Chain.Build and for certs enumeration.
772 // The user will see KeyContainerPermission demand in the case where the server
773 // cert as about to be used.
774 // Note: We call a user certificate selection delegate under permission
775 // assert but the signature of the delegate is unique so it's safe
777 [StorePermission(SecurityAction.Assert, Unrestricted=true)]
778 private bool AcquireServerCredentials(ref byte[] thumbPrint)
780 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireServerCredentials");
782 X509Certificate localCertificate = null;
783 bool cachedCred = false;
785 if (m_CertSelectionDelegate != null)
787 X509CertificateCollection tempCollection = new X509CertificateCollection();
788 tempCollection.Add(m_ServerCertificate);
789 localCertificate = m_CertSelectionDelegate(string.Empty, tempCollection, null, new string[0]);
790 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireServerCredentials() Use delegate selected Cert");
794 localCertificate = m_ServerCertificate;
797 if (localCertificate == null)
798 throw new NotSupportedException(SR.GetString(SR.net_ssl_io_no_server_cert));
800 // SECURITY: Accessing X509 cert Credential is disabled for semitrust
801 // We no longer need to demand for unmanaged code permissions.
802 // EnsurePrivateKey should do the right demand for us.
803 X509Certificate2 selectedCert = EnsurePrivateKey(localCertificate);
805 if (selectedCert == null)
806 throw new NotSupportedException(SR.GetString(SR.net_ssl_io_no_server_cert));
808 GlobalLog.Assert(localCertificate.Equals(selectedCert), "AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'.");
811 // Note selectedCert is a safe ref possibly cloned from the user passed Cert object
813 byte [] guessedThumbPrint = selectedCert.GetCertHash();
815 SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, m_ProtocolFlags, m_EncryptionPolicy);
817 if (cachedCredentialHandle != null)
819 m_CredentialsHandle = cachedCredentialHandle;
820 m_ServerCertificate = localCertificate;
825 SecureCredential secureCredential = new SecureCredential(SecureCredential.CurrentVersion, selectedCert, SecureCredential.Flags.Zero, m_ProtocolFlags, m_EncryptionPolicy);
826 m_CredentialsHandle = AcquireCredentialsHandle(CredentialUse.Inbound, ref secureCredential);
827 thumbPrint = guessedThumbPrint;
828 m_ServerCertificate = localCertificate;
833 // an extra cert could have been created, dispose it now
834 if ((object)localCertificate != (object)selectedCert)
835 selectedCert.Reset();
838 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), ValidationHelper.ToString(m_CredentialsHandle));
844 // Security: we temporarily reset thread token to open the handle under process acount
846 [SecurityPermissionAttribute(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
847 SafeFreeCredentials AcquireCredentialsHandle(CredentialUse credUsage, ref SecureCredential secureCredential)
849 // First try without impersonation, if it fails, then try the process account.
850 // I.E. We don't know which account the certificate context was created under.
853 // For v 1.1 compat We want to ensure the credential are accessed under >>process<< acount.
855 using (WindowsIdentity.Impersonate(IntPtr.Zero))
857 return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
860 return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
865 internal ProtocolToken NextMessage(byte[] incoming, int offset, int count) {
866 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::NextMessage");
867 byte[] nextmsg = null;
868 SecurityStatus errorCode = GenerateToken(incoming, offset, count, ref nextmsg);
870 if (!m_ServerMode && errorCode == SecurityStatus.CredentialsNeeded)
872 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::NextMessage() returned SecurityStatus.CredentialsNeeded");
873 SetRefreshCredentialNeeded();
874 errorCode = GenerateToken(incoming, offset, count, ref nextmsg);
876 ProtocolToken token = new ProtocolToken(nextmsg, errorCode);
877 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::NextMessage", token.ToString());
882 GenerateToken - Called after each sucessive state
883 in the Client - Server handshake. This function
884 generates a set of bytes that will be sent next to
885 the server. The server responds, each response,
886 is pass then into this function, again, and the cycle
887 repeats until successful connection, or failure.
890 input - bytes from the wire
891 output - ref to byte [], what we will send to the
894 errorCode - an SSPI error code
897 private SecurityStatus GenerateToken(byte[] input, int offset, int count, ref byte[] output)
901 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::GenerateToken, m_RefreshCredentialNeeded = " + m_RefreshCredentialNeeded);
904 if (offset < 0 || offset > (input == null ? 0 : input.Length))
906 GlobalLog.Assert(false, "SecureChannel#" + ValidationHelper.HashString(this) + "::GenerateToken", "Argument 'offset' out of range.");
907 throw new ArgumentOutOfRangeException("offset");
909 if (count < 0 || count > (input == null ? 0 : input.Length - offset))
911 GlobalLog.Assert(false, "SecureChannel#" + ValidationHelper.HashString(this) + "::GenerateToken", "Argument 'count' out of range.");
912 throw new ArgumentOutOfRangeException("count");
915 SecurityBuffer incomingSecurity = null;
916 SecurityBuffer[] incomingSecurityBuffers = null;
919 incomingSecurity = new SecurityBuffer(input, offset, count, BufferType.Token);
920 incomingSecurityBuffers = new SecurityBuffer[]
923 new SecurityBuffer(null, 0, 0, BufferType.Empty)
927 SecurityBuffer outgoingSecurity = new SecurityBuffer(null, BufferType.Token);
931 bool cachedCreds = false;
932 byte[] thumbPrint = null;
934 // Looping through ASC or ISC with potenially cached credential that could have been
935 // already disposed from a different thread before ISC or ASC dir increemnt a cred ref count.
942 if (m_RefreshCredentialNeeded)
944 cachedCreds = m_ServerMode
945 ? AcquireServerCredentials(ref thumbPrint)
946 : AcquireClientCredentials(ref thumbPrint);
951 errorCode = SSPIWrapper.AcceptSecurityContext(
952 GlobalSSPI.SSPISecureChannel,
953 ref m_CredentialsHandle,
954 ref m_SecurityContext,
955 ServerRequiredFlags | (m_RemoteCertRequired? ContextFlags.MutualAuth: ContextFlags.Zero),
965 if(incomingSecurity == null)
967 errorCode = SSPIWrapper.InitializeSecurityContext(
968 GlobalSSPI.SSPISecureChannel,
969 ref m_CredentialsHandle,
970 ref m_SecurityContext,
972 RequiredFlags | ContextFlags.InitManualCredValidation,
979 // This only needs to happen the first time per context.
980 if ((errorCode == (int)SecurityStatus.OK || errorCode == (int)SecurityStatus.ContinueNeeded)
981 && ComNetOS.IsWin8orLater && Microsoft.Win32.UnsafeNativeMethods.IsPackagedProcess.Value)
983 // Windows Store app. Specify a window handle in case SChannel needs to pop-up prompts, like
984 // when it asks for permission to use a client certificate.
985 int setError = SSPIWrapper.SetContextAttributes(GlobalSSPI.SSPISecureChannel,
987 ContextAttribute.UiInfo,
988 UnsafeNclNativeMethods.AppXHelper.PrimaryWindowHandle.Value);
989 Debug.Assert(setError == 0, "SetContextAttributes error: " + setError);
994 errorCode = SSPIWrapper.InitializeSecurityContext(
995 GlobalSSPI.SSPISecureChannel,
997 ref m_SecurityContext,
999 RequiredFlags | ContextFlags.InitManualCredValidation,
1001 incomingSecurityBuffers,
1008 } while (cachedCreds && m_CredentialsHandle == null);
1012 if (m_RefreshCredentialNeeded)
1014 m_RefreshCredentialNeeded = false;
1016 // Assuming the ISC or ASC has referenced the credential,
1017 // we want to call dispose so to decrement the effective ref count.
1019 if (m_CredentialsHandle !=null)
1020 m_CredentialsHandle.Close();
1022 // This call may bump up the credential reference count further
1024 // Note that thumbPrint is retrieved from a safe cert object that was possible cloned from the user passed cert
1026 if (!cachedCreds && m_SecurityContext != null && !m_SecurityContext.IsInvalid && !m_CredentialsHandle.IsInvalid)
1028 SslSessionsCache.CacheCredential(m_CredentialsHandle, thumbPrint, m_ProtocolFlags, m_EncryptionPolicy);
1034 output = outgoingSecurity.token;
1037 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::GenerateToken()", MapSecurityStatus((uint)errorCode));
1039 return (SecurityStatus) errorCode;
1044 ProcessHandshakeSuccess -
1045 Called on successful completion of Handshake -
1046 used to set header/trailer sizes for encryption use
1048 Fills in the information about established protocol
1051 internal void ProcessHandshakeSuccess() {
1052 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::ProcessHandshakeSuccess");
1053 StreamSizes streamSizes = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.StreamSizes) as StreamSizes;
1054 if (streamSizes != null) {
1057 m_HeaderSize = streamSizes.header;
1058 m_TrailerSize = streamSizes.trailer;
1059 m_MaxDataSize = checked(streamSizes.maximumMessage - (m_HeaderSize + m_TrailerSize));
1063 if (!NclUtilities.IsFatal(e)){
1064 GlobalLog.Assert(false, "SecureChannel#" + ValidationHelper.HashString(this) + "::ProcessHandshakeSuccess", "StreamSizes out of range.");
1069 m_ConnectionInfo = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPISecureChannel, m_SecurityContext, ContextAttribute.ConnectionInfo) as SslConnectionInfo;
1070 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::ProcessHandshakeSuccess");
1074 Encrypt - Encrypts our bytes before we send them over the wire
1076 PERF: make more efficient, this does an extra copy when the offset
1080 buffer - bytes for sending
1083 output - Encrypted bytes
1088 internal SecurityStatus Encrypt(byte[] buffer, int offset, int size, ref byte[] output, out int resultSize) {
1089 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt");
1090 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt() - offset: " + offset.ToString() + " size: " + size.ToString() +" buffersize: " + buffer.Length.ToString() );
1091 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt() buffer:[" + Encoding.ASCII.GetString(buffer, 0, Math.Min(buffer.Length,128)) + "]");
1093 byte[] e_writeBuffer;
1096 if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length))
1098 throw new ArgumentOutOfRangeException("offset");
1100 if (size < 0 || size > (buffer == null ? 0 : buffer.Length - offset))
1102 throw new ArgumentOutOfRangeException("size");
1107 int bufferSizeNeeded = checked(size + m_HeaderSize + m_TrailerSize);
1108 if (output != null && bufferSizeNeeded <= output.Length)
1110 e_writeBuffer = output;
1114 e_writeBuffer = new byte[bufferSizeNeeded];
1116 Buffer.BlockCopy(buffer, offset, e_writeBuffer, m_HeaderSize, size);
1120 if (!NclUtilities.IsFatal(e)){
1121 GlobalLog.Assert(false, "SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt", "Arguments out of range.");
1126 // encryption using SCHANNEL requires 4 buffers: header, payload, trailer, empty
1128 SecurityBuffer[] securityBuffer = new SecurityBuffer[4];
1130 securityBuffer[0] = new SecurityBuffer(e_writeBuffer, 0, m_HeaderSize, BufferType.Header);
1131 securityBuffer[1] = new SecurityBuffer(e_writeBuffer, m_HeaderSize, size, BufferType.Data);
1132 securityBuffer[2] = new SecurityBuffer(e_writeBuffer, m_HeaderSize + size, m_TrailerSize, BufferType.Trailer);
1133 securityBuffer[3] = new SecurityBuffer(null, BufferType.Empty);
1135 int errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPISecureChannel, m_SecurityContext, securityBuffer, 0);
1137 if (errorCode != 0) {
1138 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt ERROR", errorCode.ToString("x"));
1139 return (SecurityStatus)errorCode;
1142 output = e_writeBuffer;
1143 // The full buffer may not be used
1144 resultSize = securityBuffer[0].size + securityBuffer[1].size + securityBuffer[2].size;
1145 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt OK", "data size:" + resultSize.ToString());
1146 return SecurityStatus.OK;
1151 internal SecurityStatus Decrypt(byte[] payload, ref int offset, ref int count) {
1152 GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::Decrypt() - offset: " + offset.ToString() + " size: " + count.ToString() +" buffersize: " + payload.Length.ToString() );
1154 if (offset < 0 || offset > (payload == null ? 0 : payload.Length))
1156 GlobalLog.Assert(false, "SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt", "Argument 'offset' out of range.");
1157 throw new ArgumentOutOfRangeException("offset");
1159 if (count < 0 || count > (payload == null ? 0 : payload.Length - offset))
1161 GlobalLog.Assert(false, "SecureChannel#" + ValidationHelper.HashString(this) + "::Encrypt", "Argument 'count' out of range.");
1162 throw new ArgumentOutOfRangeException("count");
1165 // decryption using SCHANNEL requires four buffers
1166 SecurityBuffer[] decspc = new SecurityBuffer[4];
1167 decspc[0] = new SecurityBuffer(payload, offset, count, BufferType.Data);
1168 decspc[1] = new SecurityBuffer(null, BufferType.Empty);
1169 decspc[2] = new SecurityBuffer(null, BufferType.Empty);
1170 decspc[3] = new SecurityBuffer(null, BufferType.Empty);
1172 SecurityStatus errorCode = (SecurityStatus)SSPIWrapper.DecryptMessage(GlobalSSPI.SSPISecureChannel, m_SecurityContext, decspc, 0);
1175 for (int i = 0; i < decspc.Length; i++) {
1176 // Sucessfully decoded data and placed it at the following position in the buffer.
1177 if ((errorCode == SecurityStatus.OK && decspc[i].type == BufferType.Data)
1178 // or we failed to decode the data, here is the encoded data
1179 || (errorCode != SecurityStatus.OK && decspc[i].type == BufferType.Extra)) {
1180 offset = decspc[i].offset;
1181 count = decspc[i].size;
1191 VerifyRemoteCertificate - Validates the content of a Remote Certificate
1193 checkCRL if true, checks the certificate revocation list for validity.
1194 checkCertName, if true checks the CN field of the certificate
1198 //This method validates a remote certificate.
1199 //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build
1200 // A user callback has unique signature so it is safe to call it under permisison assert.
1202 [StorePermission(SecurityAction.Assert, Unrestricted=true)]
1203 internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback)
1205 GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::VerifyRemoteCertificate");
1206 SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;
1207 // we don't catch exceptions in this method, so it's safe for "accepted" be initialized with true
1208 bool success = false;
1209 X509Chain chain = null;
1210 X509Certificate2 remoteCertificateEx = null;
1213 X509Certificate2Collection remoteCertificateStore;
1214 remoteCertificateEx = GetRemoteCertificate(out remoteCertificateStore);
1215 m_IsRemoteCertificateAvailable = remoteCertificateEx != null;
1217 if (remoteCertificateEx == null)
1219 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::VerifyRemoteCertificate (no remote cert)", (!m_RemoteCertRequired).ToString());
1220 sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
1224 chain = new X509Chain();
1225 chain.ChainPolicy.RevocationMode = m_CheckCertRevocation? X509RevocationMode.Online : X509RevocationMode.NoCheck;
1226 chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
1227 if (remoteCertificateStore != null)
1228 chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore);
1230 if (!chain.Build(remoteCertificateEx) // Build failed on handle or on policy
1231 && chain.ChainContext == IntPtr.Zero) // Build failed to generate a valid handle
1233 throw new CryptographicException(Marshal.GetLastWin32Error());
1236 if (m_CheckCertName)
1240 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
1241 cppStruct.cbSize = ChainPolicyParameter.StructSize;
1242 cppStruct.dwFlags = 0;
1245 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(IsServer);
1246 cppStruct.pvExtraPolicyPara = &eppStruct;
1248 fixed (char* namePtr = m_HostName) {
1249 eppStruct.pwszServerName = namePtr;
1250 cppStruct.dwFlags |= (int) (IgnoreCertProblem.none & ~IgnoreCertProblem.invalid_name);
1252 SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
1253 status = PolicyWrapper.VerifyChainPolicy(chainContext, ref cppStruct);
1254 if ((CertificateProblem) status == CertificateProblem.CertCN_NO_MATCH)
1255 sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
1260 X509ChainStatus[] chainStatusArray = chain.ChainStatus;
1261 if (chainStatusArray != null && chainStatusArray.Length != 0)
1262 sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
1266 if (remoteCertValidationCallback != null) {
1267 success = remoteCertValidationCallback(m_HostName, remoteCertificateEx, chain, sslPolicyErrors);
1269 if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !m_RemoteCertRequired)
1272 success = (sslPolicyErrors == SslPolicyErrors.None);
1276 if (sslPolicyErrors != SslPolicyErrors.None)
1278 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_remote_cert_has_errors));
1279 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
1280 Logging.PrintInfo(Logging.Web, this, "\t" + SR.GetString(SR.net_log_remote_cert_not_available));
1281 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
1282 Logging.PrintInfo(Logging.Web, this, "\t" + SR.GetString(SR.net_log_remote_cert_name_mismatch));
1283 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
1284 foreach (X509ChainStatus chainStatus in chain.ChainStatus)
1285 Logging.PrintInfo(Logging.Web, this, "\t" + chainStatus.StatusInformation);
1289 if (remoteCertValidationCallback != null)
1290 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_remote_cert_user_declared_valid));
1292 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_remote_cert_has_no_errors));
1296 if (remoteCertValidationCallback != null)
1297 Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_remote_cert_user_declared_invalid));
1300 GlobalLog.Print("Cert Validation, remote cert = " + (remoteCertificateEx == null? "<null>": remoteCertificateEx.ToString(true)));
1303 // At least on Win2k server the chain is found to have dependancies on the original cert context.
1304 // So it should be closed first.
1305 if (chain != null) {
1308 if (remoteCertificateEx != null)
1309 remoteCertificateEx.Reset();
1311 GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::VerifyRemoteCertificate", success.ToString());
1318 typedef void *HCERTSTORE;
1320 //+-------------------------------------------------------------------------
1321 // Certificate context.
1323 // A certificate context contains both the encoded and decoded representation
1324 // of a certificate. A certificate context returned by a cert store function
1325 // must be freed by calling the CertFreeCertificateContext function. The
1326 // CertDuplicateCertificateContext function can be called to make a duplicate
1327 // copy (which also must be freed by calling CertFreeCertificateContext).
1328 //--------------------------------------------------------------------------
1331 // Consider removing.
1332 unsafe class CertificateContext {
1334 [StructLayout(LayoutKind.Sequential)]
1335 private struct _CERT_CONTEXT {
1336 internal Int32 dwCertEncodingType;
1337 internal IntPtr pbCertEncoded;
1338 internal Int32 cbCertEncoded;
1339 internal IntPtr pCertInfo;
1340 internal IntPtr hCertStore;
1343 internal static SafeCloseStore GetShallowHStoreHandler(SafeFreeCertContext certContext) {
1344 if (certContext.IsInvalid) {
1345 return SafeCloseStore.CreateShallowHandle(IntPtr.Zero);
1347 _CERT_CONTEXT context = (_CERT_CONTEXT)Marshal.PtrToStructure(certContext.DangerousGetHandle(), typeof(_CERT_CONTEXT));
1348 return SafeCloseStore.CreateShallowHandle(context.hCertStore);
1353 _CERT_CONTEXT dbgTemplate;
1356 internal CertificateContext(SafeFreeCertContext context) {
1357 GlobalLog.Enter("CertificateContext#" + ValidationHelper.HashString(this) + "::CertificateContext", context.DangerousGetHandle().ToString("x"));
1358 dbgTemplate = (_CERT_CONTEXT)Marshal.PtrToStructure(context.DangerousGetHandle(), typeof(_CERT_CONTEXT));
1359 GlobalLog.Leave("CertificateContext#" + ValidationHelper.HashString(this) + "::CertificateContext");
1363 [Conditional("TRAVE")]
1364 internal void DebugDump() {
1365 GlobalLog.Print("CertificateContext#" + ValidationHelper.HashString(this) + "::CertificateContext()");
1366 GlobalLog.PrintHex(" dwCertEncodingType = ", dbgTemplate.dwCertEncodingType);
1367 GlobalLog.PrintHex(" pbCertEncoded = ", dbgTemplate.pbCertEncoded);
1368 GlobalLog.PrintHex(" cbCertEncoded = ", dbgTemplate.cbCertEncoded);
1369 GlobalLog.PrintHex(" pCertInfo = ", dbgTemplate.pCertInfo);
1370 GlobalLog.PrintHex(" hCertStore = ", dbgTemplate.hCertStore);
1377 internal static string MapSecurityStatus(uint statusCode) {
1378 switch (statusCode) {
1380 case 0x80090001: return "NTE_BAD_UID";
1381 case 0x80090002: return "NTE_BAD_HASH";
1382 case 0x80090003: return "NTE_BAD_KEY";
1383 case 0x80090004: return "NTE_BAD_LEN";
1384 case 0x80090005: return "NTE_BAD_DATA";
1385 case 0x80090006: return "NTE_BAD_SIGNATURE";
1386 case 0x80090007: return "NTE_BAD_VER";
1387 case 0x80090008: return "NTE_BAD_ALGID";
1388 case 0x80090009: return "NTE_BAD_FLAGS";
1389 case 0x8009000A: return "NTE_BAD_TYPE";
1390 case 0x8009000B: return "NTE_BAD_KEY_STATE";
1391 case 0x8009000C: return "NTE_BAD_HASH_STATE";
1392 case 0x8009000D: return "NTE_NO_KEY";
1393 case 0x8009000E: return "NTE_NO_MEMORY";
1394 case 0x8009000F: return "NTE_EXISTS";
1395 case 0x80090010: return "NTE_PERM";
1396 case 0x80090011: return "NTE_NOT_FOUND";
1397 case 0x80090012: return "NTE_DOUBLE_ENCRYPT";
1398 case 0x80090013: return "NTE_BAD_PROVIDER";
1399 case 0x80090014: return "NTE_BAD_PROV_TYPE";
1400 case 0x80090015: return "NTE_BAD_PUBLIC_KEY";
1401 case 0x80090016: return "NTE_BAD_KEYSET";
1402 case 0x80090017: return "NTE_PROV_TYPE_NOT_DEF";
1403 case 0x80090018: return "NTE_PROV_TYPE_ENTRY_BAD";
1404 case 0x80090019: return "NTE_KEYSET_NOT_DEF";
1405 case 0x8009001A: return "NTE_KEYSET_ENTRY_BAD";
1406 case 0x8009001B: return "NTE_PROV_TYPE_NO_MATCH";
1407 case 0x8009001C: return "NTE_SIGNATURE_FILE_BAD";
1408 case 0x8009001D: return "NTE_PROVIDER_DLL_FAIL";
1409 case 0x8009001E: return "NTE_PROV_DLL_NOT_FOUND";
1410 case 0x8009001F: return "NTE_BAD_KEYSET_PARAM";
1411 case 0x80090020: return "NTE_FAIL";
1412 case 0x80090021: return "NTE_SYS_ERR";
1413 case 0x80090022: return "NTE_SILENT_CONTEXT";
1414 case 0x80090023: return "NTE_TOKEN_KEYSET_STORAGE_FULL";
1415 case 0x80090024: return "NTE_TEMPORARY_PROFILE";
1416 case 0x80090025: return "NTE_FIXEDPARAMETER";
1417 case 0x80090300: return "SEC_E_INSUFFICIENT_MEMORY";
1418 case 0x80090301: return "SEC_E_INVALID_HANDLE";
1419 case 0x80090302: return "SEC_E_UNSUPPORTED_FUNCTION";
1420 case 0x80090303: return "SEC_E_TARGET_UNKNOWN";
1421 case 0x80090304: return "SEC_E_INTERNAL_ERROR";
1422 case 0x80090305: return "SEC_E_SECPKG_NOT_FOUND";
1423 case 0x80090306: return "SEC_E_NOT_OWNER";
1424 case 0x80090307: return "SEC_E_CANNOT_INSTALL";
1425 case 0x80090308: return "SEC_E_INVALID_TOKEN";
1426 case 0x80090309: return "SEC_E_CANNOT_PACK";
1427 case 0x8009030A: return "SEC_E_QOP_NOT_SUPPORTED";
1428 case 0x8009030B: return "SEC_E_NO_IMPERSONATION";
1429 case 0x8009030C: return "SEC_E_LOGON_DENIED";
1430 case 0x8009030D: return "SEC_E_UNKNOWN_CREDENTIALS";
1431 case 0x8009030E: return "SEC_E_NO_CREDENTIALS";
1432 case 0x8009030F: return "SEC_E_MESSAGE_ALTERED";
1433 case 0x80090310: return "SEC_E_OUT_OF_SEQUENCE";
1434 case 0x80090311: return "SEC_E_NO_AUTHENTICATING_AUTHORITY";
1435 case 0x00090312: return "SEC_I_CONTINUE_NEEDED";
1436 case 0x00090313: return "SEC_I_COMPLETE_NEEDED";
1437 case 0x00090314: return "SEC_I_COMPLETE_AND_CONTINUE";
1438 case 0x00090315: return "SEC_I_LOCAL_LOGON";
1439 case 0x80090316: return "SEC_E_BAD_PKGID";
1440 case 0x80090317: return "SEC_E_CONTEXT_EXPIRED";
1441 case 0x00090317: return "SEC_I_CONTEXT_EXPIRED";
1442 case 0x80090318: return "SEC_E_INCOMPLETE_MESSAGE";
1443 case 0x80090320: return "SEC_E_INCOMPLETE_CREDENTIALS";
1444 case 0x80090321: return "SEC_E_BUFFER_TOO_SMALL";
1445 case 0x00090320: return "SEC_I_INCOMPLETE_CREDENTIALS";
1446 case 0x00090321: return "SEC_I_RENEGOTIATE";
1447 case 0x80090322: return "SEC_E_WRONG_PRINCIPAL";
1448 case 0x00090323: return "SEC_I_NO_LSA_CONTEXT";
1449 case 0x80090324: return "SEC_E_TIME_SKEW";
1450 case 0x80090325: return "SEC_E_UNTRUSTED_ROOT";
1451 case 0x80090326: return "SEC_E_ILLEGAL_MESSAGE";
1452 case 0x80090327: return "SEC_E_CERT_UNKNOWN";
1453 case 0x80090328: return "SEC_E_CERT_EXPIRED";
1454 case 0x80090329: return "SEC_E_ENCRYPT_FAILURE";
1455 case 0x80090330: return "SEC_E_DECRYPT_FAILURE";
1456 case 0x80090331: return "SEC_E_ALGORITHM_MISMATCH";
1457 case 0x80090332: return "SEC_E_SECURITY_QOS_FAILED";
1458 case 0x80090333: return "SEC_E_UNFINISHED_CONTEXT_DELETED";
1459 case 0x80090334: return "SEC_E_NO_TGT_REPLY";
1460 case 0x80090335: return "SEC_E_NO_IP_ADDRESSES";
1461 case 0x80090336: return "SEC_E_WRONG_CREDENTIAL_HANDLE";
1462 case 0x80090337: return "SEC_E_CRYPTO_SYSTEM_INVALID";
1463 case 0x80090338: return "SEC_E_MAX_REFERRALS_EXCEEDED";
1464 case 0x80090339: return "SEC_E_MUST_BE_KDC";
1465 case 0x8009033A: return "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED";
1466 case 0x8009033B: return "SEC_E_TOO_MANY_PRINCIPALS";
1467 case 0x8009033C: return "SEC_E_NO_PA_DATA";
1468 case 0x8009033D: return "SEC_E_PKINIT_NAME_MISMATCH";
1469 case 0x8009033E: return "SEC_E_SMARTCARD_LOGON_REQUIRED";
1470 case 0x8009033F: return "SEC_E_SHUTDOWN_IN_PROGRESS";
1471 case 0x80090340: return "SEC_E_KDC_INVALID_REQUEST";
1472 case 0x80090341: return "SEC_E_KDC_UNABLE_TO_REFER";
1473 case 0x80090342: return "SEC_E_KDC_UNKNOWN_ETYPE";
1474 case 0x80090343: return "SEC_E_UNSUPPORTED_PREAUTH";
1475 case 0x80090345: return "SEC_E_DELEGATION_REQUIRED";
1476 case 0x80090346: return "SEC_E_BAD_BINDINGS";
1477 case 0x80090347: return "SEC_E_MULTIPLE_ACCOUNTS";
1478 case 0x80090348: return "SEC_E_NO_KERB_KEY";
1479 case 0x80091001: return "CRYPT_E_MSG_ERROR";
1480 case 0x80091002: return "CRYPT_E_UNKNOWN_ALGO";
1481 case 0x80091003: return "CRYPT_E_OID_FORMAT";
1482 case 0x80091004: return "CRYPT_E_INVALID_MSG_TYPE";
1483 case 0x80091005: return "CRYPT_E_UNEXPECTED_ENCODING";
1484 case 0x80091006: return "CRYPT_E_AUTH_ATTR_MISSING";
1485 case 0x80091007: return "CRYPT_E_HASH_VALUE";
1486 case 0x80091008: return "CRYPT_E_INVALID_INDEX";
1487 case 0x80091009: return "CRYPT_E_ALREADY_DECRYPTED";
1488 case 0x8009100A: return "CRYPT_E_NOT_DECRYPTED";
1489 case 0x8009100B: return "CRYPT_E_RECIPIENT_NOT_FOUND";
1490 case 0x8009100C: return "CRYPT_E_CONTROL_TYPE";
1491 case 0x8009100D: return "CRYPT_E_ISSUER_SERIALNUMBER";
1492 case 0x8009100E: return "CRYPT_E_SIGNER_NOT_FOUND";
1493 case 0x8009100F: return "CRYPT_E_ATTRIBUTES_MISSING";
1494 case 0x80091010: return "CRYPT_E_STREAM_MSG_NOT_READY";
1495 case 0x80091011: return "CRYPT_E_STREAM_INSUFFICIENT_DATA";
1496 case 0x00091012: return "CRYPT_I_NEW_PROTECTION_REQUIRED";
1497 case 0x80092001: return "CRYPT_E_BAD_LEN";
1498 case 0x80092002: return "CRYPT_E_BAD_ENCODE";
1499 case 0x80092003: return "CRYPT_E_FILE_ERROR";
1500 case 0x80092004: return "CRYPT_E_NOT_FOUND";
1501 case 0x80092005: return "CRYPT_E_EXISTS";
1502 case 0x80092006: return "CRYPT_E_NO_PROVIDER";
1503 case 0x80092007: return "CRYPT_E_SELF_SIGNED";
1504 case 0x80092008: return "CRYPT_E_DELETED_PREV";
1505 case 0x80092009: return "CRYPT_E_NO_MATCH";
1506 case 0x8009200A: return "CRYPT_E_UNEXPECTED_MSG_TYPE";
1507 case 0x8009200B: return "CRYPT_E_NO_KEY_PROPERTY";
1508 case 0x8009200C: return "CRYPT_E_NO_DECRYPT_CERT";
1509 case 0x8009200D: return "CRYPT_E_BAD_MSG";
1510 case 0x8009200E: return "CRYPT_E_NO_SIGNER";
1511 case 0x8009200F: return "CRYPT_E_PENDING_CLOSE";
1512 case 0x80092010: return "CRYPT_E_REVOKED";
1513 case 0x80092011: return "CRYPT_E_NO_REVOCATION_DLL";
1514 case 0x80092012: return "CRYPT_E_NO_REVOCATION_CHECK";
1515 case 0x80092013: return "CRYPT_E_REVOCATION_OFFLINE";
1516 case 0x80092014: return "CRYPT_E_NOT_IN_REVOCATION_DATABASE";
1517 case 0x80092020: return "CRYPT_E_INVALID_NUMERIC_STRING";
1518 case 0x80092021: return "CRYPT_E_INVALID_PRINTABLE_STRING";
1519 case 0x80092022: return "CRYPT_E_INVALID_IA5_STRING";
1520 case 0x80092023: return "CRYPT_E_INVALID_X500_STRING";
1521 case 0x80092024: return "CRYPT_E_NOT_CHAR_STRING";
1522 case 0x80092025: return "CRYPT_E_FILERESIZED";
1523 case 0x80092026: return "CRYPT_E_SECURITY_SETTINGS";
1524 case 0x80092027: return "CRYPT_E_NO_VERIFY_USAGE_DLL";
1525 case 0x80092028: return "CRYPT_E_NO_VERIFY_USAGE_CHECK";
1526 case 0x80092029: return "CRYPT_E_VERIFY_USAGE_OFFLINE";
1527 case 0x8009202A: return "CRYPT_E_NOT_IN_CTL";
1528 case 0x8009202B: return "CRYPT_E_NO_TRUSTED_SIGNER";
1529 case 0x8009202C: return "CRYPT_E_MISSING_PUBKEY_PARA";
1530 case 0x80093000: return "CRYPT_E_OSS_ERROR";
1531 case 0x80093001: return "OSS_MORE_BUF";
1532 case 0x80093002: return "OSS_NEGATIVE_UINTEGER";
1533 case 0x80093003: return "OSS_PDU_RANGE";
1534 case 0x80093004: return "OSS_MORE_INPUT";
1535 case 0x80093005: return "OSS_DATA_ERROR";
1536 case 0x80093006: return "OSS_BAD_ARG";
1537 case 0x80093007: return "OSS_BAD_VERSION";
1538 case 0x80093008: return "OSS_OUT_MEMORY";
1539 case 0x80093009: return "OSS_PDU_MISMATCH";
1540 case 0x8009300A: return "OSS_LIMITED";
1541 case 0x8009300B: return "OSS_BAD_PTR";
1542 case 0x8009300C: return "OSS_BAD_TIME";
1543 case 0x8009300D: return "OSS_INDEFINITE_NOT_SUPPORTED";
1544 case 0x8009300E: return "OSS_MEM_ERROR";
1545 case 0x8009300F: return "OSS_BAD_TABLE";
1546 case 0x80093010: return "OSS_TOO_LONG";
1547 case 0x80093011: return "OSS_CONSTRAINT_VIOLATED";
1548 case 0x80093012: return "OSS_FATAL_ERROR";
1549 case 0x80093013: return "OSS_ACCESS_SERIALIZATION_ERROR";
1550 case 0x80093014: return "OSS_NULL_TBL";
1551 case 0x80093015: return "OSS_NULL_FCN";
1552 case 0x80093016: return "OSS_BAD_ENCRULES";
1553 case 0x80093017: return "OSS_UNAVAIL_ENCRULES";
1554 case 0x80093018: return "OSS_CANT_OPEN_TRACE_WINDOW";
1555 case 0x80093019: return "OSS_UNIMPLEMENTED";
1556 case 0x8009301A: return "OSS_OID_DLL_NOT_LINKED";
1557 case 0x8009301B: return "OSS_CANT_OPEN_TRACE_FILE";
1558 case 0x8009301C: return "OSS_TRACE_FILE_ALREADY_OPEN";
1559 case 0x8009301D: return "OSS_TABLE_MISMATCH";
1560 case 0x8009301E: return "OSS_TYPE_NOT_SUPPORTED";
1561 case 0x8009301F: return "OSS_REAL_DLL_NOT_LINKED";
1562 case 0x80093020: return "OSS_REAL_CODE_NOT_LINKED";
1563 case 0x80093021: return "OSS_OUT_OF_RANGE";
1564 case 0x80093022: return "OSS_COPIER_DLL_NOT_LINKED";
1565 case 0x80093023: return "OSS_CONSTRAINT_DLL_NOT_LINKED";
1566 case 0x80093024: return "OSS_COMPARATOR_DLL_NOT_LINKED";
1567 case 0x80093025: return "OSS_COMPARATOR_CODE_NOT_LINKED";
1568 case 0x80093026: return "OSS_MEM_MGR_DLL_NOT_LINKED";
1569 case 0x80093027: return "OSS_PDV_DLL_NOT_LINKED";
1570 case 0x80093028: return "OSS_PDV_CODE_NOT_LINKED";
1571 case 0x80093029: return "OSS_API_DLL_NOT_LINKED";
1572 case 0x8009302A: return "OSS_BERDER_DLL_NOT_LINKED";
1573 case 0x8009302B: return "OSS_PER_DLL_NOT_LINKED";
1574 case 0x8009302C: return "OSS_OPEN_TYPE_ERROR";
1575 case 0x8009302D: return "OSS_MUTEX_NOT_CREATED";
1576 case 0x8009302E: return "OSS_CANT_CLOSE_TRACE_FILE";
1577 case 0x80093100: return "CRYPT_E_ASN1_ERROR";
1578 case 0x80093101: return "CRYPT_E_ASN1_INTERNAL";
1579 case 0x80093102: return "CRYPT_E_ASN1_EOD";
1580 case 0x80093103: return "CRYPT_E_ASN1_CORRUPT";
1581 case 0x80093104: return "CRYPT_E_ASN1_LARGE";
1582 case 0x80093105: return "CRYPT_E_ASN1_CONSTRAINT";
1583 case 0x80093106: return "CRYPT_E_ASN1_MEMORY";
1584 case 0x80093107: return "CRYPT_E_ASN1_OVERFLOW";
1585 case 0x80093108: return "CRYPT_E_ASN1_BADPDU";
1586 case 0x80093109: return "CRYPT_E_ASN1_BADARGS";
1587 case 0x8009310A: return "CRYPT_E_ASN1_BADREAL";
1588 case 0x8009310B: return "CRYPT_E_ASN1_BADTAG";
1589 case 0x8009310C: return "CRYPT_E_ASN1_CHOICE";
1590 case 0x8009310D: return "CRYPT_E_ASN1_RULE";
1591 case 0x8009310E: return "CRYPT_E_ASN1_UTF8";
1592 case 0x80093133: return "CRYPT_E_ASN1_PDU_TYPE";
1593 case 0x80093134: return "CRYPT_E_ASN1_NYI";
1594 case 0x80093201: return "CRYPT_E_ASN1_EXTENDED";
1595 case 0x80093202: return "CRYPT_E_ASN1_NOEOD";
1596 case 0x80094001: return "CERTSRV_E_BAD_REQUESTSUBJECT";
1597 case 0x80094002: return "CERTSRV_E_NO_REQUEST";
1598 case 0x80094003: return "CERTSRV_E_BAD_REQUESTSTATUS";
1599 case 0x80094004: return "CERTSRV_E_PROPERTY_EMPTY";
1600 case 0x80094005: return "CERTSRV_E_INVALID_CA_CERTIFICATE";
1601 case 0x80094006: return "CERTSRV_E_SERVER_SUSPENDED";
1602 case 0x80094007: return "CERTSRV_E_ENCODING_LENGTH";
1603 case 0x80094008: return "CERTSRV_E_ROLECONFLICT";
1604 case 0x80094009: return "CERTSRV_E_RESTRICTEDOFFICER";
1605 case 0x8009400A: return "CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED";
1606 case 0x8009400B: return "CERTSRV_E_NO_VALID_KRA";
1607 case 0x8009400C: return "CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL";
1608 case 0x80094800: return "CERTSRV_E_UNSUPPORTED_CERT_TYPE";
1609 case 0x80094801: return "CERTSRV_E_NO_CERT_TYPE";
1610 case 0x80094802: return "CERTSRV_E_TEMPLATE_CONFLICT";
1611 case 0x80096001: return "TRUST_E_SYSTEM_ERROR";
1612 case 0x80096002: return "TRUST_E_NO_SIGNER_CERT";
1613 case 0x80096003: return "TRUST_E_COUNTER_SIGNER";
1614 case 0x80096004: return "TRUST_E_CERT_SIGNATURE";
1615 case 0x80096005: return "TRUST_E_TIME_STAMP";
1616 case 0x80096010: return "TRUST_E_BAD_DIGEST";
1617 case 0x80096019: return "TRUST_E_BASIC_CONSTRAINTS";
1618 case 0x8009601E: return "TRUST_E_FINANCIAL_CRITERIA";
1619 case 0x80097001: return "MSSIPOTF_E_OUTOFMEMRANGE";
1620 case 0x80097002: return "MSSIPOTF_E_CANTGETOBJECT";
1621 case 0x80097003: return "MSSIPOTF_E_NOHEADTABLE";
1622 case 0x80097004: return "MSSIPOTF_E_BAD_MAGICNUMBER";
1623 case 0x80097005: return "MSSIPOTF_E_BAD_OFFSET_TABLE";
1624 case 0x80097006: return "MSSIPOTF_E_TABLE_TAGORDER";
1625 case 0x80097007: return "MSSIPOTF_E_TABLE_LONGWORD";
1626 case 0x80097008: return "MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT";
1627 case 0x80097009: return "MSSIPOTF_E_TABLES_OVERLAP";
1628 case 0x8009700A: return "MSSIPOTF_E_TABLE_PADBYTES";
1629 case 0x8009700B: return "MSSIPOTF_E_FILETOOSMALL";
1630 case 0x8009700C: return "MSSIPOTF_E_TABLE_CHECKSUM";
1631 case 0x8009700D: return "MSSIPOTF_E_FILE_CHECKSUM";
1632 case 0x80097010: return "MSSIPOTF_E_FAILED_POLICY";
1633 case 0x80097011: return "MSSIPOTF_E_FAILED_HINTS_CHECK";
1634 case 0x80097012: return "MSSIPOTF_E_NOT_OPENTYPE";
1635 case 0x80097013: return "MSSIPOTF_E_FILE";
1636 case 0x80097014: return "MSSIPOTF_E_CRYPT";
1637 case 0x80097015: return "MSSIPOTF_E_BADVERSION";
1638 case 0x80097016: return "MSSIPOTF_E_DSIG_STRUCTURE";
1639 case 0x80097017: return "MSSIPOTF_E_PCONST_CHECK";
1640 case 0x80097018: return "MSSIPOTF_E_STRUCTURE";
1641 case 0x800B0001: return "TRUST_E_PROVIDER_UNKNOWN";
1642 case 0x800B0002: return "TRUST_E_ACTION_UNKNOWN";
1643 case 0x800B0003: return "TRUST_E_SUBJECT_FORM_UNKNOWN";
1644 case 0x800B0004: return "TRUST_E_SUBJECT_NOT_TRUSTED";
1645 case 0x800B0005: return "DIGSIG_E_ENCODE";
1646 case 0x800B0006: return "DIGSIG_E_DECODE";
1647 case 0x800B0007: return "DIGSIG_E_EXTENSIBILITY";
1648 case 0x800B0008: return "DIGSIG_E_CRYPTO";
1649 case 0x800B0009: return "PERSIST_E_SIZEDEFINITE";
1650 case 0x800B000A: return "PERSIST_E_SIZEINDEFINITE";
1651 case 0x800B000B: return "PERSIST_E_NOTSELFSIZING";
1652 case 0x800B0100: return "TRUST_E_NOSIGNATURE";
1653 case 0x800B0101: return "CERT_E_EXPIRED";
1654 case 0x800B0102: return "CERT_E_VALIDITYPERIODNESTING";
1655 case 0x800B0103: return "CERT_E_ROLE";
1656 case 0x800B0104: return "CERT_E_PATHLENCONST";
1657 case 0x800B0105: return "CERT_E_CRITICAL";
1658 case 0x800B0106: return "CERT_E_PURPOSE";
1659 case 0x800B0107: return "CERT_E_ISSUERCHAINING";
1660 case 0x800B0108: return "CERT_E_MALFORMED";
1661 case 0x800B0109: return "CERT_E_UNTRUSTEDROOT";
1662 case 0x800B010A: return "CERT_E_CHAINING";
1663 case 0x800B010B: return "TRUST_E_FAIL";
1664 case 0x800B010C: return "CERT_E_REVOKED";
1665 case 0x800B010D: return "CERT_E_UNTRUSTEDTESTROOT";
1666 case 0x800B010E: return "CERT_E_REVOCATION_FAILURE";
1667 case 0x800B010F: return "CERT_E_CN_NO_MATCH";
1668 case 0x800B0110: return "CERT_E_WRONG_USAGE";
1669 case 0x800B0111: return "TRUST_E_EXPLICIT_DISTRUST";
1670 case 0x800B0112: return "CERT_E_UNTRUSTEDCA";
1671 case 0x800B0113: return "CERT_E_INVALID_POLICY";
1672 case 0x800B0114: return "CERT_E_INVALID_NAME";
1674 return String.Format("0x{0:x} [{1}]", statusCode, statusCode);
1677 static readonly string[] InputContextAttributes = {
1678 "ISC_REQ_DELEGATE", // 0x00000001
1679 "ISC_REQ_MUTUAL_AUTH", // 0x00000002
1680 "ISC_REQ_REPLAY_DETECT", // 0x00000004
1681 "ISC_REQ_SEQUENCE_DETECT", // 0x00000008
1682 "ISC_REQ_CONFIDENTIALITY", // 0x00000010
1683 "ISC_REQ_USE_SESSION_KEY", // 0x00000020
1684 "ISC_REQ_PROMPT_FOR_CREDS", // 0x00000040
1685 "ISC_REQ_USE_SUPPLIED_CREDS", // 0x00000080
1686 "ISC_REQ_ALLOCATE_MEMORY", // 0x00000100
1687 "ISC_REQ_USE_DCE_STYLE", // 0x00000200
1688 "ISC_REQ_DATAGRAM", // 0x00000400
1689 "ISC_REQ_CONNECTION", // 0x00000800
1690 "ISC_REQ_CALL_LEVEL", // 0x00001000
1691 "ISC_REQ_FRAGMENT_SUPPLIED", // 0x00002000
1692 "ISC_REQ_EXTENDED_ERROR", // 0x00004000
1693 "ISC_REQ_STREAM", // 0x00008000
1694 "ISC_REQ_INTEGRITY", // 0x00010000
1695 "ISC_REQ_IDENTIFY", // 0x00020000
1696 "ISC_REQ_NULL_SESSION", // 0x00040000
1697 "ISC_REQ_MANUAL_CRED_VALIDATION", // 0x00080000
1698 "ISC_REQ_RESERVED1", // 0x00100000
1699 "ISC_REQ_FRAGMENT_TO_FIT", // 0x00200000
1712 static readonly string[] OutputContextAttributes = {
1713 "ISC_RET_DELEGATE", // 0x00000001
1714 "ISC_RET_MUTUAL_AUTH", // 0x00000002
1715 "ISC_RET_REPLAY_DETECT", // 0x00000004
1716 "ISC_RET_SEQUENCE_DETECT", // 0x00000008
1717 "ISC_RET_CONFIDENTIALITY", // 0x00000010
1718 "ISC_RET_USE_SESSION_KEY", // 0x00000020
1719 "ISC_RET_USED_COLLECTED_CREDS", // 0x00000040
1720 "ISC_RET_USED_SUPPLIED_CREDS", // 0x00000080
1721 "ISC_RET_ALLOCATED_MEMORY", // 0x00000100
1722 "ISC_RET_USED_DCE_STYLE", // 0x00000200
1723 "ISC_RET_DATAGRAM", // 0x00000400
1724 "ISC_RET_CONNECTION", // 0x00000800
1725 "ISC_RET_INTERMEDIATE_RETURN", // 0x00001000
1726 "ISC_RET_CALL_LEVEL", // 0x00002000
1727 "ISC_RET_EXTENDED_ERROR", // 0x00004000
1728 "ISC_RET_STREAM", // 0x00008000
1729 "ISC_RET_INTEGRITY", // 0x00010000
1730 "ISC_RET_IDENTIFY", // 0x00020000
1731 "ISC_RET_NULL_SESSION", // 0x00040000
1732 "ISC_RET_MANUAL_CRED_VALIDATION", // 0x00080000
1733 "ISC_RET_RESERVED1", // 0x00100000
1734 "ISC_RET_FRAGMENT_ONLY", // 0x00200000
1748 // Consider removing.
1749 internal static string MapInputContextAttributes(int attributes) {
1750 return ContextAttributeMapper(attributes, InputContextAttributes);
1753 internal static string MapOutputContextAttributes(int attributes) {
1754 return ContextAttributeMapper(attributes, OutputContextAttributes);
1757 internal static string ContextAttributeMapper(int attributes, string[] attributeNames) {
1762 bool haveResult = false;
1764 while (attributes != 0) {
1765 if ((attributes & bit) != 0) {
1770 result += attributeNames[index];
1780 [System.Diagnostics.Conditional("DEBUG")]
1781 internal void DebugMembers() {
1782 GlobalLog.Print("m_Destination =" + m_Destination);
1783 GlobalLog.Print("m_ClientCertificates =" + m_ClientCertificates);
1784 GlobalLog.Print("m_ServerCertificate =" + m_ServerCertificate);
1785 GlobalLog.Print("m_Attributes =" + m_Attributes);
1791 // ProtocolToken - used to process and handle the return codes
1792 // from the SSPI wrapper
1795 class ProtocolToken {
1796 internal SecurityStatus Status;
1797 internal byte[] Payload;
1800 internal bool Failed {
1802 return ((Status != SecurityStatus.OK) && (Status != SecurityStatus.ContinueNeeded));
1806 internal bool Done {
1808 return (Status == SecurityStatus.OK);
1812 internal bool Renegotiate {
1814 return (Status == SecurityStatus.Renegotiate);
1818 internal bool CloseConnection {
1820 return (Status == SecurityStatus.ContextExpired);
1824 internal ProtocolToken(byte[] data, SecurityStatus errorCode) {
1827 Size = data!=null ? data.Length : 0;
1830 internal Win32Exception GetException() {
1831 // if it's not done, then there's got to be an error, even if it's
1832 // a Handshake message up, and we only have a Warning message.
1833 return this.Done ? null : new Win32Exception((int)Status);
1837 public override string ToString() {
1838 return "Status="+Status.ToString() + ", data size="+Size;