Генерация и подписание сертификата на разных машинах C# - PullRequest
0 голосов
/ 30 марта 2020

Мне нужно сгенерировать сертификаты, которые будут использоваться для безопасной связи между агентами. Каждый агент генерирует сертификат и должен отправить его в ЦС системы на другом компьютере, чтобы он был подписан (и доверен другим агентам). Я делаю это, используя C# со следующим кодом для агента:

 //generate certificate
        ECDsa elipticCurveNistP256Key = ECDsa.Create(ECCurve.CreateFromValue("1.2.840.10045.3.1.7")); // nistP256 curve
        CertificateRequest certificateRequest = new CertificateRequest("CN=" + agentId, elipticCurveNistP256Key, HashAlgorithmName.SHA256);
        certificateRequest.CertificateExtensions.Add(
            new X509BasicConstraintsExtension(false, false, 0, false));
        certificateRequest.CertificateExtensions.Add(
            new X509KeyUsageExtension(
                X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation,
                false));

        // Add the SubjectAlternativeName extension
        var sanBuilder = new SubjectAlternativeNameBuilder();
        sanBuilder.AddIpAddress(IPAddress.Parse(agentIpAddress));
        certificateRequest.CertificateExtensions.Add(sanBuilder.Build());

        certificateRequest.CertificateExtensions.Add(
            new X509EnhancedKeyUsageExtension(
                new OidCollection
                {
                    new Oid("1.3.6.1.5.5.7.3.8")
                },
                true));

        certificateRequest.CertificateExtensions.Add(
            new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));

И следующий код для системы CA:

  X509Certificate2 signedCertificate = certificateRequest.Create(
            caCertificatePFX,
            DateTimeOffset.UtcNow.AddDays(-1),
            DateTimeOffset.UtcNow.AddDays(30),
            new byte[] {1, 2, 3, 4});

Конечно, я использую также код для связи между машинами, которые я здесь не показываю. Но у меня есть по крайней мере две проблемы:

  1. Я хотел бы иметь полное разделение между генерацией сертификата и подписью, но даже при большом количестве попыток это был единственный код, который мне удалось получить работать. Если я не ошибаюсь, этот код имеет создание сертификата в системе CA, что не является идеальным сценарием (CA имеет доступ к секретному ключу агента), но если я не нашел лучшего, это то, что я могу принять.

  2. Вторая проблема заключается в том, что даже если я приму первую проблему, мне все равно нужно будет отправить объект CertificateRequest с одного компьютера на другой, а CertificateRequest не будет сериализуемым. Я нашел метод CreateSigningRequest (), который «создает значение CertificationRequest PKCS # 10 в ASN.1 DER, закодированное в формате ASN.1, представляющее состояние текущего объекта». однако я не нашел способа сделать его объектом CertificateRequest, чтобы я мог запустить системный код CA.

Кто-нибудь знает, как я могу это сделать? Надеюсь полностью разделить генерацию сертификата и подпись сертификата, но если это невозможно, по крайней мере создать объект CertificateRequest обратно.

Я работаю. Net Framework 4.7.2, который мне нужно поддерживать для использования Ранее разработанные Windows Формы.

Спасибо

Ответы [ 2 ]

0 голосов
/ 30 марта 2020

Я настоятельно рекомендую использовать программное обеспечение CA для подписи запросов на сертификаты. Период.

Любая попытка присвоить собственный код CA сделает решение ненадежным, fr agile и подверженным ошибкам во многих аспектах. Есть несколько вариантов, начиная с Microsoft ADCS (Windows) и EJBCA (Windows / Linux). Любой другой дизайн будет просто плохим.

0 голосов
/ 30 марта 2020

Как вы заметили, нет способа зачитать запрос PKCS # 10. Это в значительной степени связано с тем, что слишком многих вещей не хватает, чтобы быть «ОК» Центром сертификации, поэтому наличие считывателя просто сделает для многих «плохих» Центров сертификации. (Поскольку ваш ЦС не поддерживает отзыв, это также «плохой» ЦС, но вы уменьшаете его с помощью сертификатов с коротким сроком службы.)

Запрос PKCS # 10 содержит:

  • Версия формата данных
  • Имя (предположительно то, которое запрашивающий запрашивает)
  • Публичный c ключ
  • Атрибуты
    • Запрошенные расширения приходит сюда (EKU, Subject Alternative Name, et c)
  • Подпись, подтверждающая наличие у запрашивающего лица закрытого ключа.

Данные версия формата не имеет значения, если вы не используете формат данных, и подпись не очень важна для «закрытых» эмитентов (ЦС, которые выдают сертификаты только непосредственно известным сторонам). Так что вам просто нужно перенести ключ publi c и любые другие данные, необходимые для запроса (с учетом вашего текущего кода, идентификатора агента и IP-адреса).

Единственная сложная часть - отправка publi. c key ... но с. NET Core 3.0+ вы можете нормализовать все ключи к их формату SubjectPublicKeyInfo:

byte[] spki = elipticCurveNistP256Key.ExportSubjectPublicKeyInfo();

Хотя это было бы чрезвычайно умно для типа PublicKey иметь метод ImportSubjectPublicKeyInfo, чего еще не произошло. Для синтаксического анализа generi c вам нужно попробовать все основные типы ключей, но, поскольку вы являетесь закрытым центром сертификации с другой стороны, вы можете заранее знать, что это ECDSA:

using (ECDsa clientPub = ECDsa.Create())
{
    clientPub.ImportSubjectPublicKeyInfo(transmittedSpki, out _);

    // the rest of your code goes here.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...