0

我有一个 x509 证书作为文件/字节数组,我想用它来验证CertificateVerifyTLS 消息中提供的签名。我想我可以SecKeyVerifySignature在确定证书的密钥算法(参数)并从成绩单哈希(连接到上下文字符串等)中SecKeyAlgorithm初始化之后使用。signedData

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);

但是,我无法找到一种方法来提取密钥的签名算法(公钥算法)。我发现SecKeyIsAlgorithmSupported。我是否需要遍历所有可能的SecKeyAlgorithm常量以找到密钥正在使用的常量(即 a SecKeyAlgorithmfor id-ecPublicKey)?

4

1 回答 1

0

我误解了自己的目标。

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");
}
于 2020-04-18T14:14:10.083 回答