Подтвердить что ты не робот

Как проверить подпись для подписанного документа XML с помощью SHA256?

Кажется, что SignedXml.CheckSignature работает нормально только для подписанных документов с использованием SHA1.

Я попробовал этот код, добавив алгоритм SHA256, и CheckSignature работал нормально, но классы WIF начали бросать следующее исключение:

System.Security.Cryptography.CryptographicException: указан неверный алгоритм. В этом методе вызов System.IdentityModel.Services.FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest

Кажется, что ProcessSignInRequest использует алгоритм SHA1, который был здесь переопределен здесь:

CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), 
                          "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");

Что я пропустил? Как я могу указать алгоритм в CheckSignature?

4b9b3361

Ответ 1

У меня была такая же проблема сегодня. Оказалось, что сертификат подписи WIF был создан с использованием CSP без поддержки SHA256 (подробнее).

Я просмотрел исходный код System.IdentityModel и обнаружил, что он содержит специальную обработку для этого случая. Когда у вас есть соответствующий алгоритм, зарегистрированный глобально, WIF использует его вместо своей внутренней реализации, а класс RSAPKCS1SHA256SignatureDescription не включает эту специальную обработку.

Итак, я сделал свою собственную реализацию SignatureDescription, которая воссоздает RSACryptoServiceProvider с параметрами по умолчанию, включая поддержку SHA256.

/// <summary>
/// Represents the sha256RSA signature algorithm.
/// </summary>
public sealed class RsaPkcs1Sha256SignatureDescription : SignatureDescription
{
    /// <summary>
    /// This type of CSP has SHA256 support
    /// </summary>
    private const int PROV_RSA_AES = 24;

    public RsaPkcs1Sha256SignatureDescription()
    {
        KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
        DigestAlgorithm = typeof(SHA256Cng).FullName;
        FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;
        DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;
    }

    /// <summary>
    /// Adds support for sha256RSA XML signatures.
    /// </summary>
    public static void RegisterForSignedXml()
    {
        CryptoConfig.AddAlgorithm(
            typeof (RsaPkcs1Sha256SignatureDescription),
            "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
    }

    public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
    {
        if (key == null) throw new ArgumentNullException("key");

        key = GetSha2CompatibleKey(key);

        var signatureDeformatter = new RSAPKCS1SignatureDeformatter(key);
        signatureDeformatter.SetHashAlgorithm("SHA256");
        return signatureDeformatter;
    }

    public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
    {
        if (key == null) throw new ArgumentNullException("key");

        key = GetSha2CompatibleKey(key);

        var signatureFormatter = new RSAPKCS1SignatureFormatter(key);
        signatureFormatter.SetHashAlgorithm("SHA256");
        return signatureFormatter;
    }

    // Some certificates are generated without SHA2 support, this method recreates the CSP for them.
    // See /info/451752/can-rsacryptoserviceprovider-nets-rsa-use-sha256-for-encryption-not-signing-instead-of-sha1/1971807#1971807
    // WIF handles this case internally if no sha256RSA support is installed globally.
    private static AsymmetricAlgorithm GetSha2CompatibleKey(AsymmetricAlgorithm key)
    {
        var csp = key as RSACryptoServiceProvider;
        if (csp == null || csp.CspKeyContainerInfo.ProviderType == PROV_RSA_AES)
            return key;

        var newKey = new RSACryptoServiceProvider(new CspParameters(PROV_RSA_AES));
        newKey.ImportParameters(csp.ExportParameters(true));
        return newKey;
    }
}