Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / IdentityModel / System / IdentityModel / Selectors / X509CertificateChain.cs / 1 / 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; 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. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ThrowHelper.cs
- GridViewCommandEventArgs.cs
- ReferenceConverter.cs
- _OverlappedAsyncResult.cs
- XmlSchemaObjectCollection.cs
- TrustManager.cs
- QueryStack.cs
- XmlDocument.cs
- AspProxy.cs
- ExtenderProvidedPropertyAttribute.cs
- ContentPresenter.cs
- _BaseOverlappedAsyncResult.cs
- Listbox.cs
- FontFamilyConverter.cs
- AliasGenerator.cs
- PrintController.cs
- ReaderWriterLockWrapper.cs
- SaveFileDialog.cs
- XmlSchemaObject.cs
- DBSqlParserColumnCollection.cs
- SQLGuid.cs
- EdgeModeValidation.cs
- OleDbRowUpdatingEvent.cs
- EntityDataSourceDataSelectionPanel.cs
- StaticTextPointer.cs
- BufferBuilder.cs
- Sentence.cs
- ToolboxItem.cs
- EditorZoneBase.cs
- DBSchemaTable.cs
- cache.cs
- HtmlInputHidden.cs
- WindowsFormsSectionHandler.cs
- BindableTemplateBuilder.cs
- GiveFeedbackEvent.cs
- WhereQueryOperator.cs
- BamlRecordReader.cs
- RefType.cs
- FrugalMap.cs
- LicenseManager.cs
- ScriptResourceInfo.cs
- ListBindingConverter.cs
- _CacheStreams.cs
- TransactionProtocol.cs
- MultiPageTextView.cs
- ResourceCodeDomSerializer.cs
- EntryIndex.cs
- DirectionalLight.cs
- HttpRawResponse.cs
- FormViewDeletedEventArgs.cs
- WebPartsSection.cs
- EastAsianLunisolarCalendar.cs
- CreateUserWizardStep.cs
- SQLString.cs
- Send.cs
- OleDbDataReader.cs
- TextDataBindingHandler.cs
- EventsTab.cs
- SequentialActivityDesigner.cs
- Win32MouseDevice.cs
- IOThreadTimer.cs
- RuntimeVariablesExpression.cs
- QilGenerator.cs
- HostedHttpTransportManager.cs
- WebPartCatalogCloseVerb.cs
- ToolboxControl.cs
- _NetRes.cs
- SelectionProviderWrapper.cs
- SplitContainer.cs
- ProgressBar.cs
- ColumnClickEvent.cs
- HtmlTableCellCollection.cs
- precedingsibling.cs
- DataGridBoolColumn.cs
- TypeInitializationException.cs
- GroupBoxAutomationPeer.cs
- IntegerValidator.cs
- FileInfo.cs
- FormViewInsertedEventArgs.cs
- RadioButtonFlatAdapter.cs
- ContravarianceAdapter.cs
- _TransmitFileOverlappedAsyncResult.cs
- OdbcInfoMessageEvent.cs
- CodeDomExtensionMethods.cs
- TypeHelpers.cs
- XmlCharacterData.cs
- PersonalizableTypeEntry.cs
- ListViewItem.cs
- CompModSwitches.cs
- WorkflowNamespace.cs
- SoapExtensionReflector.cs
- DbProviderFactoriesConfigurationHandler.cs
- HttpModule.cs
- MetadataItemSerializer.cs
- Quaternion.cs
- SecurityState.cs
- OracleInternalConnection.cs
- PrimitiveCodeDomSerializer.cs
- StructuredTypeInfo.cs
- HttpServerVarsCollection.cs