How do you verify the signature returned by appengine.SignBytes?

huangapple go评论72阅读模式
英文:

How do you verify the signature returned by appengine.SignBytes?

问题

Google App Engine的Go运行时具有SignBytes函数、PublicCertificates函数和Certificate结构。

#func SignBytes

func SignBytes(c Context, bytes []byte) (keyName string, signature []byte, err error)

SignBytes使用应用程序唯一的私钥对字节进行签名。

#func PublicCertificates

func PublicCertificates(c Context) ([]Certificate, error)

PublicCertificates检索应用程序的公共证书。它们可用于验证SignBytes返回的签名。

type Certificate

type Certificate struct {
    KeyName string
    Data    []byte // PEM-encoded X.509 certificate
}

Certificate表示应用程序的公共证书。

很明显,应用程序需要遍历公共证书来验证签名。但是签名是如何生成和验证的并不清楚。Go的rsa包有两个用于验证签名的函数,VerifyPKCS1v15VerifyPSS,每个函数都需要一个crypto.Hash标识符作为参数。目前,有15个不同的哈希标识符(例如crypto.MD5,crypto.SHA256),提供了2x15=30种验证函数和哈希标识符的组合。

SignBytes生成的签名如何验证?

英文:

Google App Engine's Go runtime has a SignBytes function, a PublicCertificates function, and a Certificate structure.

> #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.

It's clear that the application is expected to iterate through the public certificates to verify the signature. But it is not clear how the signature is generate or verified. Go's rsa package has two functions to verify signatures, VerifyPKCS1v15 and VerifyPSS, and each of those functions takes a crypto.Hash identifier as a parameter. Currently, there are 15 different hash identifiers (e.g., crypto.MD5, crypto.SHA256) giving 2x15=30 combinations of verification function and hash identifier.

How is the signature produced by SignBytes verified?

答案1

得分: 4

使用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上发布了验证步骤的

更新

Google提供了一些示例代码来验证SignBytes。其中,文件app-identity-samples-read-only/python/app_identity_test.py中有一个名为buildjwt的方法,它创建了一个由SignBytes签名的JWT,JWT的alg是RS256,它在RFC 7518中定义为使用SHA-256的RSASSA-PKCS1-v1_5。

注意:我正在使用Go App Engine for Managed VMs(参见google.golang.org/appengine导入),而不是经典的Go App Engine运行时,尽管对于SignBytes来说并没有太大的区别。

英文:

VerifyPKCS1v15 using SHA256

I discovered this by trying all combinations of verification scheme and hash type; I did not find documentation guaranteeing this is the signature scheme that will be used.

But for the intrepid, below is a code sample that signs data and verifies the signature.

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
}

I've also published the the verify step in a package on github.

Update

Google provides some 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 to be RSASSA-PKCS1-v1_5 using SHA-256.

Note: I'm using Go App Engine for Managed VMs (see "google.golang.org/appengine" import) rather than the classic Go App Engine runtime, though there isn't really much different for the purposes of SignBytes.

huangapple
  • 本文由 发表于 2015年9月10日 02:05:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/32486427.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定