微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

仅使用 .Net 生成证书请求并提交给 CA

如何解决仅使用 .Net 生成证书请求并提交给 CA

我正在尝试仅使用 .Net 代码创建证书请求并将请求提交给我们的内部 Active Directory PKI 证书颁发机构,然后取回证书。我有一个已经工作了几年的解决方案,但它使用 CERTCLILib 和 CERTENROLLLib,我想摆脱这些依赖项并将此代码移植到 .Net 5。

然后将这些证书导入 Yubikey 设备。我们在 Yubikey 上生成密钥对,然后将公钥与 CSR 一起使用。

这里的这个问题 Generate and Sign Certificate Request using pure .net Framework 对获得 DER 编码的 CSR 非常有帮助,但我仍然有一些我无法弄清楚的问题。

  1. 如何指定要在 CertificateRequest 对象中使用的 CA 和模板?
  2. 我有一个公钥,它是一个 RSAParameters 对象。如何将其放入 RSA 对象以与 CertificateRequst 构造函数一起使用?
  3. 获得 DER 编码的 CSR 后,我该如何将其提交给 CA?我在 System.Security.Cryptography.X509Certificates 命名空间中找不到任何实现此目的的类或方法

这是我当前正在运行的代码,我想将其移植到 .NET 5。请注意,DeviceDetails 包含有关 Yubikey 设备以及 CA 和模板的属性。此代码是配置 Yubikey 设备的大型应用的一部分。

    {
        //private const int CC_UIPICKCONfig = 0x1;
        private const int CR_IN_BASE64 = 0x1;
        private const int CR_IN_FORMatanY = 0;
        private const int CR_disP_ISSUED = 0x3;
        private const int CR_disP_UNDER_SUBMISSION = 0x5;
        private const int CR_OUT_BASE64 = 0x1;

        public static string GenerateRequest(DeviceDetails deviceDetails)
        {
            //  Create all the objects that will be required
            var objPkcs10 = new CX509CertificateRequestPkcs10();
            var objDN = new CX500distinguishedname();
            var objObjectIds = new CObjectIds();
            var objObjectId = new CObjectId();
            var objExtensionKeyUsage = new CX509ExtensionKeyUsage();
            var objX509ExtensionEnhancedKeyUsage = new CX509ExtensionEnhancedKeyUsage();
            var objPublicKey = new CX509PublicKey();

            try
            {
                var publicKey = Utilities.ExportPublicKeyToPEMFormat(deviceDetails.PublicKey);

                publicKey = string.Join("",publicKey.Split(new[] { "\r\n" },StringSplitOptions.RemoveEmptyEntries).Where(s => !s.StartsWith("--")));

                objPublicKey.InitializefromEncodedPublicKeyInfo(publicKey,EncodingType.XCN_CRYPT_STRING_BASE64);

                var sha512 = new CObjectId();
                sha512.InitializefromValue("2.16.840.1.101.3.4.2.3");

                // Initialize the PKCS#10 certificate request object based on the public key.
                objPkcs10.InitializefrompublicKey(X509CertificateEnrollmentContext.ContextUser,objPublicKey,"");
                objPkcs10.HashAlgorithm = sha512;

                //Key Usage Extension
                objExtensionKeyUsage.InitializeEncode(
                    X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE |
                    X509KeyUsageFlags.XCN_CERT_NON_REPUDIATION_KEY_USAGE |
                    X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE |
                    X509KeyUsageFlags.XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE
                );

                objPkcs10.X509Extensions.Add((CX509Extension)objExtensionKeyUsage);

                // Enhanced Key Usage Extension
                objObjectId.InitializefromValue("1.3.6.1.5.5.7.3.2"); // OID for Client Authentication usage
                objObjectIds.Add(objObjectId);
                objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
                objPkcs10.X509Extensions.Add((CX509Extension)objX509ExtensionEnhancedKeyUsage);

                //  Encode the name in using the distinguished Name object
                objDN.Encode(
                    deviceDetails.CertificateDetails.Subject,X500NameFlags.XCN_CERT_NAME_STR_NONE
                );

                //  Adding the subject name by using the distinguished Name object initialized above
                objPkcs10.Subject = objDN;

                //  Adding the Subject Alternate Names
                var strRfc822Name = deviceDetails.UserDetails.OUN + "@corp.com";
                var strUpn = deviceDetails.UserDetails.OUN + "@corp.com";

                var objRfc822Name = new CAlternativeName();
                var objUserPrincipalName = new CAlternativeName();
                var objAlternativeNames = new CAlternativeNames();
                var objExtensionAlternativeNames = new CX509ExtensionAlternativeNames();

                // Set Alternative RFC822 Name
                objRfc822Name.InitializefromString(AlternativeNameType.XCN_CERT_ALT_NAME_RFC822_NAME,strRfc822Name);
                

                // Set Alternative UPN
                objUserPrincipalName.InitializefromString(AlternativeNameType.XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME,strUpn);

                // Set Alternative Names 
                objAlternativeNames.Add(objRfc822Name);
                
                objAlternativeNames.Add(objUserPrincipalName);
                objExtensionAlternativeNames.InitializeEncode(objAlternativeNames);
                objPkcs10.X509Extensions.Add((CX509Extension)objExtensionAlternativeNames);

                // Create a CMC outer request and initialize
                var cmcReq = new CX509CertificateRequestCmc();
                cmcReq.InitializefromInnerRequestTemplateName(objPkcs10,deviceDetails.CertificateDetails.TemplateName);              

                // encode the request
                cmcReq.Encode();
                var strRequest = cmcReq.RawData[EncodingType.XCN_CRYPT_STRING_BASE64];
                return strRequest;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        // Submit request to CA and get response
        public static X509Certificate2 SendRequest(DeviceDetails deviceDetails,string request,out string error)
        {
            error = "";

            //  Create all the objects that will be required
            //var objCertConfig = new CCertConfig();
            var objcertrequest = new Ccertrequest();

            try
            {
                // Submit the request
                var idisposition = objcertrequest.Submit(
                    CR_IN_BASE64 | CR_IN_FORMatanY,request,null,deviceDetails.CertificateDetails.IssuingCa
                );

                // Check the submission status
                if (CR_disP_ISSUED != idisposition) // Not enrolled
                {
                    var strdisposition = objcertrequest.GetdispositionMessage();

                    if (CR_disP_UNDER_SUBMISSION == idisposition) // Pending
                    {
                        error = "The submission is pending: " + strdisposition;
                        return null;
                    }

                    else // Failed
                    {
                        error = $"The submission Failed: {strdisposition}. Last status: {objcertrequest.GetLastStatus()}";
                        return null;
                    }
                }

                // Get the certificate
                var strCert = objcertrequest.GetCertificate(CR_OUT_BASE64);
                var rawCert = Convert.FromBase64String(strCert);

                return new X509Certificate2(rawCert);
            }

            catch (Exception ex)
            {
                throw new Exception($"Error sending the request. {ex.Message}");
            }
        }

解决方法

多部分问题很难,因为它们需要多部分答案。以下是我可以回答的部分:

如何指定要在 CertificateRequest 对象中使用的 CA 和模板?

您不能,但没关系,因为您也没有在 CertEnroll 代码中。 CertificateRequest 对象等效于您的 objPkcs10,CA 和模板用于处理 CreateSigningRequest 输出。

我有一个公钥,它是一个 RSAParameters 对象。如何将其放入 RSA 对象以与 CertificateRequst 构造函数一起使用?

using (RSA key = RSA.Create())
{
    key.ImportParameters(rsaParameters);
    ...
}

一旦我获得了 DER 编码的 CSR,我该如何将其提交给 CA?我在 System.Security.Cryptography.X509Certificates 命名空间中找不到任何实现该功能的类或方法。

框中没有直接用于此的任何内容。基于 CX509CertificateRequest 类名,它似乎使用了 Certificate Management over CMS (CMC),但仍然需要解决身份验证和请求提交部分。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。