| File: System\Security\Cryptography\X509Certificates\CertificatePal.Windows.Import.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Runtime.InteropServices; using Internal.Cryptography; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography.X509Certificates { internal sealed partial class CertificatePal { internal static partial ICertificatePal FromBlob(ReadOnlySpan<byte> rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { return FromBlobOrFile(rawData, null, password, keyStorageFlags); } internal static partial ICertificatePal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { return FromBlobOrFile(ReadOnlySpan<byte>.Empty, fileName, password, keyStorageFlags); } private static CertificatePal FromBlobOrFile(ReadOnlySpan<byte> rawData, string? fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(!rawData.IsEmpty || fileName != null); Debug.Assert(password != null); bool loadFromFile = (fileName != null); bool deleteKeyContainer = false; Interop.Crypt32.ContentType contentType; SafeCertStoreHandle? hCertStore = null; SafeCryptMsgHandle? hCryptMsg = null; SafeCertContextHandle? pCertContext = null; try { unsafe { fixed (byte* pRawData = rawData) { fixed (char* pFileName = fileName) { Interop.Crypt32.DATA_BLOB certBlob = new Interop.Crypt32.DATA_BLOB(new IntPtr(pRawData), (uint)(loadFromFile ? 0 : rawData.Length)); Interop.Crypt32.CertQueryObjectType objectType = loadFromFile ? Interop.Crypt32.CertQueryObjectType.CERT_QUERY_OBJECT_FILE : Interop.Crypt32.CertQueryObjectType.CERT_QUERY_OBJECT_BLOB; void* pvObject = loadFromFile ? (void*)pFileName : (void*)&certBlob; bool success = Interop.Crypt32.CryptQueryObject( objectType, pvObject, X509ExpectedContentTypeFlags, X509ExpectedFormatTypeFlags, 0, out _, out contentType, out _, out hCertStore, out hCryptMsg, out pCertContext); if (!success) { int hr = Marshal.GetHRForLastWin32Error(); throw hr.ToCryptographicException(); } } } if (contentType == Interop.Crypt32.ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED || contentType == Interop.Crypt32.ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { pCertContext?.Dispose(); pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); } else if (contentType == Interop.Crypt32.ContentType.CERT_QUERY_CONTENT_PFX) { try { Pkcs12LoaderLimits limits = X509Certificate.GetPkcs12Limits(loadFromFile, password); if (loadFromFile) { Debug.Assert(fileName is not null); return (CertificatePal)X509CertificateLoader.LoadPkcs12PalFromFile( fileName, password.DangerousGetSpan(), keyStorageFlags, limits); } else { return (CertificatePal)X509CertificateLoader.LoadPkcs12Pal( rawData, password.DangerousGetSpan(), keyStorageFlags, limits); } } catch (Pkcs12LoadLimitExceededException e) { throw new CryptographicException( SR.Cryptography_X509_PfxWithoutPassword_MaxAllowedIterationsExceeded, e); } } CertificatePal pal = new CertificatePal(pCertContext, deleteKeyContainer); pCertContext = null; return pal; } } finally { hCertStore?.Dispose(); hCryptMsg?.Dispose(); pCertContext?.Dispose(); } } private static unsafe SafeCertContextHandle GetSignerInPKCS7Store(SafeCertStoreHandle hCertStore, SafeCryptMsgHandle hCryptMsg) { // make sure that there is at least one signer of the certificate store int dwSigners; int cbSigners = sizeof(int); if (!Interop.Crypt32.CryptMsgGetParam(hCryptMsg, Interop.Crypt32.CryptMsgParamType.CMSG_SIGNER_COUNT_PARAM, 0, out dwSigners, ref cbSigners)) throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); if (dwSigners == 0) throw ErrorCode.CRYPT_E_SIGNER_NOT_FOUND.ToCryptographicException(); // get the first signer from the store, and use that as the loaded certificate int cbData = 0; if (!Interop.Crypt32.CryptMsgGetParam(hCryptMsg, Interop.Crypt32.CryptMsgParamType.CMSG_SIGNER_INFO_PARAM, 0, default(byte*), ref cbData)) throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); fixed (byte* pCmsgSignerBytes = new byte[cbData]) { if (!Interop.Crypt32.CryptMsgGetParam(hCryptMsg, Interop.Crypt32.CryptMsgParamType.CMSG_SIGNER_INFO_PARAM, 0, pCmsgSignerBytes, ref cbData)) throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); CMSG_SIGNER_INFO_Partial* pCmsgSignerInfo = (CMSG_SIGNER_INFO_Partial*)pCmsgSignerBytes; Interop.Crypt32.CERT_INFO certInfo = default(Interop.Crypt32.CERT_INFO); certInfo.Issuer.cbData = pCmsgSignerInfo->Issuer.cbData; certInfo.Issuer.pbData = pCmsgSignerInfo->Issuer.pbData; certInfo.SerialNumber.cbData = pCmsgSignerInfo->SerialNumber.cbData; certInfo.SerialNumber.pbData = pCmsgSignerInfo->SerialNumber.pbData; SafeCertContextHandle? pCertContext = null; if (!Interop.crypt32.CertFindCertificateInStore(hCertStore, Interop.Crypt32.CertFindType.CERT_FIND_SUBJECT_CERT, &certInfo, ref pCertContext)) { Exception e = Marshal.GetHRForLastWin32Error().ToCryptographicException(); pCertContext.Dispose(); throw e; } return pCertContext; } } private const Interop.Crypt32.ExpectedContentTypeFlags X509ExpectedContentTypeFlags = Interop.Crypt32.ExpectedContentTypeFlags.CERT_QUERY_CONTENT_FLAG_CERT | Interop.Crypt32.ExpectedContentTypeFlags.CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT | Interop.Crypt32.ExpectedContentTypeFlags.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | Interop.Crypt32.ExpectedContentTypeFlags.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | Interop.Crypt32.ExpectedContentTypeFlags.CERT_QUERY_CONTENT_FLAG_PFX; private const Interop.Crypt32.ExpectedFormatTypeFlags X509ExpectedFormatTypeFlags = Interop.Crypt32.ExpectedFormatTypeFlags.CERT_QUERY_FORMAT_FLAG_ALL; } }