使用根证书(CA)签名证书有效,但新签名证书没有扩展名

时间:2018-03-30 11:34:02

标签: c# windows certificate x509certificate signing

这是我的第一个问题。我已经解决了这个问题好几天了,所以我希望你能帮助我。

我在C#中编写了一个应用程序,可以创建带扩展名的证书(alternativ域名,签名扩展等),并将其导入Windows证书库。大多数函数都是从Crypt32.dll编组的,就像CertCreateSelfSignCertificate一样,一切正常。

我的下一个任务是使用自己创建的证书颁发机构签署证书。所以我使用CryptSignAndEncodeCertificate来创建签名证书。它可以创建一个签名证书,但它没有扩展名,也没有私钥。

这是应该成为魔术的功能。

public static X509Certificate2 SignCertificate(X509Certificate2 certificateToSign, int KeySpecification, 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());

                    CRYPT_ALGORITHM_IDENTIFIER signatureAlgo = new CRYPT_ALGORITHM_IDENTIFIER()
                    {
                        pszObjId = NativeMethods.OID_RSA_SHA256RSA
                    };

                    // get the key handle of the CA Cert

                    CRYPT_KEY_PROV_INFO pKeyInfo = (CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(hProvAllocPtr, typeof(CRYPT_KEY_PROV_INFO));

                    // Acquire a context to the provider for crypto

                    if (!NativeMethods.CryptAcquireContext(ref hCAProv, pKeyInfo.ContainerName, pKeyInfo.ProviderName, pKeyInfo.ProviderType, pKeyInfo.Flags))
                        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(certificateToSign.Handle, typeof(NativeMethods.CERT_CONTEXT));
                    NativeMethods.CERT_INFO subordinateCertInfo = (NativeMethods.CERT_INFO)Marshal.PtrToStructure(subordinateCertContext.pCertInfo, typeof(NativeMethods.CERT_INFO));

                    IntPtr extensions = CreateExtensionsStructure(certificateToSign.Extensions);

                    subordinateCertInfo.cExtension = certificateToSign.Extensions == null ? 0 : (uint)certificateToSign.Extensions.Count;
                    subordinateCertInfo.rgExtension = extensions;

                    subordinateCertInfo.SignatureAlgorithm = signatureAlgo;
                    subordinateCertInfo.Issuer = CACertInfo.Subject;

                    subordinateCertInfoAllocPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.CERT_INFO)));
                    Marshal.StructureToPtr(subordinateCertInfo, subordinateCertInfoAllocPtr, false);

                    byte[] pbEncodedCert = null;
                    UInt32 pbEncodedCertLength = 0;

                      if (!NativeMethods.CryptSignAndEncodeCertificate(hCAProv,
                                                                    (uint)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)KeySpecification,
                                                                    NativeMethods.X509_ASN_ENCODING,
                                                                    NativeMethods.X509_CERT_TO_BE_SIGNED,
                                                                    subordinateCertInfoAllocPtr,
                                                                    ref signatureAlgo,
                                                                    IntPtr.Zero,
                                                                    pbEncodedCert,
                                                                    ref pbEncodedCertLength))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    X509Certificate2 signedCertificate = new X509Certificate2(pbEncodedCert, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);

                    return signedCertificate;
                }

另一个问题是为什么我不能从CERT_INFO

获得给定证书的扩展名
NativeMethods.CERT_CONTEXT subordinateCertContext = (NativeMethods.CERT_CONTEXT)Marshal.PtrToStructure(certificateToSign.Handle, typeof(NativeMethods.CERT_CONTEXT));
NativeMethods.CERT_INFO subordinateCertInfo = (NativeMethods.CERT_INFO)Marshal.PtrToStructure(subordinateCertContext.pCertInfo, typeof(NativeMethods.CERT_INFO));

顺便说一下,如果我在CryptSignAndEncodeCertificate中直接使用subordinateCertInfo作为pvStructInfo,则新证书具有扩展名,但它不会与CA建立连接。因为未设置subordinateCertInfo.Issuer。

[DllImport(CRYPT32, SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptSignAndEncodeCertificate(IntPtr hCryptProvOrNCryptKey,
                                                        uint dwKeySpec,
                                                        uint dwCertEncodingType,
                                                        ulong lpszStructType,
                                                        IntPtr pvStructInfo,
                                                        ref CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
                                                        IntPtr pvHashAuxInfo,
                                                        byte[] pbEncoded,
                                                        ref uint pcbEncoded);

顺便说一下,我不想使用Bouncy Castle或者用C ++编写应用程序。所以我希望你有一个没有一些极端变化的解决方案。

0 个答案:

没有答案