当前位置: 首页 > 知识库问答 >
问题:

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

颜黎昕
2023-03-14

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

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

这里的问题使用纯.NET Framework生成和签署证书请求对获得DER编码的CSR非常有帮助,但是我仍然有一些问题没有弄清楚。

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

下面是我想移植到.NET5的当前代码。请注意,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}");
            }
        }

共有1个答案

卫烨
2023-03-14

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

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

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

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

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

盒子里没有直接装这个的东西。基于CX509CertificateRequest类名,它似乎在使用CMS证书管理(CMC),但仍然需要解决身份验证和请求提交部分。

 类似资料:
  • 我正在尝试使用纯.NET代码创建证书请求,并根据现有的CA证书(在Windows证书存储中或作为单独的文件)从证书请求创建证书。 我知道有类和可用于加载证书并访问它们的信息,但在命名空间中没有任何类或功能可用于创建证书请求或对此类证书请求进行签名以创建新的已签名证书。 并且尽管命名空间的文档说明: System.security.Cryptography.PKCS命名空间为公钥加密标准(PKCS)

  • 它是使用.NET 4.7.2生成的,类似于本问题中的答案:使用纯.NET Framework生成和签名证书请求 然后将序列化的CSR发送到服务器,服务器需要创建证书--问题是如何做到这一点。

  • 本文向大家介绍.NET的Ajax请求数据提交实例,包括了.NET的Ajax请求数据提交实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了.NET的Ajax请求数据提交实现方法。分享给大家供大家参考。具体如下: 控制器 希望本文所述对大家的.NET程序设计有所帮助。

  • 我想使用TLS相互身份验证在Go中制造的API上对一个客户端进行身份验证。我已经创建了一个证书颁发机构,假设Bob有一个他想与客户机一起使用的密钥对。Bob创建了一个证书请求,并希望我验证他的证书,以便在API上进行授权和身份验证。 我已使用此方法创建了我的证书颁发机构: Bob使用它来创建他的证书和证书请求: 我想实现这一点,但在围棋: 但如果朱莉娅现在想登录怎么办?她将必须创建一个CSR,发送

  • 问题是如何在Java中以编程方式生成证书链。换言之,我想用java执行此处详述的操作:http://fusesource.com/docs/broker/5.3/security/i382664.html 当然,我可以为新客户端创建RSA密钥: } 并生成相应的证书: } 然后我生成证书签名请求,并将其保存到csrFile文件: 哪里 现在我应该用CA私钥对CSR进行签名,但我不知道如何在java

  • 我们将Jenkins2设置为构建每个向github的推送,我们不使用Pull Request构建器(尽管作为Pull请求一部分的提交显然也会被构建)。GitHub集成插件说它只适用于pull request builder,所以这对我们来说不起作用。 我也尝试过github-notify插件,但它似乎不适合我们的情况(可能是因为回购是私有的和/或作为组织的一部分拥有的,而不是个人用户)。我尝试让它