Проверка подписи DSA, сгенерированной PKCS#11 с OpenSSL

Я хочу подписать хэш SHA-256 с DSA, используя оболочку Java PKCS#11 для API PKCS#11 модуля аппаратной защиты. Для этого я выбрал Механизм CKM_DSA, загрузил соответствующий ключ DSA из токена и подписал данные (считанные как байтовый массив). Ключ, который я использую для тестирования, имеет длину 1024 бита.

Кажется, все работает нормально: ключ загружен, Session.sign() возвращает массив byte[] длиной 40. Это соответствует спецификации PKCS#11, которая гласит:

"Для целей этого механизма сигнатура DSA представляет собой 40-байтовую строку, соответствующую объединению значений r и s DSA, каждое из которых представляет собой старший значащий байт первым".

Теперь я хочу проверить эту подпись, используя openSSL, то есть, используя

openssl dgst -d -sha256 -verify ${PUBLIC_KEY} -signature signature.der <raw input file>

Это работает, если я

а) создал подпись с помощью OpenSSL

b) создал подпись с использованием bouncycastle и закодировал результат как последовательность DER в кодировке ASN1.

Теперь я хочу сделать то же самое с подписью PKCS#11. Мой вопрос: как отформатировать этот 40-байтовый массив? Я попробовал следующее:

        //sign data
        byte[] signedData = this.pkcs11Session.sign(dataToSign);
        //convert result
        byte[] r = new byte[20];
        byte[] s = new byte[20];
        System.arraycopy(signedData, 0, r, 0, 20);
        System.arraycopy(signedData, 19, s, 0, 20);

        //encode result
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new ASN1Integer(r));
        v.add(new ASN1Integer(s));
        return new DERSequence(v).getEncoded(ASN1Encoding.DER);

Часть кодирования кажется правильной, потому что она работает, если я создаю r и s напрямую с bouncycastle и другим программным ключом. Кроме того, openssl принимает формат ввода, но проверка иногда завершается с ошибкой, иногда просто с "Ошибка проверки".

Таким образом, я предполагаю, что преобразование подписи PKCS#11 в r и s неверно. Может ли кто-нибудь помочь найти ошибку?

1 ответ

Вы, вероятно, должны конвертировать r а также s значения в BigInteger класс, прежде чем сделать. Причина этого заключается в том, что ASN.1 использует кодирование со знаком, а DH приводит к кодированию без знака. Таким образом, у вас довольно высокий шанс получить отрицательное значение в ASN.1, что приведет к ошибке.

Чтобы выполнить преобразование, используйте new BigInteger(1, r) а также new BigInteger(1, s) и положить результат в ASN1Integer экземпляров. Здесь 1 указывает, что значение необходимо преобразовать в положительное значение (т. Е. Вход является положительным без знака).

Другие вопросы по тегам