您如何验证 appengine.SignBytes 返回的签名?
How do you verify the signature returned by appengine.SignBytes?
Google App Engine 的 Go 运行时具有 SignBytes function, a PublicCertificates function, and a Certificate 结构。
func SignBytes
func SignBytes(c Context, bytes []byte) (keyName string, signature []byte, err error)
SignBytes signs bytes using a private key unique to your application.
func PublicCertificates
func PublicCertificates(c Context) ([]Certificate, error)
PublicCertificates retrieves the public certificates for the app. They
can be used to verify a signature returned by SignBytes.
type Certificate
type Certificate struct {
KeyName string
Data []byte // PEM-encoded X.509 certificate
}
Certificate represents a public certificate for the app.
很明显,应用程序需要遍历 public 证书来验证签名。但目前尚不清楚签名是如何生成或验证的。 Go 的 rsa package has two functions to verify signatures, VerifyPKCS1v15 and VerifyPSS, and each of those functions takes a crypto.Hash 标识符作为参数。目前,有 15 种不同的哈希标识符(例如,crypto.MD5、crypto.SHA256)给出了 2x15=30 种验证函数和哈希标识符的组合。
SignBytes 生成的签名是如何验证的?
使用 SHA256 验证 PKCS1v15
我通过尝试验证方案和哈希类型的所有组合发现了这一点;我没有找到保证这是将要使用的签名方案的文档。
但是对于勇敢的人来说,下面是一个代码示例,它可以对数据进行签名并验证签名。
package yourpackage
import (
"crypto"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"google.golang.org/appengine"
"net/http"
)
func signAndVerify(request *http.Request) error {
c := appengine.NewContext(request)
data := []byte("test data to sign")
_, sig, err := appengine.SignBytes(c, data)
if err != nil {
return err
}
certs, err := appengine.PublicCertificates(c)
if err != nil {
return err
}
lastErr := errors.New("ErrNoPublicCertificates")
for _, cert := range certs {
block, _ := pem.Decode(cert.Data)
if block == nil {
lastErr = errors.New("ErrPemDecodeFailure")
continue
}
x509Cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
lastErr = err
continue
}
pubkey, ok := x509Cert.PublicKey.(*rsa.PublicKey)
if !ok {
lastErr = errors.New("ErrNotRSAPublicKey")
continue
}
signBytesHash := crypto.SHA256
h := signBytesHash.New()
h.Write(data)
hashed := h.Sum(nil)
err = rsa.VerifyPKCS1v15(pubkey, signBytesHash, hashed, sig)
if err != nil {
lastErr = err
continue
}
return nil
}
return lastErr
}
我还在 github 上的 package 中发布了验证步骤。
更新
Google 使用 SHA-256 提供一些 sample code that verifies SignBytes. In it, there is a file app-identity-samples-read-only/python/app_identity_test.py
has a method named buildjwt
that creates a JWT signed by SignBytes, and the JWT alg is RS256, which is defined in RFC 7518 RSASSA-PKCS1-v1_5。
注意:我使用的是 Go App Engine for Managed VMs(请参阅“google.golang.org/appengine”导入)而不是经典的 Go App Engine 运行时,尽管没有对于 SignBytes 的目的来说真的没有太大的不同。
Google App Engine 的 Go 运行时具有 SignBytes function, a PublicCertificates function, and a Certificate 结构。
func SignBytes
func SignBytes(c Context, bytes []byte) (keyName string, signature []byte, err error)
SignBytes signs bytes using a private key unique to your application.
func PublicCertificates
func PublicCertificates(c Context) ([]Certificate, error)
PublicCertificates retrieves the public certificates for the app. They can be used to verify a signature returned by SignBytes.
type Certificate
type Certificate struct { KeyName string Data []byte // PEM-encoded X.509 certificate }
Certificate represents a public certificate for the app.
很明显,应用程序需要遍历 public 证书来验证签名。但目前尚不清楚签名是如何生成或验证的。 Go 的 rsa package has two functions to verify signatures, VerifyPKCS1v15 and VerifyPSS, and each of those functions takes a crypto.Hash 标识符作为参数。目前,有 15 种不同的哈希标识符(例如,crypto.MD5、crypto.SHA256)给出了 2x15=30 种验证函数和哈希标识符的组合。
SignBytes 生成的签名是如何验证的?
使用 SHA256 验证 PKCS1v15
我通过尝试验证方案和哈希类型的所有组合发现了这一点;我没有找到保证这是将要使用的签名方案的文档。
但是对于勇敢的人来说,下面是一个代码示例,它可以对数据进行签名并验证签名。
package yourpackage
import (
"crypto"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"google.golang.org/appengine"
"net/http"
)
func signAndVerify(request *http.Request) error {
c := appengine.NewContext(request)
data := []byte("test data to sign")
_, sig, err := appengine.SignBytes(c, data)
if err != nil {
return err
}
certs, err := appengine.PublicCertificates(c)
if err != nil {
return err
}
lastErr := errors.New("ErrNoPublicCertificates")
for _, cert := range certs {
block, _ := pem.Decode(cert.Data)
if block == nil {
lastErr = errors.New("ErrPemDecodeFailure")
continue
}
x509Cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
lastErr = err
continue
}
pubkey, ok := x509Cert.PublicKey.(*rsa.PublicKey)
if !ok {
lastErr = errors.New("ErrNotRSAPublicKey")
continue
}
signBytesHash := crypto.SHA256
h := signBytesHash.New()
h.Write(data)
hashed := h.Sum(nil)
err = rsa.VerifyPKCS1v15(pubkey, signBytesHash, hashed, sig)
if err != nil {
lastErr = err
continue
}
return nil
}
return lastErr
}
我还在 github 上的 package 中发布了验证步骤。
更新
Google 使用 SHA-256 提供一些 sample code that verifies SignBytes. In it, there is a file app-identity-samples-read-only/python/app_identity_test.py
has a method named buildjwt
that creates a JWT signed by SignBytes, and the JWT alg is RS256, which is defined in RFC 7518 RSASSA-PKCS1-v1_5。
注意:我使用的是 Go App Engine for Managed VMs(请参阅“google.golang.org/appengine”导入)而不是经典的 Go App Engine 运行时,尽管没有对于 SignBytes 的目的来说真的没有太大的不同。