Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / IdentityModel / System / IdentityModel / Selectors / X509CertificateChain.cs / 1305376 / X509CertificateChain.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.IdentityModel.Selectors { using System.IdentityModel.Tokens; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; // Most of codes are copied from \ndp\fx\src\security\system\security\cryptography\x509\X509Chain.cs class X509CertificateChain { public const uint DefaultChainPolicyOID = CAPI.CERT_CHAIN_POLICY_BASE; bool useMachineContext; X509ChainPolicy chainPolicy; uint chainPolicyOID = X509CertificateChain.DefaultChainPolicyOID; public X509CertificateChain() : this(false) { } public X509CertificateChain(bool useMachineContext) { this.useMachineContext = useMachineContext; } public X509CertificateChain(bool useMachineContext, uint chainPolicyOID) { this.useMachineContext = useMachineContext; // One of the condition to pass NT_AUTH is the issuer of the cert must be trusted by NT auth. // Simply add to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EnterpriseCertificates\NTAuth\Certificates this.chainPolicyOID = chainPolicyOID; } public X509ChainPolicy ChainPolicy { get { if (this.chainPolicy == null) { this.chainPolicy = new X509ChainPolicy(); } return this.chainPolicy; } set { this.chainPolicy = value; } } public X509ChainStatus[] ChainStatus { #pragma warning suppress 56503 get { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } } // There are 2 steps in chain validation. // 1) BuildChain by calling CAPI.CertGetCertificateChain. The result is // the chain context containing the chain and status. // 2) VerifyChain by calling CAPI.CertVerifyCertificateChainPolicy. // Refer to MB50916, Since Vista out-of-the-box will trust the chain with PeerTrust, // we include the flag to ignore PeerTrust for CAPI.CertVerifyCertificateChainPolicy. public bool Build(X509Certificate2 certificate) { if (certificate == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("certificate"); if (certificate.Handle == IntPtr.Zero) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("certificate", SR.GetString(SR.ArgumentInvalidCertificate)); SafeCertChainHandle safeCertChainHandle = SafeCertChainHandle.InvalidHandle; X509ChainPolicy chainPolicy = this.ChainPolicy; chainPolicy.VerificationTime = DateTime.Now; BuildChain(this.useMachineContext ? new IntPtr(CAPI.HCCE_LOCAL_MACHINE) : new IntPtr(CAPI.HCCE_CURRENT_USER), certificate.Handle, chainPolicy.ExtraStore, chainPolicy.ApplicationPolicy, chainPolicy.CertificatePolicy, chainPolicy.RevocationMode, chainPolicy.RevocationFlag, chainPolicy.VerificationTime, chainPolicy.UrlRetrievalTimeout, out safeCertChainHandle); // Verify the chain using the specified policy. CAPI.CERT_CHAIN_POLICY_PARA PolicyPara = new CAPI.CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CAPI.CERT_CHAIN_POLICY_PARA))); CAPI.CERT_CHAIN_POLICY_STATUS PolicyStatus = new CAPI.CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CAPI.CERT_CHAIN_POLICY_STATUS))); // Ignore peertrust. Peer trust caused the chain to succeed out-of-the-box in Vista. // This new flag is only available in Vista. PolicyPara.dwFlags = (uint)chainPolicy.VerificationFlags | CAPI.CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG; if (!CAPI.CertVerifyCertificateChainPolicy(new IntPtr(this.chainPolicyOID), safeCertChainHandle, ref PolicyPara, ref PolicyStatus)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } if (PolicyStatus.dwError != CAPI.S_OK) { int error = (int)PolicyStatus.dwError; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenValidationException(SR.GetString(SR.X509ChainBuildFail, SecurityUtils.GetCertificateId(certificate), new CryptographicException(error).Message))); } return true; } static unsafe void BuildChain(IntPtr hChainEngine, IntPtr pCertContext, X509Certificate2Collection extraStore, OidCollection applicationPolicy, OidCollection certificatePolicy, X509RevocationMode revocationMode, X509RevocationFlag revocationFlag, DateTime verificationTime, TimeSpan timeout, out SafeCertChainHandle ppChainContext) { SafeCertStoreHandle hCertStore = ExportToMemoryStore(extraStore, pCertContext); CAPI.CERT_CHAIN_PARA ChainPara = new CAPI.CERT_CHAIN_PARA(); ChainPara.cbSize = (uint)Marshal.SizeOf(typeof(CAPI.CERT_CHAIN_PARA)); // Application policy SafeHGlobalHandle applicationPolicyHandle = SafeHGlobalHandle.InvalidHandle; SafeHGlobalHandle certificatePolicyHandle = SafeHGlobalHandle.InvalidHandle; try { if (applicationPolicy != null && applicationPolicy.Count > 0) { ChainPara.RequestedUsage.dwType = CAPI.USAGE_MATCH_TYPE_AND; ChainPara.RequestedUsage.Usage.cUsageIdentifier = (uint)applicationPolicy.Count; applicationPolicyHandle = CopyOidsToUnmanagedMemory(applicationPolicy); ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = applicationPolicyHandle.DangerousGetHandle(); } // Certificate policy if (certificatePolicy != null && certificatePolicy.Count > 0) { ChainPara.RequestedIssuancePolicy.dwType = CAPI.USAGE_MATCH_TYPE_AND; ChainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier = (uint)certificatePolicy.Count; certificatePolicyHandle = CopyOidsToUnmanagedMemory(certificatePolicy); ChainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = certificatePolicyHandle.DangerousGetHandle(); } ChainPara.dwUrlRetrievalTimeout = (uint)timeout.Milliseconds; FILETIME ft = new FILETIME(); *((long*)&ft) = verificationTime.ToFileTime(); uint flags = MapRevocationFlags(revocationMode, revocationFlag); // Build the chain. if (!CAPI.CertGetCertificateChain(hChainEngine, pCertContext, ref ft, hCertStore, ref ChainPara, flags, IntPtr.Zero, out ppChainContext)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } } finally { if (applicationPolicyHandle != null) applicationPolicyHandle.Dispose(); if (certificatePolicyHandle != null) certificatePolicyHandle.Dispose(); hCertStore.Close(); } } static SafeCertStoreHandle ExportToMemoryStore(X509Certificate2Collection collection, IntPtr pCertContext) { CAPI.CERT_CONTEXT certContext = (CAPI.CERT_CONTEXT)Marshal.PtrToStructure(pCertContext, typeof(CAPI.CERT_CONTEXT)); // No extra store nor intermediate certificates if ((collection == null || collection.Count <= 0) && certContext.hCertStore == IntPtr.Zero) { return SafeCertStoreHandle.InvalidHandle; } // we always want to use CERT_STORE_ENUM_ARCHIVED_FLAG since we want to preserve the collection in this operation. // By default, Archived certificates will not be included. SafeCertStoreHandle certStoreHandle = CAPI.CertOpenStore(new IntPtr(CAPI.CERT_STORE_PROV_MEMORY), CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, IntPtr.Zero, CAPI.CERT_STORE_ENUM_ARCHIVED_FLAG | CAPI.CERT_STORE_CREATE_NEW_FLAG, null); if (certStoreHandle == null || certStoreHandle.IsInvalid) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } // // We use CertAddCertificateLinkToStore to keep a link to the original store, so any property changes get // applied to the original store. This has a limit of 99 links per cert context however. // // Add extra store if (collection != null && collection.Count > 0) { foreach (X509Certificate2 x509 in collection) { if (!CAPI.CertAddCertificateLinkToStore(certStoreHandle, x509.Handle, CAPI.CERT_STORE_ADD_ALWAYS, SafeCertContextHandle.InvalidHandle)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } } } // Add intermediates if (certContext.hCertStore != IntPtr.Zero) { X509Store store = new X509Store(certContext.hCertStore); X509Certificate2Collection intermediates = null; try { intermediates = store.Certificates; foreach (X509Certificate2 x509 in intermediates) { if (!CAPI.CertAddCertificateLinkToStore(certStoreHandle, x509.Handle, CAPI.CERT_STORE_ADD_ALWAYS, SafeCertContextHandle.InvalidHandle)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } } } finally { SecurityUtils.ResetAllCertificates(intermediates); store.Close(); } } return certStoreHandle; } static SafeHGlobalHandle CopyOidsToUnmanagedMemory(OidCollection oids) { SafeHGlobalHandle safeAllocHandle = SafeHGlobalHandle.InvalidHandle; if (oids == null || oids.Count == 0) return safeAllocHandle; int ptrSize = oids.Count * Marshal.SizeOf(typeof(IntPtr)); int oidSize = 0; foreach (Oid oid in oids) { oidSize += (oid.Value.Length + 1); } safeAllocHandle = SafeHGlobalHandle.AllocHGlobal(ptrSize + oidSize); IntPtr pOid = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + ptrSize); for (int index = 0; index < oids.Count; index++) { Marshal.WriteIntPtr(new IntPtr((long)safeAllocHandle.DangerousGetHandle() + index * Marshal.SizeOf(typeof(IntPtr))), pOid); byte[] ansiOid = Encoding.ASCII.GetBytes(oids[index].Value); Marshal.Copy(ansiOid, 0, pOid, ansiOid.Length); pOid = new IntPtr((long)pOid + oids[index].Value.Length + 1); } return safeAllocHandle; } static uint MapRevocationFlags(X509RevocationMode revocationMode, X509RevocationFlag revocationFlag) { uint dwFlags = 0; if (revocationMode == X509RevocationMode.NoCheck) return dwFlags; if (revocationMode == X509RevocationMode.Offline) dwFlags |= CAPI.CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; if (revocationFlag == X509RevocationFlag.EndCertificateOnly) dwFlags |= CAPI.CERT_CHAIN_REVOCATION_CHECK_END_CERT; else if (revocationFlag == X509RevocationFlag.EntireChain) dwFlags |= CAPI.CERT_CHAIN_REVOCATION_CHECK_CHAIN; else dwFlags |= CAPI.CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; return dwFlags; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataRelationCollection.cs
- PerformanceCounterCategory.cs
- mda.cs
- Deserializer.cs
- DummyDataSource.cs
- BrowserCapabilitiesFactoryBase.cs
- PassportPrincipal.cs
- Point.cs
- dataobject.cs
- ResponseBodyWriter.cs
- EditBehavior.cs
- ApplicationHost.cs
- OperationAbortedException.cs
- EventData.cs
- DecoderReplacementFallback.cs
- AlphaSortedEnumConverter.cs
- RawStylusInputCustomDataList.cs
- ColorAnimationUsingKeyFrames.cs
- InheritedPropertyChangedEventArgs.cs
- CodeTypeMemberCollection.cs
- Connector.xaml.cs
- CultureSpecificStringDictionary.cs
- PopupRoot.cs
- XmlSecureResolver.cs
- AssertSection.cs
- TableAdapterManagerNameHandler.cs
- ToolboxComponentsCreatedEventArgs.cs
- WindowHideOrCloseTracker.cs
- ContainerParagraph.cs
- SettingsAttributeDictionary.cs
- ExpressionConverter.cs
- HttpWebResponse.cs
- TextSearch.cs
- MetadataItemEmitter.cs
- EventEntry.cs
- VolatileEnlistmentMultiplexing.cs
- HttpPostProtocolReflector.cs
- PolygonHotSpot.cs
- AttributeProviderAttribute.cs
- FontFamilyValueSerializer.cs
- LinqDataSourceStatusEventArgs.cs
- SpecialFolderEnumConverter.cs
- _LoggingObject.cs
- HebrewNumber.cs
- DefaultValidator.cs
- MissingFieldException.cs
- XsltArgumentList.cs
- IndicShape.cs
- TraceHandler.cs
- ContextProperty.cs
- CodeExpressionStatement.cs
- SmiMetaData.cs
- SqlCacheDependencyDatabaseCollection.cs
- ScrollableControl.cs
- OutputScopeManager.cs
- TileBrush.cs
- SamlSerializer.cs
- ValidationPropertyAttribute.cs
- ToolboxItem.cs
- DelegateSerializationHolder.cs
- TreeWalkHelper.cs
- EncodingDataItem.cs
- Point3DAnimationBase.cs
- Boolean.cs
- ObsoleteAttribute.cs
- WebPartMovingEventArgs.cs
- HtmlElementEventArgs.cs
- ExitEventArgs.cs
- DbRetry.cs
- SurrogateSelector.cs
- ExtendedProtectionPolicyElement.cs
- GeometryDrawing.cs
- LazyTextWriterCreator.cs
- FrameworkElementAutomationPeer.cs
- StreamUpdate.cs
- HostDesigntimeLicenseContext.cs
- WebPartEventArgs.cs
- XmlAttributeCache.cs
- HwndStylusInputProvider.cs
- externdll.cs
- PersonalizationStateInfoCollection.cs
- FontUnitConverter.cs
- ResourceSetExpression.cs
- JsonWriterDelegator.cs
- ProgressiveCrcCalculatingStream.cs
- ErrorFormatterPage.cs
- ExtenderControl.cs
- ValidatingPropertiesEventArgs.cs
- CollectionViewGroupInternal.cs
- MethodExecutor.cs
- DecimalSumAggregationOperator.cs
- RuntimeEnvironment.cs
- Table.cs
- ChannelEndpointElement.cs
- UInt16.cs
- TypedLocationWrapper.cs
- HandlerMappingMemo.cs
- HttpListenerException.cs
- EntityContainer.cs
- HttpPostedFileWrapper.cs