我在 x509(作为 JWS 中的 x5c 标头)中验证哪些字段以证明证书的合法性?
Posted
技术标签:
【中文标题】我在 x509(作为 JWS 中的 x5c 标头)中验证哪些字段以证明证书的合法性?【英文标题】:What fields do I verify in a x509 (as x5c header in a JWS) to prove legitimacy of the Certificate? 【发布时间】:2021-12-17 07:49:14 【问题描述】:我已经发布了一个类似的问题 here,但我意识到我的问题可能更多地与 x509 证书有关,而不是一般的 JWS。
事情是这样的,我对 JWS 还很陌生,Apple 现在将它们作为服务器到服务器通信的一部分进行传输。我试图了解如何充分保证 JWS 的有效性,因为据我了解,签名验证仅意味着整个 JWS 没有被篡改。 我不知道如何真正验证此有效负载确实来自受信任的来源(又名 Apple)。
这是我目前得到的(php):
//1. explode jws and decode what's needed
$components = explode('.', $jws);
$headerJson = json_decode(base64_decode($components[0]),true);
$signature = base64Url_decode($components[2]);
//2. extract all certificates from 'x5c' header
foreach ($headerJson['x5c'] as $x5c)
$c = '-----BEGIN CERTIFICATE-----'.PHP_EOL;
$c .= chunk_split($x5c,64,PHP_EOL);
$c .= '-----END CERTIFICATE-----'.PHP_EOL;
$certificates[] = openssl_x509_read($c);
//3. verify validity of certificate chain (each one is signed by the next, except root cert)
for($i = 0; $i < count($certificates); $i++)
if ($i == count($certificates) - 1)
if (openssl_x509_verify($certificates[$i], $certificates[$i]) != 1)
throw new Exception("Invalid Root Certificate");
else
if (openssl_x509_verify($certificates[$i], $certificates[$i+1]) != 1)
throw new Exception("Invalid Certificate");
//4. get public_key from first certificate
$public_key = openssl_pkey_get_public($certificates[0]);
//5. verify entire token, including signature (using the Firebase library)
$parsed_token = (array) \Firebase\JWT\JWT::decode($jws, $public_key, ['ES256']);
//helper function: a simple base64 url decoder
function base64Url_decode($data)
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
证书内部是否有特定字段可供检查(不能被欺骗)以验证 JWS 的身份/来源?
谢谢!
【问题讨论】:
我认为这里的关键概念与 HTTPS 连接相同:您应该有一个硬编码的“信任锚”或“根证书”,您已独立收到JWS,然后“证书链”提供从那里到实际签名的一系列链接(每个证书颁发者“担保”链中的下一个)。不过,我不会将其作为答案发布,因为我不确切知道要验证的代码是什么样的。 @IMSoP 嘿,谢谢你的回答。所以在这张纸条上,我刚刚发现了一篇九月份的文章,上面写着For the moment, Apple has not published the root certificate used to validate the chain. We'll update this article when they do
。我刚刚继续https://www.apple.com/certificateauthority/
,他们有 4 个根证书(我可以看到第 4 个与 x5c 标头中的最后一个匹配)。那么我该怎么做呢?
@IMSoP 所以,我继续下载它,将其转换为.pem
格式,然后在步骤#3 中,我没有自己验证根证书,而是用下载的那个来验证它。有效。是这样吗?我只是将该证书存储在服务器上并始终将根 CA 与它进行比较?
是的,我想差不多就是这样。一般的想法是您在链中找到一个由您下载的根签名的证书;然后是由那个签名的;依此类推,直到您获得签署 JWS 本身的证书。正如我所说,这是关于每个证书“担保”下一个证书,所以没有人可以在你不注意的情况下换掉中间的证书。
@IMSoP 好的,因为我在 x5c 标头中获得了 3 个证书,这应该是逻辑:第一个签署 JWS,第二个签署第一个,第三个(也是最后一个)签署签署第二个。最后,因为最后一个是root,所以我们使用下载的那个来确保它是自己签名的。太棒了,非常感谢!您肯定为我指明了正确的方向,并帮助我更好地理解了这一点!
【参考方案1】:
感谢@IMSoP 为我指明了正确的方向。
当 JWS 包含证书链(x5c
标头)时,我们应该拥有这些有效证书的副本(或者至少是根证书,因为它会验证链的其余部分)。就我而言,我可以在 Apple's website 上找到它们。
下载它们后,就很简单了:
openssl_x509_verify($jws_root_cert, $downloaded_apple_root_cert);
【讨论】:
以上是关于我在 x509(作为 JWS 中的 x5c 标头)中验证哪些字段以证明证书的合法性?的主要内容,如果未能解决你的问题,请参考以下文章
io.jsonwebtoken.UnsupportedJwtException:不支持签名声明 JWS