You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在OpenSSL中使用Apple身份验证公钥?PHP调用报错排查

如何使用Apple公钥配合OpenSSL(PHP实现)

你尝试使用Apple身份验证服务的公钥配合OpenSSL,但代码运行报错,错误信息如下:

Fatal error: Uncaught TypeError: openssl_pkey_get_details(): Argument #1 ($key) must be of type OpenSSLAsymmetricKey

你的代码:

<?php
$key = '-----BEGIN PUBLIC KEY-----'. "
".chunk_split("1JiU4l3YCeT4o0gVmxGTEK1IXR-Ghdg5Bzka12tzmtdCxU00ChH66aV-4HRBjF1t95IsaeHeDFRgmF0lJbTDTqa6_VZo2hc0zTiUAsGLacN6slePvDcR1IMucQGtPP5tGhIbU-HKabsKOFdD4VQ5PCXifjpN9R-1qOR571BxCAl4u1kUUIePAAJcBcqGRFSI_I1j_jbN3gflK_8ZNmgnPrXA0kZXzj1I7ZHgekGbZoxmDrzYm2zmja1MsE5A_JX7itBYnlR41LOtvLRCNtw7K3EFlbfB6hkPL-Swk5XNGbWZdTROmaTNzJhV-lWT0gGm6V1qWAK2qOZoIDa_3Ud0Gw", 64).'-----END PUBLIC KEY-----';

print_r($key);
$res = openssl_pkey_get_public($key);

print_r(openssl_pkey_get_details($res));

问题原因

从Apple接口获取的是JWK格式的公钥(JSON Web Key),你直接把JWK里的n值(模数值)拼接成PEM格式是错误的:

  • RSA公钥需要同时包含模(n)和指数(e)两个核心参数,你的代码缺少指数部分
  • base64url编码的n值需要先转换为普通base64,再解码为二进制,不能直接作为PEM内容
  • 未按照RSA公钥的ASN.1结构组装,导致OpenSSL无法识别为有效公钥,openssl_pkey_get_public返回false,后续调用openssl_pkey_get_details自然会触发类型错误

解决步骤

1. 获取并解析Apple的JWK密钥集

先请求Apple的接口获取密钥集,解析出对应kid的JWK(通常需要和ID Token里的kid匹配):

$jwks = json_decode(file_get_contents('https://appleid.apple.com/auth/keys'), true);
// 假设你已经拿到对应kid的JWK,比如取第一个
$jwk = $jwks['keys'][0];

2. 将JWK转换为PEM格式公钥

推荐使用成熟库简化转换,比如phpseclib(需通过Composer安装:composer require phpseclib/phpseclib):

use phpseclib3\Crypt\RSA;

$rsa = RSA::loadJWK(json_encode($jwk));
$pem = $rsa->getPublicKey()->toString('PKCS8');

如果不想用第三方库,可以手动处理(需处理base64url解码、ASN.1组装):

// base64url转base64
function base64url_decode($data) {
    return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}

$n = base64url_decode($jwk['n']);
$e = base64url_decode($jwk['e']);

// 组装ASN.1结构
$modulus = pack('Ca*a*', 2, strlen($n), $n);
$exponent = pack('Ca*a*', 2, strlen($e), $e);
$rsa_public_key = pack('Ca*a*', 48, strlen($modulus.$exponent), $modulus.$exponent);

// 转为PEM格式
$pem = '-----BEGIN PUBLIC KEY-----' . PHP_EOL;
$pem .= chunk_split(base64_encode($rsa_public_key), 64, PHP_EOL);
$pem .= '-----END PUBLIC KEY-----';

3. 正确加载并使用公钥

$res = openssl_pkey_get_public($pem);
if ($res === false) {
    die('公钥加载失败:' . openssl_error_string());
}

// 获取公钥详情
$details = openssl_pkey_get_details($res);
print_r($details);

// 后续可用于验证Apple ID Token等操作
// openssl_verify(...)

内容的提问来源于stack exchange,提问作者zzzdzdzd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:15:35