尽管 OpenSSL 成功,但无法在 Golang 中验证 RSA PSS 分离签名
Can't verify RSA PSS detached signature in Golang despite OpenSSL success
我已经尝试了我能想到的一切。我通读了我能找到的每个 Go 库,以找出我可能出错的地方,但我把它弄丢了。
OpenSSL 签名命令:
openssl cms -sign -binary -md sha256 -in Thing.tar -outform der -out Thing.sig -signer thing-sign.pem -keyopt rsa_padding_mode:pss
我获得了正确的 OpenSSL 说明:
openssl cms -verify -binary -md sha256 -in Thing.sig -inform DER -content Thing.tar -out Thing.dmp -CAfile ca-chain.pem
OpenSSL 是成功的,但我在 Golang 中的每一次尝试都是惨败。我认为这可能与填充有关,但目前这是一个缺乏根据的猜测。这就是我认为我理解这个过程所得到的!傻我。
如果需要,我很乐意提供迄今为止已尝试过的文档,只是目前我没有耐心。如果有人可以提供有关如何复制此 OpenSSL 命令的见解,我将不胜感激。
让我知道我可以提供什么帮助。
谢谢!
编辑:
现在我已经休息了,这是我正在使用的代码:
func(t *Thing) VerifyThisThingWithSig() (bool, error) {
sig, err := ioutil.ReadFile(t.sigPath)
if err != nil {
return false, err
}
rootPem, err := ioutil.ReadFile(cfg.Certs.CACertChain)
if err != nil {
return false, err
}
block, _ := pem.Decode(rootPem)
var cert *x509.Certificate
cert, _ = x509.ParseCertificate(block.Bytes)
rsaPubKey := cert.PublicKey.(*rsa.PublicKey)
hasher := sha256.New()
f, err := os.Open(t.tarPath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
if _, err := io.Copy(hasher, f); err != nil {
log.Fatal(err)
}
var opts rsa.PSSOptions
err = rsa.VerifyPSS(rsaPubKey, crypto.SHA256, hasher.Sum(nil), sig, &opts)
if err != nil {
return false, err
}
return true, err
}
在 go src 中查看 rsa.VerifyPSS():
func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *PSSOptions) error {
if len(sig) != pub.Size() {
return ErrVerification
}
s := new(big.Int).SetBytes(sig)
m := encrypt(new(big.Int), pub, s)
emBits := pub.N.BitLen() - 1
emLen := (emBits + 7) / 8
if m.BitLen() > emLen*8 {
return ErrVerification
}
em := m.FillBytes(make([]byte, emLen))
return emsaPSSVerify(digest, em, emBits, opts.saltLength(), hash.New())
}
...public 密钥和签名(我的分别是 256 和 1782)的大小比较,我马上就失败了。
从 ASN.1 数据读取,我有 OID:
1.2.840.113549.1.1.10 rsaPSS (PKCS #1)
1.2.840.113549.1.1.8 pkcs1-MGF (PKCS #1)
我是这样看签名的吗?使用 pkcs7 库,我能够毫无问题地解析 sig 数据,但我不能用它来验证 pkcs1 rsapss。我迷失在加密货币的森林里。
编辑 2:
好的。我想我可以手动执行此操作。我想我需要解析 pkcs7 签名,提取包含创建时生成的分离内容的 sha256 总和的 OID,并与我在验证时生成的内容 sha256 进行比较。
除非另有说明,否则这就是我下一步要去的地方。将报告结果。
好的,我不得不 rewrite/merge 两个现有的库来完成它,但契约已经完成。
一个库支持我需要的 RSAPSS,但不支持证书链或签名时间验证。另一个支持证书链和签名时间验证,但不支持 RSAPSS 算法。所以我将我需要的部分合并到一个支持两者的新库中。
最终代码:
func(t *Thing) VerifyThingWithSig() (bool, error) {
tar, err := ioutil.ReadFile(t.tarPath)
if err != nil {
return false, err
}
sig, err := ioutil.ReadFile(t.sigPath)
if err != nil {
return false, err
}
certPool := x509.NewCertPool()
certs, err := ioutil.ReadFile(cfg.Certs.ThingCAChain)
if err != nil {
return false, err
}
certPool.AppendCertsFromPEM(certs)
p7, err := pkcs7.Parse(sig)
if err != nil {
return false, err
}
p7.Content = tar
if bytes.Compare(tar, p7.Content) != 0 {
err = fmt.Errorf("Content was not in the parsed data")
return false, err
}
if err = p7.VerifyWithChain(certPool); err != nil {
return false, err
}
return true, err
}
我已经尝试了我能想到的一切。我通读了我能找到的每个 Go 库,以找出我可能出错的地方,但我把它弄丢了。
OpenSSL 签名命令:
openssl cms -sign -binary -md sha256 -in Thing.tar -outform der -out Thing.sig -signer thing-sign.pem -keyopt rsa_padding_mode:pss
我获得了正确的 OpenSSL 说明:
openssl cms -verify -binary -md sha256 -in Thing.sig -inform DER -content Thing.tar -out Thing.dmp -CAfile ca-chain.pem
OpenSSL 是成功的,但我在 Golang 中的每一次尝试都是惨败。我认为这可能与填充有关,但目前这是一个缺乏根据的猜测。这就是我认为我理解这个过程所得到的!傻我。
如果需要,我很乐意提供迄今为止已尝试过的文档,只是目前我没有耐心。如果有人可以提供有关如何复制此 OpenSSL 命令的见解,我将不胜感激。
让我知道我可以提供什么帮助。
谢谢!
编辑:
现在我已经休息了,这是我正在使用的代码:
func(t *Thing) VerifyThisThingWithSig() (bool, error) {
sig, err := ioutil.ReadFile(t.sigPath)
if err != nil {
return false, err
}
rootPem, err := ioutil.ReadFile(cfg.Certs.CACertChain)
if err != nil {
return false, err
}
block, _ := pem.Decode(rootPem)
var cert *x509.Certificate
cert, _ = x509.ParseCertificate(block.Bytes)
rsaPubKey := cert.PublicKey.(*rsa.PublicKey)
hasher := sha256.New()
f, err := os.Open(t.tarPath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
if _, err := io.Copy(hasher, f); err != nil {
log.Fatal(err)
}
var opts rsa.PSSOptions
err = rsa.VerifyPSS(rsaPubKey, crypto.SHA256, hasher.Sum(nil), sig, &opts)
if err != nil {
return false, err
}
return true, err
}
在 go src 中查看 rsa.VerifyPSS():
func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *PSSOptions) error {
if len(sig) != pub.Size() {
return ErrVerification
}
s := new(big.Int).SetBytes(sig)
m := encrypt(new(big.Int), pub, s)
emBits := pub.N.BitLen() - 1
emLen := (emBits + 7) / 8
if m.BitLen() > emLen*8 {
return ErrVerification
}
em := m.FillBytes(make([]byte, emLen))
return emsaPSSVerify(digest, em, emBits, opts.saltLength(), hash.New())
}
...public 密钥和签名(我的分别是 256 和 1782)的大小比较,我马上就失败了。
从 ASN.1 数据读取,我有 OID:
1.2.840.113549.1.1.10 rsaPSS (PKCS #1)
1.2.840.113549.1.1.8 pkcs1-MGF (PKCS #1)
我是这样看签名的吗?使用 pkcs7 库,我能够毫无问题地解析 sig 数据,但我不能用它来验证 pkcs1 rsapss。我迷失在加密货币的森林里。
编辑 2:
好的。我想我可以手动执行此操作。我想我需要解析 pkcs7 签名,提取包含创建时生成的分离内容的 sha256 总和的 OID,并与我在验证时生成的内容 sha256 进行比较。
除非另有说明,否则这就是我下一步要去的地方。将报告结果。
好的,我不得不 rewrite/merge 两个现有的库来完成它,但契约已经完成。
一个库支持我需要的 RSAPSS,但不支持证书链或签名时间验证。另一个支持证书链和签名时间验证,但不支持 RSAPSS 算法。所以我将我需要的部分合并到一个支持两者的新库中。
最终代码:
func(t *Thing) VerifyThingWithSig() (bool, error) {
tar, err := ioutil.ReadFile(t.tarPath)
if err != nil {
return false, err
}
sig, err := ioutil.ReadFile(t.sigPath)
if err != nil {
return false, err
}
certPool := x509.NewCertPool()
certs, err := ioutil.ReadFile(cfg.Certs.ThingCAChain)
if err != nil {
return false, err
}
certPool.AppendCertsFromPEM(certs)
p7, err := pkcs7.Parse(sig)
if err != nil {
return false, err
}
p7.Content = tar
if bytes.Compare(tar, p7.Content) != 0 {
err = fmt.Errorf("Content was not in the parsed data")
return false, err
}
if err = p7.VerifyWithChain(certPool); err != nil {
return false, err
}
return true, err
}