3

目前正在创建证书颁发机构和颁发的证书。请求、注册和验证的生成都是正常的,但是当我检查我的证书存储时,我意识到,它正在将它们放在我的个人证书目录中。出于记忆、安全和法律原因,我不能这样做。

证书存储在安全的远程数据库中。证书可以从集合中随机访问或在随机机器上生成。如果他们生成证书,它将把它们存储在创建证书的任何机器上。有没有办法生成证书注册 (CX509Enrollment) 而不会在机器上留下任何证书的痕迹?

控制注册的部分相对较小且直截了当。它只能以管理员身份运行。我认为那是因为它正在向商店添加证书。

我目前正在运行一个单独的项目文件来尝试调试此问题。我的两个证书都是构建并保存在内存中的。

static void Main(string[] args)
{
    X509Certificate2 rootCert = CreateSelfSignedCertificate("testRoot");
    X509Certificate2 signedChild = CreateSignedCertificate("testyMcTesterson", rootCert);

    X509Chain chain = new X509Chain();
    chain.ChainPolicy = new X509ChainPolicy()
    {
        RevocationMode = X509RevocationMode.NoCheck,
        VerificationFlags = X509VerificationFlags.AllFlags,
        UrlRetrievalTimeout = new TimeSpan(0, 1, 0)
    };
    chain.ChainPolicy.ExtraStore.Add(rootCert);
    bool isValid = chain.Build(signedChild); //Is True :D
}

证书最终在我的个人证书存储中

我当前的证书存储

我的注册发生在这种方法中。它需要一个完全构造和编码的证书请求。

public static CX509Enrollment EnrollCertificateRequest(CX509CertificateRequestCertificate certRequest)
{
    var enroll = new CX509Enrollment();
    enroll.InitializeFromRequest(certRequest);
    string csr = enroll.CreateRequest(); 
    enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
        csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); 

    return enroll;
}

编辑 我目前仅限于.NET 4.5.x。我遇到的另一个问题是,尝试使用 root 签署证书会引发 CRYPT_E_NOT_FOUND 异常。

4

2 回答 2

1

可能没有办法做到这一点CX509Enroll。但是您可以使用 .NET Framework 4.7.2 和CertificateRequest类来实现您的目标。

using (RSA rsa = RSA.Create(2048))
{
    CertificateRequest request = new CertificateRequest(
        "CN=Your Name Here",
        rsa,
        HashAlgorithmName.SHA256,
        RSASignaturePadding.Pkcs1);

    SubjectAlternativeNameBuilder builder = new SubjectAlternativeNameBuilder();
    builder.AddDnsName("your.name.here");
    builder.AddDnsName("your.other.name.here");

    request.CertificateExtensions.Add(builder.Build());

    // Any other extensions you're supposed to request, like not being a CA.
    request.CertificateExtensions.Add(
        new X509BasicConstraintsExtension(false, false, 0, false));

    // TLS Server?
    request.CertificateExtensions.Add(
        new X509EnhancedKeyUsageExtension(
            new OidCollection
            {
                new Oid("1.3.6.1.5.5.7.3.1")
            },
            false));

    byte[] derEncodedRequest = request.CreateSigningRequest();

    X509Certificate2 responseWithPrivateKey;

    using (X509Certificate2 response = SendRequestToServerAndGetResponse(derEncodedRequest))
    {
        responseWithPrivateKey = response.CopyWithPrivateKey(rsa);
    }

    // Use it, save it to a PFX, whatever.
    // At this point, nothing has touched the hard drive.
}
于 2018-05-22T21:04:39.170 回答
0

我在不使用注册并坚持使用 .NET 4.5.x 的情况下弄清楚了。我首先使用 CspParameters 创建了一个 RSACrytpoServiceProvider。然后我从 RSACryptoServiceProvider 构造一个私钥和公钥。我创建一个证书请求并从私钥启动。证书请求被编码并转换为原始数据,然后转换为字节。然后这些字节用于创建 X509Certificate2。

public static X509Certificate2 GenerateCertificate(string subjectName)
{
    var dn = new CX500DistinguishedName();
    dn.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_COMMA_FLAG);

    //Create crytpo provider to generate an assymetric key
    int KeyType = (int)X509ProviderType.XCN_PROV_RSA_SCHANNEL;
    CspParameters cspParams = new CspParameters(KeyType);
    cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
    cspParams.KeyContainerName = Guid.NewGuid().ToString();
    var rsa = new RSACryptoServiceProvider(2048, cspParams);
    var CryptoProvider = rsa.CspKeyContainerInfo.ProviderName;

    var keyContainerName = rsa.CspKeyContainerInfo.KeyContainerName;
    CX509PrivateKey privateKey = new CX509PrivateKey();
    privateKey.MachineContext = true;
    privateKey.ProviderName = CryptoProvider;
    privateKey.ContainerName = keyContainerName;
    privateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
    privateKey.Open();

    keyContainerName = privateKey.ContainerName;
    CX509PublicKey publicKey = privateKey.ExportPublicKey();

    var oid = new CObjectId();
    oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server
    var oidlist = new CObjectIds();
    oidlist.Add(oid);
    var eku = new CX509ExtensionEnhancedKeyUsage();
    eku.InitializeEncode(oidlist);

    var hashobj = new CObjectId();
    hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
        ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
        AlgorithmFlags.AlgorithmFlagsNone, "SHA256");

    CX509CertificateRequestCertificate certRequest = new CX509CertificateRequestCertificate();
    certRequest.InitializeFromPrivateKey(
        X509CertificateEnrollmentContext.ContextMachine,
        privateKey,
        "");

    certRequest.Subject = dn;
    certRequest.NotBefore = DateTime.Now;
    certRequest.NotAfter = DateTime.Now.AddYears(1);
    certRequest.HashAlgorithm = hashobj;
    certRequest.X509Extensions.Add((CX509Extension)eku);
    certRequest.Encode();

    return new X509Certificate2(
    Convert.FromBase64String(certRequest.RawData), "",
    X509KeyStorageFlags.Exportable)
    {
        PrivateKey = rsa,
        FriendlyName = subjectName
    };
}

颁发证书。启动并附加 CSignerCertificate 遵循相同的过程。但在此之前,我将根证书保存到 My, Local Machine Certificate Store。然后,我使用刚刚添加到商店的根创建一个签名证书。然后我从商店中删除证书。

签署证书请求

var dnSigner = new CX500DistinguishedName();
dnSigner.Encode("CN=" + signer.FriendlyName, X500NameFlags.XCN_CERT_NAME_STR_COMMA_FLAG);

string base64Root = Convert.ToBase64String(signer.RawData);
CSignerCertificate certSigner = new CSignerCertificate();

bool useMachineStore = ((ICspAsymmetricAlgorithm)signer.PrivateKey).CspKeyContainerInfo.MachineKeyStore;
certSigner.Initialize(useMachineStore, X509PrivateKeyVerify.VerifyNone, EncodingType.XCN_CRYPT_STRING_BASE64, base64Root);
certRequest.SignerCertificate = certSigner;
certRequest.Issuer = dnSigner;
static void Main(string[] args)
{
    X509Certificate2 rootCert = GenerateCertificate("TEST_ROOT");
    X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadWrite);
    store.Add(rootCert);
    X509Certificate2 signedChild = GenerateUserCertificate("Testy McTesterson", rootCert);
    store.Remove(rootCert);
    store.Close();
}

需要注意的一些重要事项:这仅适用于某些密钥用法和密钥规范标志 X509Chain 仍将构建和验证,但它会识别根是不受信任的(易于绕过)。

于 2018-05-24T21:32:45.423 回答