在 Go Server 中为 IOS 生成订阅报价签名时出现问题
Posted
技术标签:
【中文标题】在 Go Server 中为 IOS 生成订阅报价签名时出现问题【英文标题】:Issue while generating subscription offer signature for IOS in Go Server 【发布时间】:2021-11-08 10:42:53 【问题描述】:Go 版本:go 版本 go1.16.7 linux/amd64
进口:
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"math/big"
"net/http"
"time"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"go.mongodb.org/mongo-driver/mongo"
)
我正在使用的代码
var (
// the id and private key below is got from here:
// https://developer.apple.com/documentation/storekit/in-app_purchase/generating_a_subscription_offer_signature_using_node_js
AppleKeyId = "mykeyid"
ApplePrivateKey = `-----BEGIN PRIVATE KEY-----
MyKey
-----END PRIVATE KEY-----`
privateKey, _ = AuthKeyFromBytes([]byte(ApplePrivateKey))
sep = "\u2063"
AppBundleID = "mybundlename"
)
func AuthKeyFromBytes(key []byte) (*ecdsa.PrivateKey, error)
var err error
// Parse PEM block
var block *pem.Block
if block, _ = pem.Decode(key); block == nil
return nil, errors.New("token: AuthKey must be a valid .p8 PEM file")
// Parse the key
var parsedKey interface
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil
return nil, err
var pkey *ecdsa.PrivateKey
var ok bool
if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok
return nil, errors.New("token: AuthKey must be of type ecdsa.privateKey")
return pkey, nil
type SignParams struct
ProductIdentifier string `json:"productIdentifier"`
OfferID string `json:"offerID"`
ApplicationUsername string `json:"applicationUsername"`
type SignResult struct
KeyID string `json:"keyID"`
Nonce string `json:"nonce"`
Timestamp int64 `json:"timestamp"`
Signature string `json:"signature"`
func Sign(params *SignParams) (SignResult, error)
nonce := uuid.NewV4().String()
timestamp := time.Now().UnixNano() / 1000000
payload := AppBundleID + sep +
AppleKeyId + sep +
params.ProductIdentifier + sep +
params.OfferID + sep +
params.ApplicationUsername + sep +
nonce + sep +
fmt.Sprintf("%v", timestamp)
hash := sha256.Sum256([]byte(payload))
sig, err := privateKey.Sign(rand.Reader, hash[:], nil) Error Here
if err != nil
return SignResult, err
return SignResult
KeyID: AppleKeyId,
Nonce: nonce,
Timestamp: timestamp,
Signature: base64.StdEncoding.EncodeToString(sig),
, nil
问题:sig, err := privateKey.Sign(rand.Reader, hash[:], nil) in Sign Function
控制台出错:
2021/09/13 09:47:59 [Recovery] 2021/09/13 - 09:47:59 panic recovered:
POST /signatures HTTP/1.1
Host: localhost:5000
Accept: */*
Accept-Encoding: gzip, deflate, br
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 114
Content-Type: application/json
Postman-Token: 12f5ac0a-3379-40ad-826e-78dc63579cbb
User-Agent: PostmanRuntime/7.28.4
runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:212 (0x435cda)
panicmem: panic(memoryError)
/usr/local/go/src/runtime/signal_unix.go:734 (0x44e852)
sigpanic: panicmem()
/usr/local/go/src/crypto/ecdsa/ecdsa.go:204 (0x5652b8)
Sign: entropylen := (priv.Curve.Params().BitSize + 7) / 16
/usr/local/go/src/crypto/ecdsa/ecdsa.go:116 (0x564ba4)
(*PrivateKey).Sign: r, s, err := Sign(rand, priv, digest)
/usr/local/go/src/crypto/ecdsa/ecdsa.go:286 (0xd8fd0f)
SignASN1: return priv.Sign(rand, hash, nil)
/home/zainkhan/GolandProjects/kotc-server/controllers/signature.go:121 (0xd8fcc1)
Sign: sig, err := ecdsa.SignASN1(rand.Reader, privateKey, hash[:])
/home/zainkhan/GolandProjects/kotc-server/controllers/signature.go:39 (0xd8f284)
(*signaturesController).post: final, err := Sign(req)
/home/zainkhan/GolandProjects/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0x992c99)
(*Context).Next: c.handlers[c.index](c)
/home/zainkhan/GolandProjects/pkg/mod/github.com/gin-gonic/gin@v1.7.3/recovery.go:99 (0x992c80)
CustomRecoveryWithWriter.func1: c.Next()
/home/zainkhan/GolandProjects/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0x991d73)
(*Context).Next: c.handlers[c.index](c)
/home/zainkhan/GolandProjects/pkg/mod/github.com/gin-gonic/gin@v1.7.3/logger.go:241 (0x991d32)
LoggerWithConfig.func1: c.Next()
/home/zainkhan/GolandProjects/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0x988109)
(*Context).Next: c.handlers[c.index](c)
/home/zainkhan/GolandProjects/pkg/mod/github.com/gin-gonic/gin@v1.7.3/gin.go:489 (0x9880ef)
(*Engine).handleHTTPRequest: c.Next()
/home/zainkhan/GolandProjects/pkg/mod/github.com/gin-gonic/gin@v1.7.3/gin.go:445 (0x987bdb)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2867 (0x6e2462)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1932 (0x6dd88c)
(*conn).serve: serverHandlerc.server.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1371 (0x46e5a0)
goexit: BYTE $0x90 // NOP
我不知道它为什么来, ///////////////////////////////////////// ///////////////////////////////////////// ///////////////////////////////////////// ///////////////////////////////////////// ///////////////////////////////////////// ///////////////////////////////////////// ///////////////////////////////////////// //////
【问题讨论】:
【参考方案1】:实际的问题是func AuthKeyFromBytes(key []byte)
返回 nil 并带有一些错误或损坏的数据到 privateKey。然后,当您调用 privateKey.Sign
时,go 无法将 PrivateKey
类型的变量 privateKey 转换为指针 *PrivateKey
。
在使用privateKey
之前不要省略错误赋值和检查错误
privateKey, privateKeyError = AuthKeyFromBytes([]byte(ApplePrivateKey))
【讨论】:
"error": "token: AuthKey must be a valid .p8 PEM file" 我正在尝试从 .pem 文件添加私钥,但仍然面临这个问题。如果您有任何解决方案,请告诉我 我不太擅长证书,但在我看来,您需要将 PEM 转换为 p8 证书。这可能会有所帮助***.com/a/39327439/12301864以上是关于在 Go Server 中为 IOS 生成订阅报价签名时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
php [请求报价] YITH WooCommerce请求报价和WooCommerce订阅
如何在 SQL Server 2000 中为所有单笔表格生成脚本? [关闭]