/// <summary> /// Accepts a CSR-like object to sign by another key /// </summary> /// <param name="request">The request to sign</param> /// <param name="CACert">The signing key</param> /// <returns>Returns a signed certificate</returns> public static X509Certificate2 SignCertificate(CertificateSigningRequest request, X509Certificate2 CACert) { IntPtr hCAProv = IntPtr.Zero; IntPtr hProvAllocPtr = IntPtr.Zero; IntPtr subordinateCertInfoAllocPtr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { // Get CA cert into CERT_CONTEXT // Get CA cert into CERT_INFO from context.pCertInfo NativeMethods.CERT_CONTEXT CAContext = (NativeMethods.CERT_CONTEXT)Marshal.PtrToStructure(CACert.Handle, typeof(NativeMethods.CERT_CONTEXT)); NativeMethods.CERT_INFO CACertInfo = (NativeMethods.CERT_INFO)Marshal.PtrToStructure(CAContext.pCertInfo, typeof(NativeMethods.CERT_INFO)); uint pcbData = 0; // get the context property handle of the CA Cert if (!NativeMethods.CertGetCertificateContextProperty(CACert.Handle, 2, hProvAllocPtr, ref pcbData)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } hProvAllocPtr = NativeMethods.LocalAlloc(0, new IntPtr((long)pcbData)); if (!NativeMethods.CertGetCertificateContextProperty(CACert.Handle, 2, hProvAllocPtr, ref pcbData)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } // get the key handle of the CA Cert NativeMethods.CRYPT_KEY_PROV_INFO pKeyInfo = (NativeMethods.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(hProvAllocPtr, typeof(NativeMethods.CRYPT_KEY_PROV_INFO)); // Acquire a context to the provider for crypto if (!NativeMethods.CryptAcquireContext(ref hCAProv, pKeyInfo.pwszContainerName, pKeyInfo.pwszProvName, pKeyInfo.dwProvType, pKeyInfo.dwFlags)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // Get subordinate cert into CERT_CONTEXT // Get subordinate cert into CERT_INFO from context.pCertInfo NativeMethods.CERT_CONTEXT subordinateCertContext = (NativeMethods.CERT_CONTEXT)Marshal.PtrToStructure(request.Certificate.Handle, typeof(NativeMethods.CERT_CONTEXT)); NativeMethods.CERT_INFO subordinateCertInfo = (NativeMethods.CERT_INFO)Marshal.PtrToStructure(subordinateCertContext.pCertInfo, typeof(NativeMethods.CERT_INFO)); NativeMethods.CRYPT_ALGORITHM_IDENTIFIER signatureAlgo = new NativeMethods.CRYPT_ALGORITHM_IDENTIFIER() { pszObjId = string.IsNullOrWhiteSpace(request.SignatureAlgorithm) ? NativeMethods.OID_RSA_SHA256RSA : request.SignatureAlgorithm }; // apply new issuer subordinateCertInfo.NotBefore = CertUtil.FileTimeFromDateTime(DateTime.UtcNow.AddHours(-1)); subordinateCertInfo.NotAfter = CertUtil.FileTimeFromDateTime(DateTime.UtcNow.Add(request.ExpirationLength)); var caExtensions = CertUtil.ConvertExtensions(request.Extensions)[0]; subordinateCertInfo.cExtension = request.Extensions == null ? 0 : (uint)request.Extensions.Count; subordinateCertInfo.rgExtension = caExtensions; subordinateCertInfo.SignatureAlgorithm = signatureAlgo; subordinateCertInfo.Issuer = CACertInfo.Subject; subordinateCertInfoAllocPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.CERT_INFO))); Marshal.StructureToPtr(subordinateCertInfo, subordinateCertInfoAllocPtr, false); byte[] pbEncodedCert = null; uint pbEncodedCertLength = 0; if (!NativeMethods.CryptSignAndEncodeCertificate(hCAProv, (uint)request.KeySpecification, NativeMethods.X509_ASN_ENCODING, NativeMethods.X509_CERT_TO_BE_SIGNED, subordinateCertInfoAllocPtr, ref signatureAlgo, IntPtr.Zero, pbEncodedCert, ref pbEncodedCertLength)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } pbEncodedCert = new byte[pbEncodedCertLength]; if (!NativeMethods.CryptSignAndEncodeCertificate(hCAProv, (uint)request.KeySpecification, NativeMethods.X509_ASN_ENCODING, NativeMethods.X509_CERT_TO_BE_SIGNED, subordinateCertInfoAllocPtr, ref signatureAlgo, IntPtr.Zero, pbEncodedCert, ref pbEncodedCertLength)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var cert3 = new X509Certificate2(pbEncodedCert); return(cert3); } finally { if (hProvAllocPtr != IntPtr.Zero) { NativeMethods.CryptReleaseContext(hProvAllocPtr, 0); } if (hCAProv != IntPtr.Zero) { NativeMethods.CryptReleaseContext(hCAProv, 0); } if (hProvAllocPtr != IntPtr.Zero) { Marshal.FreeHGlobal(hProvAllocPtr); } if (subordinateCertInfoAllocPtr != IntPtr.Zero) { Marshal.FreeHGlobal(subordinateCertInfoAllocPtr); } } }
/// <summary> /// Create a certificate /// </summary> /// <param name="request">A request to generate certificate</param> /// <returns>Returns a pointer to the signed certificate</returns> internal static unsafe IntPtr CreateSelfSignedCertificatePtr(CertificateGenerationRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (string.IsNullOrWhiteSpace(request.Subject)) { throw new ArgumentException("request.Subject is null"); } NativeMethods.CERT_NAME_BLOB pSubjectIssuerBlob = new NativeMethods.CERT_NAME_BLOB(0, null); IntPtr extensionsPtr = IntPtr.Zero; var subjectName = request.Subject; var extensions = request.Extensions; var parameters = request.Parameters; if (parameters == null) { parameters = new CspParameters() { ProviderName = MS_ENH_RSA_AES_PROV, ProviderType = PROV_RSA_AES, KeyContainerName = Guid.NewGuid().ToString(), KeyNumber = (int)KeyNumber.Exchange, Flags = CspProviderFlags.UseMachineKeyStore } } ; var keySize = request.KeySize; if (keySize <= 0) { keySize = MINIMUM_SELF_SIGNED_CERTIFICATE_KEYSIZE; } var expirationLength = request.ExpirationLength; if (expirationLength <= TimeSpan.MinValue) { expirationLength = TimeSpan.FromDays(365); } var durationInMinutes = expirationLength.TotalMinutes; var signatureAlgo = request.SignatureAlgorithm; if (string.IsNullOrWhiteSpace(signatureAlgo)) { signatureAlgo = NativeMethods.OID_RSA_SHA256RSA; } string container = Guid.NewGuid().ToString(); try { uint pcbEncoded = 0; if (!NativeMethods.CertStrToName(NativeMethods.X509_ASN_ENCODING, subjectName, NativeMethods.CERT_X500_NAME_STR, IntPtr.Zero, null, ref pcbEncoded, IntPtr.Zero) && pcbEncoded <= 0) { throw new Win32Exception(Marshal.GetLastWin32Error()); } byte[] pbEncoded = new byte[pcbEncoded]; if (!NativeMethods.CertStrToName(NativeMethods.X509_ASN_ENCODING, subjectName, NativeMethods.CERT_X500_NAME_STR, IntPtr.Zero, pbEncoded, ref pcbEncoded, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } using (new RSACryptoServiceProvider(keySize, parameters)) { pSubjectIssuerBlob.CopyData(pbEncoded); NativeMethods.CRYPT_KEY_PROV_INFO pKeyProvInfo = new NativeMethods.CRYPT_KEY_PROV_INFO { pwszProvName = parameters.ProviderName, pwszContainerName = parameters.KeyContainerName, dwProvType = (uint)parameters.ProviderType, dwFlags = 0x20, //(uint)parameters.Flags, dwKeySpec = (uint)parameters.KeyNumber }; NativeMethods.CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm = new NativeMethods.CRYPT_ALGORITHM_IDENTIFIER { pszObjId = signatureAlgo }; pSignatureAlgorithm.parameters.cbData = 0; pSignatureAlgorithm.parameters.pbData = IntPtr.Zero; NativeMethods.SYSTEM_TIME pStartTime = new NativeMethods.SYSTEM_TIME(DateTime.UtcNow); NativeMethods.SYSTEM_TIME pEndTime = new NativeMethods.SYSTEM_TIME(DateTime.UtcNow.AddMinutes((double)durationInMinutes)); extensionsPtr = CertUtil.ConvertExtensions(extensions)[0]; IntPtr handle = NativeMethods.CertCreateSelfSignCertificate(IntPtr.Zero, ref pSubjectIssuerBlob, 0, ref pKeyProvInfo, ref pSignatureAlgorithm, ref pStartTime, ref pEndTime, extensionsPtr); if (handle == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return(handle); } } finally { if (IntPtr.Zero != extensionsPtr) { Marshal.FreeHGlobal(extensionsPtr); extensionsPtr = IntPtr.Zero; } pSubjectIssuerBlob.Dispose(); } } }