Зарегистрируйте сертификат X509 без каких-либо следов его на машине - PullRequest
0 голосов
/ 22 мая 2018

В настоящее время создаются центры сертификации и выданные сертификаты.Генерация запроса, регистрация и проверка работоспособны, но когда я проверил хранилище сертификатов, я понял, что он помещает их в личный каталог сертификатов.По памяти, по соображениям безопасности и по юридическим причинам я не могу этого иметь.

Сертификаты хранятся в защищенной удаленной базе данных.Сертификаты могут быть случайным образом доступны или генерироваться на случайной машине из коллекции.Если они генерируют сертификаты, они будут храниться на том компьютере, на котором был создан сертификат.Есть ли способ сгенерировать регистрацию сертификата (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
}

Сертификаты попадают в мое личное хранилище сертификатов

My current certificate store

Myрегистрация происходит в этом методе.Требуется полностью скомпонованный и закодированный запрос сертификата.

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;
}

EDIT В настоящее время я ограничен .NET 4.5.x.Еще одна проблема, с которой я сталкиваюсь, заключается в том, что при попытке подписать сертификат с правами root возникает исключение CRYPT_E_NOT_FOUND.

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Я понял, не используя регистрацию и придерживаясь .NET 4.5.x.Сначала я создаю RSACrytpoServiceProvider с использованием CspParameters.Затем я создаю закрытый и открытый ключ из RSACryptoServiceProvider.Я создаю запрос сертификата и инициирую с закрытого ключа.Запрос сертификата кодируется и преобразуется в необработанные данные, а затем в байты.Затем байты используются для создания сертификата X509.

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 инициируется и присоединяется.Но прежде чем это произойдет, я сохраняю корневой сертификат в хранилище сертификатов на локальном компьютере.Затем я создаю подписанный сертификат, используя только что добавленный в хранилище рут.Затем я удаляю сертификат из магазина.

Подписание запроса на сертификат

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 будетпо-прежнему собирать и проверять, но он распознает, что корень недоверен (легко обойти).

0 голосов
/ 23 мая 2018

Вероятно, нет способа сделать это с 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.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...