fix(iap): 修复JWS验证逻辑,支持原始R||S签名格式
Build docker and publish / build (20.15.1) (push) Successful in 6m38s
Build docker and publish / build (20.15.1) (push) Successful in 6m38s
fix(middleware): 增加设备中间件的日志记录 fix(auth): 优化认证中间件的错误日志记录 feat(iap): 添加苹果交易附加逻辑的详细日志
This commit is contained in:
+30
-22
@@ -6,6 +6,7 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
@@ -21,20 +22,26 @@ func cleanB64(s string) string {
|
||||
}, trimmed)
|
||||
}
|
||||
|
||||
func decodeB64URL(s string) ([]byte, error) {
|
||||
s = cleanB64(s)
|
||||
if b, err := base64.RawURLEncoding.DecodeString(s); err == nil {
|
||||
return b, nil
|
||||
}
|
||||
switch len(s) % 4 {
|
||||
case 2:
|
||||
s += "=="
|
||||
case 3:
|
||||
s += "="
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(s)
|
||||
}
|
||||
|
||||
func ParseTransactionJWS(jws string) (*TransactionPayload, error) {
|
||||
parts := strings.Split(strings.TrimSpace(jws), ".")
|
||||
if len(parts) != 3 {
|
||||
return nil, ErrInvalidJWS
|
||||
}
|
||||
payloadB64 := cleanB64(parts[1])
|
||||
// add padding if required
|
||||
switch len(payloadB64) % 4 {
|
||||
case 2:
|
||||
payloadB64 += "=="
|
||||
case 3:
|
||||
payloadB64 += "="
|
||||
}
|
||||
data, err := base64.RawURLEncoding.DecodeString(payloadB64)
|
||||
data, err := decodeB64URL(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -78,15 +85,8 @@ func VerifyTransactionJWS(jws string) (*TransactionPayload, error) {
|
||||
if len(parts) != 3 {
|
||||
return nil, ErrInvalidJWS
|
||||
}
|
||||
hdrB64 := cleanB64(parts[0])
|
||||
switch len(hdrB64) % 4 {
|
||||
case 2:
|
||||
hdrB64 += "=="
|
||||
case 3:
|
||||
hdrB64 += "="
|
||||
}
|
||||
var hdr jwsHeader
|
||||
hdrBytes, err := base64.RawURLEncoding.DecodeString(hdrB64)
|
||||
hdrBytes, err := decodeB64URL(parts[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -109,14 +109,22 @@ func VerifyTransactionJWS(jws string) (*TransactionPayload, error) {
|
||||
return nil, ErrInvalidJWS
|
||||
}
|
||||
signingInput := cleanB64(parts[0]) + "." + cleanB64(parts[1])
|
||||
sig := cleanB64(parts[2])
|
||||
sigBytes, err := base64.RawURLEncoding.DecodeString(sig)
|
||||
sigBytes, err := decodeB64URL(parts[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d := sha256.Sum256([]byte(signingInput))
|
||||
if !ecdsa.VerifyASN1(pub, d[:], sigBytes) {
|
||||
return nil, ErrInvalidJWS
|
||||
// Try ASN.1 signature first
|
||||
if ecdsa.VerifyASN1(pub, d[:], sigBytes) {
|
||||
return ParseTransactionJWS(jws)
|
||||
}
|
||||
return ParseTransactionJWS(jws)
|
||||
// Fallback: raw R||S (JWS ES256 uses raw signature)
|
||||
if len(sigBytes) == 64 {
|
||||
r := new(big.Int).SetBytes(sigBytes[:32])
|
||||
s := new(big.Int).SetBytes(sigBytes[32:])
|
||||
if ecdsa.Verify(pub, d[:], r, s) {
|
||||
return ParseTransactionJWS(jws)
|
||||
}
|
||||
}
|
||||
return nil, ErrInvalidJWS
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user