Ошибка проверки цифровой подписи для доступа к веб-сервису

Мне нужно отправить цифровую подпись в качестве одного из параметров на внешний веб-сервис.

Шаги для создания в соответствии с документацией:

  1. Создайте DOM представление XML данных
  2. Создайте канонизированное представление данных DOM. Канонизированное представление должно соответствовать форме, описанной в http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments;
  3. Создайте подпись RSA для шифрования SHA1 дайджеста канонизированного представления. Подпись шифруется с использованием закрытого ключа Участника;
  4. Закодируйте двоичную подпись в строку в кодировке base64.
  5. Поместите строку Signature в элемент SOAP message ReqDigSig;
  6. Сохраните XML-данные, так как они могут понадобиться позже для поддержки неотказуемости отправленных XML-данных.

Я использовал следующий код:

private string SignXML(X509Certificate2 Cert, string data)
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = false;
        xmlDoc.LoadXml(data);

        XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
        t.LoadInput(xmlDoc);
        Stream s = (Stream)t.GetOutput(typeof(Stream));

        SHA1 sha1 = SHA1.Create();
        byte[] hash = sha1.ComputeHash(s);


        RSACryptoServiceProvider rsaKey =
        (RSACryptoServiceProvider)Cert.PrivateKey;
        RSAParameters rsaPrivateParams = rsaKey.ExportParameters(true);
        rsaKey.ImportParameters(rsaPrivateParams);
        byte[] signature =  rsaKey.Encrypt(hash, false);

        return Convert.ToBase64String(signature);
    }

Но ответ от веб-сервиса говорит об ошибке проверки цифровой подписи.

приведенный выше код соответствует описанию в документации? Как я могу проверить, действительна ли цифровая подпись? есть ли какой-нибудь онлайн-инструмент?

[Сообщение отредактировано следующим образом] Я пытался использовать следующее. Я проверил подпись, и она возвращает true. Но не работает с конца веб-сервиса. В чем разница между методами signData, signHash и createsignature классов rsaPKCsignatureformatter?

        var document = Encoding.UTF8.GetBytes(Reqdata);

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = false;
        xmlDoc.LoadXml(Reqdata);

        //trial with XmlDsigC14NWithCommentsTransform class
        XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
        t.LoadInput(xmlDoc);
        Stream s = (Stream)t.GetOutput(typeof(Stream));

        //trial with SignedXML class
        SignedXml signedXml = new SignedXml(xmlDoc);
        signedXml.SignedInfo.CanonicalizationMethod =
        SignedXml.XmlDsigC14NWithCommentsTransformUrl;
        document = Encoding.UTF8.GetBytes(signedXml.ToString());

        byte[] hashedDocument;

        using (var sha1 = SHA1.Create())
        {
            //hashedDocument = sha1.ComputeHash(document);
            hashedDocument = sha1.ComputeHash(s);
        }

        var digitalSignature = new DigitalSignature();
        digitalSignature.AssignNewKey();

        byte[] signature = digitalSignature.SignData(hashedDocument);
        string finalsignature = Convert.ToBase64String(signature) ;
        byte[] finalSignveri = Convert.FromBase64String(finalsignature);
        bool verified = digitalSignature.VerifySignature(hashedDocument, finalSignveri);

и класс цифровой подписи выглядит следующим образом:

public class DigitalSignature
{
    private RSAParameters publicKey;
    private RSAParameters privateKey;

    public void AssignNewKey()
    {
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.PersistKeyInCsp = false;
            publicKey = rsa.ExportParameters(false);
            privateKey = rsa.ExportParameters(true);
        }
    }

    public byte[] SignData(byte[] hashOfDataToSign)
    {
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.PersistKeyInCsp = false;
            rsa.ImportParameters(privateKey);

            var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
            rsaFormatter.SetHashAlgorithm("SHA1");

            return rsaFormatter.CreateSignature(hashOfDataToSign);
        }
    }

    public bool VerifySignature(byte[] hashOfDataToSign, byte[] signature)
    {
        using (var rsa = new RSACryptoServiceProvider())
        {
            rsa.ImportParameters(publicKey);

            var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
            rsaDeformatter.SetHashAlgorithm("SHA1");

            return rsaDeformatter.VerifySignature(hashOfDataToSign, signature);
        }
    }   
}

Не могли бы вы сообщить мне, какие данные вы конкретно ищете в wsdl? К сожалению, я не могу предоставить здесь полную информацию о wsdl.

