【问题标题】:Marshal AppleID's Public Key to rsa.PublicKeyMarshal AppleID 的公钥到 rsa.PublicKey
【发布时间】:2021-02-05 16:53:06
【问题描述】:

我正在尝试在 Go 中验证来自 Apple 的 JWT,我需要他们的公钥作为 Go 的 rsa.PublicKey 来执行此操作。我从以下指定的端点检索了他们的密钥:

https://developer.apple.com/documentation/sign_in_with_apple/fetch_apple_s_public_key_for_verifying_token_signature

得到以下结果:

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "86D88Kf",
      "use": "sig",
      "alg": "RS256",
      "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ",
      "e": "AQAB"
    },
    {
      "kty": "RSA",
      "kid": "eXaunmL",
      "use": "sig",
      "alg": "RS256",
      "n": "4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw",
      "e": "AQAB"
    }
  ]
}

我尝试了x509.ParsePKCS1PublicKey(...) 函数,方法是解析单个键和使用asn1.Marshall(...) 函数返回的整个JSON。我在尝试解析 der 时出错。

然后我注意到密钥包含"n""e" 字符串对,并且定义为here,所以我尝试直接创建公钥。但是,rsa.PublicKey 中的NE 分别是*big.Intint

我似乎找不到"n""e" 的编码,所以我无法准确地将这些值转换为rsa.PublicKey。我试过base64,但是没用。

谁能告诉我如何将 Apple 的公钥转换为合适的rsa.PublicKey

【问题讨论】:

    标签: go oauth-2.0 jwt rsa


    【解决方案1】:

    您的 JSON 中的 "n""e" 的值只是 base64 编码的大端二进制整数,因此一旦您对它们进行解码,您可以将它们转换为类型为 *big.Intbig.Int.SetBytes,然后使用这些来填充*rsa.PublicKey

    您提到您尝试过 base64,但它不起作用,但您需要确保使用正确的编码和填充选项 - 编码字符串中存在 -_ 字符表示您正在处理 RFC 4648 URL 安全编码,并且字符串的长度不能被 4 整除这一事实表明不存在填充字符,因此您需要使用 base64.URLEncoding.WithPadding(base64.NoPadding)

    您可以直接解组和转换的类型的综合示例:

    package main
    
    import (
            "crypto/rsa"
            "encoding/base64"
            "encoding/json"
            "log"
            "math/big"
    )
    
    const keyJSON = `{
        "kty": "RSA",
        "kid": "86D88Kf",
        "use": "sig",
        "alg": "RS256",
        "n": "4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw",
        "e": "AQAB"
    }`
    
    // decodeBase64BigInt decodes a base64-encoded larger integer from Apple's key format.
    func decodeBase64BigInt(s string) *big.Int {
            buffer, err := base64.URLEncoding.WithPadding(base64.NoPadding).DecodeString(s)
            if err != nil {
                    log.Fatalf("failed to decode base64: %v", err)
            }
    
            return big.NewInt(0).SetBytes(buffer)
    }
    
    // appleKey is a type of public key.
    type appleKey struct {
            KTY string
            KID string
            Use string
            Alg string
            N   *big.Int
            E   int
    }
    
    // UnmarshalJSON parses a JSON-encoded value and stores the result in the object.
    func (k *appleKey) UnmarshalJSON(b []byte) error {
            var tmp struct {
                    KTY string `json:"kty"`
                    KID string `json:"kid"`
                    Use string `json:"use"`
                    Alg string `json:"alg"`
                    N   string `json:"n"`
                    E   string `json:"e"`
            }
    
            if err := json.Unmarshal(b, &tmp); err != nil {
                    return err
            }
    
            *k = appleKey{
                    KTY: tmp.KTY,
                    KID: tmp.KID,
                    Use: tmp.Use,
                    Alg: tmp.Alg,
                    N:   decodeBase64BigInt(tmp.N),
                    E:   int(decodeBase64BigInt(tmp.E).Int64()),
            }
    
            return nil
    }
    
    // RSA returns a corresponding *rsa.PublicKey
    func (k appleKey) RSA() *rsa.PublicKey {
            return &rsa.PublicKey{
                    N: k.N,
                    E: k.E,
            }
    }
    
    func main() {
            // Decode the Apple key.
            var ak appleKey
            if err := json.Unmarshal([]byte(keyJSON), &ak); err != nil {
                    log.Fatalf("failed to unmarshal JSON: %v", err)
            }
    
            // Convert it to a normal *rsa.PublicKey.
            rk := ak.RSA()
    
            if rk.Size() != 256 {
                    log.Fatalf("unexpected key size: %d", rk.Size())
            }
    
            // Do what you like with the RSA key now.
    }
    

    【讨论】:

    • 我不知道base64还有更多的编码格式。这对您很有帮助,谢谢。
    猜你喜欢
    • 2021-03-02
    • 2020-12-19
    • 2017-02-06
    • 2019-02-22
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    • 2016-03-27
    相关资源
    最近更新 更多