Как разобрать сертификат x509 и извлечь алгоритм подписи его ключа? - PullRequest
1 голос
/ 11 апреля 2020

У меня есть сертификат x509 в виде массива файлов / байтов, который я хотел бы использовать для проверки подписи, указанной в сообщении CertificateVerify TLS. Я думаю, что смогу использовать SecKeyVerifySignature после того, как определю алгоритм ключа сертификата (параметр SecKeyAlgorithm) и инициализирую signedData из транскрипта ha sh (сцепленный) в контекстную строку, et c.).

openssl x509 сообщает о ключе сертификата как

Subject Public Key Info:
    Public Key Algorithm: id-ecPublicKey
        Public-Key: (256 bit)
        pub:
            04:44:58:8c:d0:95:90:14:45:82:db:4f:56:41:7d:
            57:0e:f5:b4:d8:65:04:6c:21:5a:cd:1e:0e:87:10:
            f9:31:c6:fa:b9:ad:b3:a5:e1:df:9f:32:25:4b:a9:
            40:5c:d4:56:0d:bb:55:fd:f4:68:f9:4e:89:70:56:
            b9:1c:4a:ef:93
        ASN1 OID: prime256v1
        NIST CURVE: P-256 

Я считаю, что могу проанализировать сертификат с помощью механизма, описанного здесь , например.

CFDataRef certData = CFDataCreate(NULL, (const UInt8*) rawCert, len);
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, certData);

И я думаю, что могу использовать SecCertificateCopyKey для извлечения ключа, например.

SecKeyRef key = SecCertificateCopyKey(certificate);

Я не могу Однако найдите способ извлечь алгоритм подписи ключа (Publi c Key Algorithm). Я нашел SecKeyIsAlgorithmSupported. Нужно ли перебирать все возможные SecKeyAlgorithm константы, чтобы найти ту, которую использует ключ (ie. A SecKeyAlgorithm для id-ecPublicKey)?

1 Ответ

0 голосов
/ 18 апреля 2020

Я неправильно понял свои собственные цели.

В сообщении CertificateVerify дайджест рукопожатия до этого момента. Сервер использует закрытый ключ своего сертификата для выполнения этой подписи. Как указано в спецификации TLS 1.3 , алгоритм подписи является частью структуры CertificateVerify

struct {
    SignatureScheme algorithm;
    opaque signature<0..2^16-1>;
} CertificateVerify;

Мне просто нужно извлечь ее и преобразовать в SecKeyAlgorithm. Например (с C ++)

SecKeyAlgorithm keyAlgorithm;
// algorithm extracted from CertificateVerify
switch (algorithm) {
  case SignatureScheme::ecdsa_secp256r1_sha256:
    keyAlgorithm = kSecKeyAlgorithmECDSASignatureDigestX962SHA256;
    break;
  case SignatureScheme::rsa_pss_sha256:
    keyAlgorithm = kSecKeyAlgorithmRSASignatureDigestPSSSHA256;
    break;
  case SignatureScheme::ed25519:
  case SignatureScheme::ed448:
  default:
    throw std::runtime_error("unsupported peer cert type");
}

Затем я могу подтвердить, что сертификат поддерживает этот алгоритм

if (!SecKeyIsAlgorithmSupported(key, kSecKeyOperationTypeVerify, keyAlgorithm)) {
  CFRelease(publicKey);
  throw std::runtime_error("Unsupported signature scheme");
}

и, наконец, выполнить проверку с помощью signature в CertificateVerify и скомпилированные подписанные данные из рукопожатия

CFErrorRef error;
bool signatureVerified = SecKeyVerifySignature(key, keyAlgorithm, toBeSignedData, signature, &error);
if (!signatureVerified) {
  CFRelease(error); // or use it
  throw std::runtime_error("Signature verification failed");
}
...