Возвращаемая ошибка, я полагаю, обработана пользователем и указывает «Ошибка проверки цифровой подписи».

[Отредактировано]

Ниже вы найдете фрагмент кода, который генерирует цифровую подпись в java. Это было отправлено третьей стороной для справки. Я не java-разработчик. Может ли кто-нибудь сообщить мне, соответствует ли код С#, который я написал, коду Java? если нет, пожалуйста, дайте мне знать, где я ошибаюсь.

private static String createDigitalSignature(Key key, byte[] data) {

    byte[] signature = null;

    try {
        // Initialize xml-security library
        org.apache.xml.security.Init.init();

        // Build DOM document from XML data
        DocumentBuilderFactory dfactory = DocumentBuilderFactory
                .newInstance();
        dfactory.setNamespaceAware(true);
        dfactory.setValidating(true);
        DocumentBuilder documentBuilder = dfactory.newDocumentBuilder();
        // This is to throw away all validation errors
        documentBuilder
                .setErrorHandler(new org.apache.xml.security.utils.IgnoreAllErrorHandler());
        Document doc = documentBuilder
                .parse(new ByteArrayInputStream(data));

        // Build canonicalized XML from document
        Canonicalizer c14n = Canonicalizer
                .getInstance("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
        byte[] canonBytes = c14n.canonicalizeSubtree(doc);

        // Initialize signing object with SHA1 digest and RSA encryption
        Signature rsa = Signature.getInstance("SHA1withRSA");

        // Set private key into signing object
        rsa.initSign((PrivateKey) key);

        // Generate signature
        rsa.update(canonBytes);
        signature = rsa.sign();
    } catch (Exception ex) {
        System.out.println("Exception occurred in createDigitalSignature: "
                + ex.toString());
        System.exit(-1);
    }

    // Base64 encode signature
    BASE64Encoder b64e = new BASE64Encoder();
    String signatureString = b64e.encode(signature);

    return signatureString;
}

person maria koothoor    schedule 21.06.2016    source источник
comment
Можете ли вы опубликовать возвращенную вам ошибку? Нам нужно больше информации. как выглядит wsdl? какова длина вашей подписи?   -  person lumee    schedule 22.06.2016


Ответы (1)


На шаге 3 цифровая подпись — это не совсем то же самое, что и шифрование дайджеста. Цифровая подпись rsa в формате pkcs#1 объединяет OID (идентификатор) дайджестаAlgorithm. со значением дайджеста. Таким образом, вы создаете недействительную подпись.

Во всех языках программирования есть метод выполнения цифровой подписи без использования дайджестов и шифров. Я не программист на С#, но я думаю, вам нужно использовать RSACryptoServiceProvider.SignData

Используйте также VerifyData для проверки подписи.

person pedrofb    schedule 26.06.2016
comment
Благодарю за ваш ответ. Я отредактировал сообщение. Я попробовал другой способ создать подпись. Я использовал метод проверки, и он вернул true. Но он все еще не работает с веб-сервисом. - person maria koothoor; 28.06.2016
comment
Вы хешируете дважды. Подпись RSA также выполняет хеширование. Должно быть byte[] signature = digitalSignature.SignData(document); и bool verified = digitalSignature.VerifySignature(document, signature); - person pedrofb; 28.06.2016
comment
Я изменил его. Но он выдал ошибку, говоря о неправильном хеше в строке DigitalSignature class.rsaFormatter.CreateSignature(hashOfDataToSign); - person maria koothoor; 29.06.2016
comment
Извините, я неправильно прочитал документацию «RSAPKCS1SignatureFormatter. Нужен хэш. Вы можете использовать какой-нибудь онлайн-инструмент для проверки подписи XML. Вы также можете использовать SoapUI для вызова веб-службы, но, похоже, формат подписи не является стандартным. У вас есть пример? - person pedrofb; 29.06.2016
comment
Я отредактировал сообщение с кодом Java, предоставленным внешней службой поддержки веб-сервиса. - person maria koothoor; 30.06.2016
comment
Пожалуйста, не могли бы вы сообщить мне, можно ли использовать это консольное приложение Java в приложении .net в виде исполняемого файла? - person maria koothoor; 07.07.2016
comment
Нет, это невозможно. Я думаю, что если у вас есть функциональный пример Java, вы можете отлаживать код Java и C# для сравнения. Например, если document = Encoding.UTF8.GetBytes(signedXml.ToString()); равно byte[] canonBytes = c14n.canonicalizeSubtree(doc);. Распечатайте их в base64 для сравнения - person pedrofb; 07.07.2016