(2017-05-23 10:40:22 отредактировано kpalych)

Проверка подписи под PHP7

Добрый день!

Имеются данные, подписанные RSA (2048bit) ключом на Рутокен ЭЦП 2.0 Flash.
На стороне сервера (Ubuntu + Nginx + PHP) аппаратного токена естественно нет.

Как проверить подпись на PHP имея в наличии
- Исходные даные (UTF-8 строка);
- Сертификат открытого ключа (выдан Тестовым Удостоверяющим Центром ООО "КРИПТО-ПРО")
- Значение подписи (base64_encoded)?

Нижеприведенная конструкция конструкция дает отрицательный результат:

<?php
$str = 'Test string';
$signature = 'EsucP09CXnuaP3gOmB1GgmPAqVvKAP6q2qKHNHkdr5Xy1rYbYDTNgK0ue97SP9Zl52M8GSpXFvuRfzhlQ6Qg1Uk0CiTXHU9WgoZTFw8A1q83LmSMRoSM82/I5nW+tY9Qap4kqubupA6pN5aDOte6KuVhDLcy4NXD3EF08cz6Q5UyLlnujao4BYUAKWiPte0vofisZ1Oj9kNN/VKOxYv++zd5pw9PuGAt8tUhz1AMTTZjm9l+MROtbzhybjtPMSlD60/CxEx7Opgkg2UPczDSfQGsQcjWGwnq3iDkum0tukgtiz0g513jRZ8lwC6uMvCBtVDcR00JUUNSQZ32WKEUww==';

$certificateCApemContent =  file_get_contents($_SERVER['DOCUMENT_ROOT'].'/cert.pem');

$pubkeyid = openssl_get_publickey($certificateCApemContent);

$ok = openssl_verify(md5($str, true), base64_decode($signature), $pubkeyid, OPENSSL_ALGO_MD5);
if ($ok == 1) {
    echo "ЭЦП корректна :)";
} elseif ($ok == 0) {
    echo "ЭЦП не корректна!";
} else {
    echo "Error: " . openssl_error_string();
}

openssl_free_key($pubkeyid);

?>

Подписывались данные на C# (библиотека Pkcs11Interop):

                using (Session session = m_Slot.OpenSession(false))
                {
                    session.Login(CKU.CKU_USER, m_UserPIN);

                    ObjectHandle publicKey = null;
                    ObjectHandle privateKey = null;
                    if (_getKeyPairHandles(session, keyPairLabel, out privateKey, out publicKey))
                    {
                        Mechanism mechanism = new Mechanism(CKM.CKM_MD5);
                        byte[] sourceData = ConvertUtils.Utf8StringToBytes(data);
                        byte[] digest = session.Digest(mechanism, sourceData);

                        mechanism = new Mechanism(CKM.CKM_RSA_PKCS);

                        signature = session.Sign(mechanism, privateKey, digest);
                    }
                    session.Logout();
                }

Проверка на C# проходит успешно:

            bool success = false;

            RSACryptoServiceProvider rsa = null;

            byte[] bytesToVerify = ConvertUtils.Utf8StringToBytes(originalMessage);
            byte[] signedBytes = Convert.FromBase64String(signature);
            try
            {
                X509Certificate2 cert = new X509Certificate2((certValue != "" ? Convert.FromBase64String(certValue) : m_Certificate), "");
                rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;

                success = rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID("MD5"), signedBytes);
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                if (rsa != null) rsa.PersistKeyInCsp = false;
            }

            return success;

Подскажите как проверить валидность подписи на PHP.

Re: Проверка подписи под PHP7

kpalych пишет:

Добрый день!
Нижеприведенная конструкция конструкция дает отрицательный результат:

...
$ok = openssl_verify(md5($str, true), base64_decode($signature), $pubkeyid, OPENSSL_ALGO_MD5);
if ($ok == 1) {
    echo "ЭЦП корректна :)";
} elseif ($ok == 0) {
    echo "ЭЦП не корректна!";
} else {
    echo "Error: " . openssl_error_string();
}
...

Добрый день, kpalych!

На вход openssl_verify надо подавать не хэш, а данные:
$str, вместо md5($str, true)

Re: Проверка подписи под PHP7

Спасибо за оперативный ответ!

К сожалению конструкция

$ok = openssl_verify($str, base64_decode($signature), $pubkeyid, OPENSSL_ALGO_MD5);

так же дает отрицательный результат...

Возможно на сервере необходима установка каких либо дополнительных плагинов для поддержки ruToken?

Требуется ли установка какого либо ПО на сервере?

Re: Проверка подписи под PHP7

Отрицательный результат это -1 (ошибка при проверке подписи) или 1 (подпись неверна)?
Если -1, то что пишет openssl_error_string?

Re: Проверка подписи под PHP7

Результат 0, срабатывает ветка:

} elseif ($ok == 0) {
    echo "ЭЦП не корректна!";
}

Re: Проверка подписи под PHP7

Попробуйте на проверку передать сам сертификат.
Если не поможет, можно ещё дополнительно убедиться, что открытые ключи совпадают при проверке в php и в C#.
И на крайний случай – попробовать пореверсить буферы (подпись, ключ)

Re: Проверка подписи под PHP7

Возможно, проблема в "УЦ Крипто-Про" и в OpenSSL.
УЦ - подписывает ваш RSA-сертификат, ГОСТ-ключевой парой, а в OpenSSL возможно, возникают проблемы с такого рода "гибридными" сертификатами. Для того чтобы удостовериться в этом, советуем вам найти другой тестовый УЦ, который подписывает RSA-ключевой парой.