veraison/go-cose
GitHub: veraison/go-cose
该项目是一个用 Go 语言实现的 COSE 规范库,用于在 CBOR 格式下进行消息签名与验证。
Stars: 63 | Forks: 31
# go-cose
[](https://pkg.go.dev/github.com/veraison/go-cose)
[](https://github.com/veraison/go-cose/actions?query=workflow%3Aci)
[](https://codecov.io/gh/veraison/go-cose)
一个用于 [COSE 规范][cose-spec] 的 golang 库
## 项目状态
verasion/go-cose 项目正在积极维护中。
参见[当前发布版本](https://github.com/veraison/go-cose/releases)。
该项目*最初*是从上游的 [mozilla-services/go-cose][mozilla-go-cose] 项目 fork 而来的,但是 Veraison 和 Mozilla 的维护者已经同意废弃 mozilla-services/go-cose 项目,并将重点放在 [veraison/go-cose][veraison-go-cose] 上作为活跃项目。
## 行为准则
本项目采用了[贡献者公约行为准则](https://github.com/veraison/.github/blob/main/CODE_OF_CONDUCT.md)。
## 安装
go-cose 兼容模块模式下的现代 Go 版本,在已安装 Go 的情况下:
```
go get github.com/veraison/go-cose
```
将解析并把该包及其依赖项添加到当前的开发模块中。
或者,如果你在一个包中使用 import,也可以实现同样的效果:
```
import "github.com/veraison/go-cose"
```
然后运行不带参数的 `go get`。
最后,要使用此仓库的最新主干版本,请使用以下命令:
```
go get github.com/veraison/go-cose@main
```
## 用法
### 签名与验证
```
import "github.com/veraison/go-cose"
```
构造一个新的 COSE_Sign1_Tagged 消息,然后使用 ECDSA w/ SHA-256 对其进行签名,最后将其 marshal。例如:
```
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
_ "crypto/sha256"
"github.com/veraison/go-cose"
)
func SignP256(data []byte) ([]byte, error) {
// create a signer
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
signer, err := cose.NewSigner(cose.AlgorithmES256, privateKey)
if err != nil {
return nil, err
}
// create message header
headers := cose.Headers{
Protected: cose.ProtectedHeader{
cose.HeaderLabelAlgorithm: cose.AlgorithmES256,
},
}
// sign and marshal message
return cose.Sign1(rand.Reader, signer, headers, data, nil)
}
```
验证原始的 COSE_Sign1_Tagged 消息。例如:
```
package main
import (
"crypto"
_ "crypto/sha256"
"github.com/veraison/go-cose"
)
func VerifyP256(publicKey crypto.PublicKey, sig []byte) error {
// create a verifier from a trusted private key
verifier, err := cose.NewVerifier(cose.AlgorithmES256, publicKey)
if err != nil {
return err
}
// create a sign message from a raw COSE_Sign1 payload
var msg cose.Sign1Message
if err = msg.UnmarshalCBOR(sig); err != nil {
return err
}
return msg.Verify(nil, verifier)
}
```
有关更多示例,请参见 [example_test.go](./example_test.go)。
#### 无标签的签名与验证
如上所述,可以使用 `cose.UntaggedSign1Message` 而不是 `cose.Sign1Message` 来对无标签的 COSE_Sign1 消息进行签名和验证。
#### 对 payload digest 进行签名和验证
当 `cose.NewSigner` 与 PS{256,384,512} 或 ES{256,384,512} 一起使用时,返回的 signer 可以被转换为 `cose.DigestSigner` 接口,其 `SignDigest` 方法用于对已经过 digest 处理的消息进行签名。
当 `cose.NewVerifier` 与 PS{256,384,512} 或 ES{256,384,512} 一起使用时,返回的 verifier 可以被转换为 `cose.DigestVerifier` 接口,其 `VerifyDigest` 方法用于验证已经过 digest 处理的消息。
有关 API 的用法,请参阅 [example_test.go](./example_test.go)。
### 关于 hashing
`go-cose` 本身不导入任何 hash package,以避免将不必要的算法链接到最终的二进制文件中。
`go-cose` 用户有责任在 runtime 提供必要的 hash 函数,即通过使用 blank import:
```
import (
_ "crypto/sha256"
_ "crypto/sha512"
)
```
以下是每个内置 cose.Algorithm 所需的 package:
- cose.AlgorithmPS256, cose.AlgorithmES256:`crypto/sha256`
- cose.AlgorithmPS384, cose.AlgorithmPS512, cose.AlgorithmES384, cose.AlgorithmES512:`crypto/sha512`
- cose.AlgorithmEdDSA:无
### Countersigning
可以对 `cose.Sign1Message`、`cose.SignMessage`、`cose.Signature` 和 `cose.Countersignature` 对象进行 countersign,并将它们添加为不受保护的 header。为此,首先使用 `cose.NewCountersignature()` 创建一个 countersignature 持有者,并调用其 `Sign` 函数,传入要进行 countersign 的父对象。然后,将该 countersignature 分配为不受保护的 header `cose.HeaderLabelCounterSignatureV2`,或者如果愿意,将其保留为分离的 countersignature。
在验证 countersignature 时,必须在 countersignature 持有者的 `Verify` 函数中传入父对象。
有关示例,请参见 [example_test.go](./example_test.go)。
## 功能
### 对象的签名与验证
go-cose 支持两种不同的签名结构:
- [cose.Sign1Message](https://pkg.go.dev/github.com/veraison/go-cose#Sign1Message) 实现了 [COSE_Sign1](https://datatracker.ietf.org/doc/html/rfc8152#section-4.2)。
- [cose.SignMessage](https://pkg.go.dev/github.com/veraison/go-cose#SignMessage) 实现了 [COSE_Sign](https://datatracker.ietf.org/doc/html/rfc8152#section-4.1)。
### Countersignatures
go-cose 支持 [COSE_Countersignature](https://tools.ietf.org/html/rfc9338#section-3.1),请查看 [cose.Countersignature](https://pkg.go.dev/github.com/veraison/go-cose#Countersignature)。
### 内置算法
go-cose 内置支持以下算法:
- PS{256,384,512}:RFC 8230 中定义的 RSASSA-PSS w/ SHA。
- ES{256,384,512}:RFC 8152 中定义的 ECDSA w/ SHA。
- Ed25519:RFC 8152 中定义的 PureEdDSA。
### 自定义算法
可以在此库中使用自定义算法,例如:
```
package cose_test
import (
"errors"
"io"
"testing"
"github.com/cloudflare/circl/sign"
"github.com/cloudflare/circl/sign/schemes"
"github.com/veraison/go-cose"
)
type customKeySigner struct {
alg cose.Algorithm
key sign.PrivateKey
}
func (ks *customKeySigner) Algorithm() cose.Algorithm {
return ks.alg
}
func (ks *customKeySigner) Sign(rand io.Reader, content []byte) ([]byte, error) {
suite := schemes.ByName("ML-DSA-44")
return suite.Sign(ks.key, content, nil), nil
}
type customKeyVerifier struct {
alg cose.Algorithm
key sign.PublicKey
}
func (ks *customKeyVerifier) Algorithm() cose.Algorithm {
return ks.alg
}
func (ks *customKeyVerifier) Verify(content []byte, signature []byte) error {
suite := schemes.ByName("ML-DSA-44")
valid := suite.Verify(ks.key, content, signature, nil)
if !valid {
return errors.New("Signature not from public key")
}
return nil
}
func TestCustomSigner(t *testing.T) {
const (
COSE_ALG_ML_DSA_44 = -48
)
suite := schemes.ByName("ML-DSA-44")
var seed [32]byte // zero seed
pub, priv := suite.DeriveKey(seed[:])
var ks cose.Signer = &customKeySigner{
alg: COSE_ALG_ML_DSA_44,
key: priv,
}
var kv = customKeyVerifier{
alg: COSE_ALG_ML_DSA_44,
key: pub,
}
headers := cose.Headers{
Protected: cose.ProtectedHeader{
cose.HeaderLabelAlgorithm: COSE_ALG_ML_DSA_44,
cose.HeaderLabelKeyID: []byte("key-42"),
},
}
var payload = []byte("hello post quantum signatures")
signature, _ := cose.Sign1(nil, ks, headers, payload, nil)
var sign1 cose.Sign1Message
_ = sign1.UnmarshalCBOR(signature)
var verifier cose.Verifier = &kv
verifyError := sign1.Verify(nil, verifier)
if verifyError != nil {
t.Fatalf("Verification failed")
} else {
// fmt.Println(cbor.Diagnose(signature))
// 18([
// <<{
// / alg / 1: -48,
// / kid / 4: h'6B65792D3432'}
// >>,
// {},
// h'4974...722e',
// h'cb5a...293b'
// ])
}
}
```
### 整数范围
CBOR 支持 [-264, -1] ∪ [0, 264 - 1] 范围内的整数。
这不能映射到单一的 Go 整数类型上。
`go-cose` 使用 `int64` 来同时包含正值和负值,以保持较小的数据大小并易于使用。
主要影响在于,根据 RFC 8152 原本有效的整数标签值(即在 [-264, -263 - 1] 和 [263, 264 - 1] 范围内的值)会被 go-cose 库拒绝。
### 一致性测试
`go-cose` 会在每次本地执行 `go test` 时运行 [GlueCOSE](https://github.com/gluecose/test-vectors) 测试套件。
这些测试也会在每个 CI 作业中执行。
### 模糊测试
`go-cose` 使用 [Go 原生模糊测试](https://go.dev/doc/fuzz)实现了多个模糊测试。
模糊测试需要 Go 1.18 或更高版本,可以按如下方式执行:
```
go test -fuzz=FuzzSign1
```
### 安全审查
`go-cose` 会进行定期的安全审查。安全审查报告位于[此处](./reports)。
标签:EVTX分析, 日志审计