Есть ли способ создать сертификат DSA с использованием чистой .NET Framework, и если нет, то почему?

Начиная с .NET 4.7.2 можно создавать сертификаты RSA и EC с помощью .NET CertificateRequest. Однако я не могу найти ничего, что позволило бы мне генерировать сертификаты DSA. Вот как я бы сделал это для RSA и EC:

private static X509Certificate2 GenerateRsaCertificate()
{
    var hashAlgorithm = HashAlgorithmName.SHA256;
    var rsaKey = RSA.Create(2048);
    var subject = new X500DistinguishedName("CN=mycert");
    var request = new CertificateRequest(subject, rsaKey, hashAlgorithm, RSASignaturePadding.Pkcs1);
    var certificate = request.CreateSelfSigned(DateTime.Now - TimeSpan.FromDays(5), DateTime.Now + TimeSpan.FromDays(365));
    return certificate;
}

private static X509Certificate2 GenerateEcDsaCertificate()
{
    var hashAlgorithm = HashAlgorithmName.SHA256;
    var curve = ECCurve.NamedCurves.nistP256;
    var ecDsaKey = ECDsa.Create(curve);
    var subject = new X500DistinguishedName("CN=mycert");
    var request = new CertificateRequest(subject, ecDsaKey, hashAlgorithm);
    var certificate = request.CreateSelfSigned(DateTime.Now - TimeSpan.FromDays(5), DateTime.Now + TimeSpan.FromDays(365));
    return certificate;
}

Раньше я использовал Bouncy Castle для создания всех трех типов сертификатов, но с переходом на .NET я могу использовать только RSA и ECDsa в вызовах CertificateRequest. Есть ли причины, по которым DSA не включен? Однако я все еще могу сгенерировать ключ с помощью DSA.Create(keySize). Также .NET Framework включает в себя другие классы, которые работают с DSA: DSA, DSACng, DSACryptoServiceProvider, DSACertificateExtensions, но я ничего не вижу для генерации сертификатов. Есть ли проблемы с самим алгоритмом (может вообще не стоит его использовать)? Или я что-то пропустил в API?


person username    schedule 20.12.2019    source источник


Ответы (1)


Есть ли проблемы с самим алгоритмом (может вообще не стоит его использовать)?

DSA, не входящие в ЕС, умирает.

Я предполагаю, что на самом деле это было сделано в исходной спецификации (FIPS 186-1), которая ограничивала ключи до 1024 бит, а алгоритм - до SHA-1. В 2009 году алгоритм был обновлен в соответствии со стандартом FIPS 186-3 для поддержки немного больших ключей и хэшей SHA-2. Для подписей FIPS 186-1 (и FIPS 186-2) DSA требуются только данные и закрытый ключ (для проверки требуются только данные, подпись и открытый ключ), подписи FIPS 186-3 также требуют алгоритма хеширования в качестве входных данных... поэтому API не совсем совместим.

Windows CAPI (старшая из двух криптографических платформ Windows) проигнорировала обновление FIPS 186-3, как и Apple Security.framework. Windows CNG и OpenSSL поддерживают «новый DSA». Apple не может обрабатывать сертификаты, подписанные с «новым DSA» (и, может быть, даже с «классическим DSA», я забыл), а Windows не поддерживает «новый DSA» в цепочках сертификатов, только «классический DSA».

Таким образом, сертификаты DSA, как правило, ограничены ограничениями FIPS 186-1/186-2, что означает SHA-1 (в наши дни никому не нравится) и 1024-битные ключи (которые по сегодняшним меркам слишком малы). Если вы знаете, что OpenSSL проверяет вас, вы можете использовать лучшие ключи DSA.

DSA также обычно намного медленнее проверяет подпись, чем RSA.

На уровне безопасности 80 бит, используя инструмент скорости OpenSSL на моей случайной виртуальной машине (выходные данные слегка изменены для презентационных целей, отсортированы по убыванию проверки/с):

                                sign    verify    sign/s verify/s
