最近,应用商店服务器API中增加了一个新的API Look Up Order ID。并且该API响应的JWSTransaction由应用商店签名,为JSON Web签名格式。我们希望使用go验证它。
我们所尝试的
1.使用jwt-go,我们尝试按照this question从pem文件中提取公钥。同样按照this link,应该通过从私钥中提取公钥来解码响应
type JWSTransaction struct {
BundleID string `json:"bundleId"`
InAppOwnershipType string `json:"inAppOwnershipType"`
TransactionID string `json:"transactionId"`
ProductID string `json:"productId"`
PurchaseDate int64 `json:"purchaseDate"`
Type string `json:"type"`
OriginalPurchaseDate int64 `json:"originalPurchaseDate"`
}
func (ac *JWSTransaction) Valid() error {
return nil
}
func (a *AppStore) readPrivateKeyFromFile(keyFile string) (*ecdsa.PrivateKey, error) {
bytes, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, err
}
block, _ := pem.Decode(bytes)
if block == nil {
return nil, errors.New("appstore private key must be a valid .p8 PEM file")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
switch pk := key.(type) {
case *ecdsa.PrivateKey:
return pk, nil
default:
return nil, errors.New("appstore private key must be of type ecdsa.PrivateKey")
}
}
func (a *AppStore) ExtractClaims(tokenStr string) (*JWSTransaction, error) {
privateKey, err := a.readPrivateKeyFromFile()
if err != nil {
return nil, err
}
publicKey, err := x509.MarshalPKIXPublicKey(privateKey.Public())
if err != nil {
return nil, err
}
fmt.Println(publicKey)
tran := JWSTransaction{}
token, err := jwt.ParseWithClaims(tokenStr, &tran, func(token *jwt.Token) (interface{}, error) {
fmt.Println(token.Claims)
fmt.Println(token.Method.Alg())
return publicKey, nil
})
if err != nil {
fmt.Println(err)
}
但是,错误key is of invalid type
来自jwt.ParseWithClaims
。
1.另一种方法是通过this link的jwt-go和jwk包验证它。
token, err := jwt.ParseWithClaims(tokenStr, &tran, func(token *jwt.Token) (interface{}, error) {
fmt.Println(token.Claims)
fmt.Println(token.Method.Alg())
kid, ok := token.Header["kid"].(string)
if !ok {
return nil, errors.New("failed to find kid from headers")
}
key, found := keySet.LookupKeyID(kid)
if !found {
return nil, errors.New("failed to find kid from key set")
}
return publicKey, nil
})
但是,我们在应用商店服务器API文档中找不到公钥URL。而且,JWSTransaction的头中没有kid
。
我们想知道如何在Go中验证应用商店服务器API的JWS事务?我还缺少什么吗?
3条答案
按热度按时间rkue9o1l1#
感谢Paulw11,根据文件
“x5 c”(X.509证书链)报头参数包含与用于对JWS进行数字签名的密钥相对应的X.509公钥证书或证书链[RFC 5280]。
更新01/26/2022
为了使用来自site的apple根密钥验证x5 c头的根证书
参考这个循环。下面是示例代码
更新01/30/2022
添加验证中间证书逻辑如下
实现的细节可以在这里找到https://github.com/richzw/appstore
ni65a41a2#
我们真的需要一个golang库,可以做到这一点,我目前正在实现一个服务器回调,可以合并在一个开源库,使其更容易在golang实现。
t5zmwmid3#
如果我错了请纠正我,但最高分的答案似乎对我来说并不正确。证书链没有经过验证,用于验证消息的公钥来自根本没有经过验证的叶子证书。看起来我可以通过将证书链放在JWSDecodedHeader的x5c字段中来伪造一条假消息:
1.我自己颁发的证书
1.苹果的中级证书
1.苹果的根证书因为这个代码只验证最后2个的真实性,而不检查第一个是否是由第二个颁发的,所以我可以把我想要的任何东西放在那里。
我认为,为了验证链中的第一个证书是否有效,它缺少以下内容: