优化结构
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -20,12 +25,16 @@ const (
|
||||
var (
|
||||
appleJWSLeafExtensionOID = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 6, 11, 1}
|
||||
appleJWSIntermediateExtensionOID = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 6, 2, 1}
|
||||
appleTrustedRootFingerprints = map[string]struct{}{
|
||||
"63343abfb89a6a03ebb57e9b3f5fa7be7c4f5c756f3017b3a8c488c3653e9179": {},
|
||||
}
|
||||
)
|
||||
|
||||
// validateAppleJWSChain binds the leaf certificate used by GoPay for JWS
|
||||
// signature verification to the intermediate and root certificates that
|
||||
// GoPay validates against its embedded Apple trust anchor.
|
||||
func validateAppleJWSChain(signedPayload string) error {
|
||||
return validateAppleJWSChainWithRoots(signedPayload, appleTrustedRootFingerprints)
|
||||
}
|
||||
|
||||
func validateAppleJWSChainWithRoots(signedPayload string, trustedRoots map[string]struct{}) error {
|
||||
headerSegment, payloadSegment, signatureSegment, err := splitAppleJWS(signedPayload)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -73,6 +82,10 @@ func validateAppleJWSChain(signedPayload string) error {
|
||||
}
|
||||
certificates = append(certificates, certificate)
|
||||
}
|
||||
rootFingerprint := sha256.Sum256(certificates[2].Raw)
|
||||
if _, trusted := trustedRoots[hex.EncodeToString(rootFingerprint[:])]; !trusted {
|
||||
return errors.New("Apple JWS 根证书不受信任")
|
||||
}
|
||||
if err = certificates[0].CheckSignatureFrom(certificates[1]); err != nil {
|
||||
return fmt.Errorf("Apple JWS 叶子证书不属于声明的证书链: %w", err)
|
||||
}
|
||||
@@ -101,19 +114,20 @@ func validateAppleJWSChain(signedPayload string) error {
|
||||
return errors.New("Apple JWS 中间证书缺少 Apple 签名扩展")
|
||||
}
|
||||
|
||||
if hasVerificationTime {
|
||||
roots := x509.NewCertPool()
|
||||
roots.AddCert(certificates[2])
|
||||
intermediates := x509.NewCertPool()
|
||||
intermediates.AddCert(certificates[1])
|
||||
if _, err = certificates[0].Verify(x509.VerifyOptions{
|
||||
Roots: roots,
|
||||
Intermediates: intermediates,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||
CurrentTime: verificationTime,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("验证 Apple JWS 证书链: %w", err)
|
||||
}
|
||||
if !hasVerificationTime {
|
||||
verificationTime = time.Now()
|
||||
}
|
||||
roots := x509.NewCertPool()
|
||||
roots.AddCert(certificates[2])
|
||||
intermediates := x509.NewCertPool()
|
||||
intermediates.AddCert(certificates[1])
|
||||
if _, err = certificates[0].Verify(x509.VerifyOptions{
|
||||
Roots: roots,
|
||||
Intermediates: intermediates,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||
CurrentTime: verificationTime,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("验证 Apple JWS 证书链: %w", err)
|
||||
}
|
||||
if certificates[0].IsCA {
|
||||
return errors.New("Apple JWS 叶子证书不能是 CA")
|
||||
@@ -121,6 +135,18 @@ func validateAppleJWSChain(signedPayload string) error {
|
||||
if certificates[0].KeyUsage != 0 && certificates[0].KeyUsage&x509.KeyUsageDigitalSignature == 0 {
|
||||
return errors.New("Apple JWS 叶子证书不允许数字签名")
|
||||
}
|
||||
publicKey, ok := certificates[0].PublicKey.(*ecdsa.PublicKey)
|
||||
if !ok || publicKey.Curve != elliptic.P256() {
|
||||
return errors.New("Apple JWS 叶子证书不是 P-256 ECDSA 公钥")
|
||||
}
|
||||
signature, err := base64.RawURLEncoding.DecodeString(signatureSegment)
|
||||
if err != nil || len(signature) != 64 {
|
||||
return errors.New("Apple JWS ES256 签名格式无效")
|
||||
}
|
||||
digest := sha256.Sum256([]byte(headerSegment + "." + payloadSegment))
|
||||
if !ecdsa.Verify(publicKey, digest[:], new(big.Int).SetBytes(signature[:32]), new(big.Int).SetBytes(signature[32:])) {
|
||||
return errors.New("Apple JWS 签名校验失败")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user