rsa  1024 bits               0.000301s 0.000018s   3326.3  56419.7
dsa  1024 bits               0.000309s 0.000236s   3236.2   4240.5
ecdsa 160 bits (secp160r1)   0.0005s   0.0004s     1984.6   2385.7

112 бит безопасности

                                sign    verify    sign/s verify/s
rsa  2048 bits               0.002030s 0.000062s    492.6  16062.4
ecdsa 224 bits (nistp224)    0.0001s   0.0002s     9020.6   4252.2
dsa  2048 bits               0.000885s 0.000802s   1129.4   1247.3

128 бит безопасности

                                      sign    verify    sign/s verify/s
rsa  3072 bits                     0.006935s 0.000135s    144.2   7401.6
ecdsa 256 bits (nistp256)          0.0001s   0.0002s    16901.5   5344.7
ecdsa 256 bits (brainpoolP256t1)   0.0010s   0.0008s      980.1   1262.5
ecdsa 256 bits (brainpoolP256r1)   0.0010s   0.0008s     1012.9   1209.5
dsa  3072 bits (not in test suite)

192 бита безопасности

                                      sign    verify    sign/s verify/s
rsa  7680 bits                     0.122805s 0.000820s      8.1   1220.2
ecdsa 384 bits (nistp384)          0.0024s   0.0018s      416.1    571.2
ecdsa 384 bits (brainpoolP384t1)   0.0024s   0.0018s      410.0    545.1
ecdsa 384 bits (brainpoolP384r1)   0.0025s   0.0019s      407.4    540.1
dsa  7680 bits (beyond FIPS 186-3 DSA maximum of 3072 bits)

256 бит безопасности

                                      sign    verify    sign/s verify/s
ecdsa 521 bits (nistp521)          0.0006s   0.0012s     1563.1    841.3
ecdsa 512 bits (brainpoolP512t1)   0.0038s   0.0027s      265.2    369.1
ecdsa 512 bits (brainpoolP512r1)   0.0038s   0.0028s      262.4    360.5
rsa 15360 bits                     0.783846s 0.003190s      1.3    313.5
dsa 15360 bits (beyond FIPS 186-3 DSA maximum of 3072 bits)

Я могу использовать только RSA и ECDsa в вызовах CertificateRequest. Есть ли причины, по которым DSA не включен?

Из треда с предложением исходной функции:

Основываясь на новых данных из Windows (и их отсутствии поддержки сертификатов DSA FIPS 186-3), я собираюсь вытащить типизированный конструктор DSA и оставить DSA в качестве сценария «опытного пользователя» (пользовательский класс X509SignatureGenerator и т. д.)

Итак, он был удален в основном потому, что DSA умирает.

Или я что-то пропустил в API?

API позволяет предоставлять пользовательские генераторы подписей. В тестах CertificateRequest это подтверждается с помощью DSAX509SignatureGenerator

X509SignatureGenerator dsaGen = new DSAX509SignatureGenerator(dsaCsp);

// Use SHA-1 because that's all DSACryptoServiceProvider understands.
HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1;

CertificateRequest request = new CertificateRequest(
    new X500DistinguishedName($"CN={KeyName}-{provType}"),
    dsaGen.PublicKey,
    hashAlgorithm);

DateTimeOffset now = DateTimeOffset.UtcNow;

using (X509Certificate2 cert = request.Create(request.SubjectName, dsaGen, now, now.AddDays(1), new byte[1]))
using (X509Certificate2 certWithPrivateKey = cert.CopyWithPrivateKey(dsaCsp))
using (DSA dsa = certWithPrivateKey.GetDSAPrivateKey())
{
    byte[] signature = dsa.SignData(Array.Empty<byte>(), hashAlgorithm);

    Assert.True(dsaCsp.VerifyData(Array.Empty<byte>(), signature, hashAlgorithm));
}

(фрагмент из https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/libraries/System.Security.Cryptography.X509Certificates/tests/CertificateCreation/PrivateKeyAssociationTests.cs#L2576-L257a>

person bartonjs    schedule 20.12.2019