diff --git a/go.mod b/go.mod index 2ba4892896..527a486b1f 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.0 github.com/urfave/cli v1.22.13 - github.com/veraison/go-cose v1.0.0-rc.1 + github.com/veraison/go-cose v1.1.0 github.com/vishvananda/netlink v1.2.1-beta.2 github.com/vishvananda/netns v0.0.4 go.etcd.io/bbolt v1.3.7 diff --git a/go.sum b/go.sum index a7bc7f2a38..b10976776b 100644 --- a/go.sum +++ b/go.sum @@ -958,8 +958,8 @@ github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RV github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= github.com/vektah/gqlparser/v2 v2.4.5 h1:C02NsyEsL4TXJB7ndonqTfuQOL4XPIu0aAWugdmTgmc= github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= -github.com/veraison/go-cose v1.0.0-rc.1 h1:4qA7dbFJGvt7gcqv5MCIyCQvN+NpHFPkW7do3EeDLb8= -github.com/veraison/go-cose v1.0.0-rc.1/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= +github.com/veraison/go-cose v1.1.0 h1:AalPS4VGiKavpAzIlBjrn7bhqXiXi4jbMYY/2+UC+4o= +github.com/veraison/go-cose v1.1.0/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= diff --git a/vendor/github.com/veraison/go-cose/CODEOWNERS b/vendor/github.com/veraison/go-cose/CODEOWNERS new file mode 100644 index 0000000000..767969e2a9 --- /dev/null +++ b/vendor/github.com/veraison/go-cose/CODEOWNERS @@ -0,0 +1,4 @@ +# To be kept in sync with: [community/OWNERS](https://github.com/veraison/community/blob/main/OWNERS) +# and the GitHub Team: [go-cose-maintainers](https://github.com/orgs/veraison/teams/go-cose-maintainers) + +* henkbirkholz qmuntal roywill setrofim shizhMSFT simonfrost-arm SteveLasker thomas-fossati yogeshbdeshpande diff --git a/vendor/github.com/veraison/go-cose/CODE_OF_CONDUCT.md b/vendor/github.com/veraison/go-cose/CODE_OF_CONDUCT.md deleted file mode 100644 index 498baa3fb0..0000000000 --- a/vendor/github.com/veraison/go-cose/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,15 +0,0 @@ -# Community Participation Guidelines - -This repository is governed by Mozilla's code of conduct and etiquette guidelines. -For more details, please read the -[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). - -## How to Report -For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. - - diff --git a/vendor/github.com/veraison/go-cose/README.md b/vendor/github.com/veraison/go-cose/README.md index 2b2e492e18..74a8f7735f 100644 --- a/vendor/github.com/veraison/go-cose/README.md +++ b/vendor/github.com/veraison/go-cose/README.md @@ -8,12 +8,31 @@ A golang library for the [COSE specification][cose-spec] ## Project Status -**Current Release**: [go-cose alpha 1][release-alpha-1] +**Current Release**: [go-cose v1.0.0][current-release] The project was *initially* forked from the upstream [mozilla-services/go-cose][mozilla-go-cose] project, however the Veraison and Mozilla maintainers have agreed to retire the mozilla-services/go-cose project and focus on [veraison/go-cose][veraison-go-cose] as the active project. We thank the [Mozilla maintainers and contributors][mozilla-contributors] for their great work that formed the base of the [veraison/go-cose][veraison-go-cose] project. +## Community + +The [veraison/go-cose](https://github.com/veraison/go-cose) project is an open source community effort. + +You can reach the go-cose community via:: + +- [Mailing List](veraison-project@confidentialcomputing.io) +- Bi-weekly meetings: 08:00-09:00 Pacific + - [Zoom meeting link](https://us02web.zoom.us/j/81054434992?pwd=YjNBU21seU5VcGdtVXY3VHVjS251Zz09) + - [Calendar ics link](https://zoom.us/meeting/tZUtcu2srT8jE9YFubXn-lC9upuwUiiev52G/ics) +- [Meeting Notes](https://veraison.zulipchat.com/#narrow/stream/317999-go-cose-meetings) +- [Meeting Recordings](https://www.youtube.com/@go-cose-community3000) + +Participation in the go-cose community is governed by the Veraison [CODE_OF_CONDUCT.md](https://github.com/veraison/.github/blob/main/CODE_OF_CONDUCT.md) and [GOVERNANCE.md](https://github.com/veraison/community/blob/main/GOVERNANCE.md) + +## Code of Conduct + +This project has adopted the [Contributor Covenant Code of Conduct](https://github.com/veraison/.github/blob/main/CODE_OF_CONDUCT.md). + ## Installation go-cose is compatible with modern Go releases in module mode, with Go installed: @@ -40,41 +59,103 @@ go get github.com/veraison/go-cose@main ## Usage +### Signing and Verification + ```go import "github.com/veraison/go-cose" ``` -Construct a new COSE_Sign1 message, then sign it using ECDSA w/ SHA-512 and finally marshal it. For example: +Construct a new COSE_Sign1_Tagged message, then sign it using ECDSA w/ SHA-256 and finally marshal it. For example: ```go -// create a signer -privateKey, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) -signer, _ := cose.NewSigner(cose.AlgorithmES512, privateKey) - -// create message header -headers := cose.Headers{ - Protected: cose.ProtectedHeader{ - cose.HeaderLabelAlgorithm: cose.AlgorithmES512, - }, +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) } +``` + +Verify a raw COSE_Sign1_Tagged message. For example: -// sign and marshal message -sig, _ := cose.Sign1(rand.Reader, signer, headers, []byte("hello world"), nil) +```go +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) +} ``` -Verify a raw COSE_Sign1 message. For example: +See [example_test.go](./example_test.go) for more examples. + +#### Untagged Signing and Verification + +Untagged COSE_Sign1 messages can be signed and verified as above, using +`cose.UntaggedSign1Message` instead of `cose.Sign1Message`. + +### About hashing + +`go-cose` does not import any hash package by its own to avoid linking unnecessary algorithms to the final binary. +It is the the responsibility of the `go-cose` user to make the necessary hash functions available at runtime, i.e., +by using a blank import: ```go -// create a verifier from a trusted private key -publicKey := privateKey.Public() -verifier, _ := cose.NewVerifier(cose.AlgorithmES512, publicKey) - -// create a sign message from a raw COSE_Sign1 payload -var msg cose.Sign1Message -_ = msg.UnmarshalCBOR(raw) -_ = msg.Verify(nil, verifier) +import ( + _ "crypto/sha256" + _ "crypto/sha512" +) ``` +These are the required packages for each built-in cose.Algorithm: + +- cose.AlgorithmPS256, cose.AlgorithmES256: `crypto/sha256` +- cose.AlgorithmPS384, cose.AlgorithmPS512, cose.AlgorithmES384, cose.AlgorithmES512: `crypto/sha512` +- cose.AlgorithmEd25519: none + ## Features ### Signing and Verifying Objects @@ -110,12 +191,12 @@ per RFC 8152, are rejected by the go-cose library. ### Conformance Tests -go-cose runs the [GlueCOSE](https://github.com/gluecose/test-vectors) test suite on every local `go test` execution. +`go-cose` runs the [GlueCOSE](https://github.com/gluecose/test-vectors) test suite on every local `go test` execution. These are also executed on every CI job. ### Fuzz Tests -go-cose implements several fuzz tests using [Go's native fuzzing](https://go.dev/doc/fuzz). +`go-cose` implements several fuzz tests using [Go's native fuzzing](https://go.dev/doc/fuzz). Fuzzing requires Go 1.18 or higher, and can be executed as follows: @@ -123,8 +204,12 @@ Fuzzing requires Go 1.18 or higher, and can be executed as follows: go test -fuzz=FuzzSign1 ``` -[cose-spec]: https://datatracker.ietf.org/doc/draft-ietf-cose-rfc8152bis-struct/ +### Security Reviews + +`go-cose` undergoes periodic security review. The security review reports are located [here](./reports) + +[cose-spec]: https://datatracker.ietf.org/doc/rfc9052/ [mozilla-contributors]: https://github.com/mozilla-services/go-cose/graphs/contributors [mozilla-go-cose]: http://github.com/mozilla-services/go-cose [veraison-go-cose]: https://github.com/veraison/go-cose -[release-alpha-1]: https://github.com/veraison/go-cose/releases/tag/v1.0.0-alpha.1 +[current-release]: https://github.com/veraison/go-cose/releases/tag/v1.0.0 diff --git a/vendor/github.com/veraison/go-cose/SECURITY.md b/vendor/github.com/veraison/go-cose/SECURITY.md index 1840d0f2b5..d4ab969dd7 100644 --- a/vendor/github.com/veraison/go-cose/SECURITY.md +++ b/vendor/github.com/veraison/go-cose/SECURITY.md @@ -4,11 +4,11 @@ This document provides the details on the veraison/go-cose security policy and d ## Supported Versions -[go-cose][go-cose] is currently is in active development, moving to a [1.0.0 release][v1.0.0-milestone]. The latest pre-release will be supported until 1.0.0 is released. As 1.0.0 is released, pre-release references will need to be redirected to 1.0.0. +The current stable release of [go-cose][go-cose] is [v1.0.0][v1.0.0-release]. Please upgrade to [v1.0.0][v1.0.0-release] if you are using a pre-release version. | Version | Supported | | ------- | ------------------ | -| [v1.0.0-alpha1][v1.0.0-alpha1-release] | :green_check_mark: | +| [v1.0.0][v1.0.0-release] | Yes | ## Report A Vulnerability @@ -23,7 +23,7 @@ To make a report please email the private security list at >5 != 2 { // major type 2: bstr + return nil, errors.New("cbor: require bstr type") + } + + // fast path: return immediately if bstr is already deterministic + if err := decModeWithTagsForbidden.Valid(data); err != nil { + return nil, err + } + ai := data[0] & 0x1f + if ai < 24 { + return data, nil + } + switch ai { + case 24: + if data[1] >= 24 { + return data, nil + } + case 25: + if data[1] != 0 { + return data, nil + } + case 26: + if data[1] != 0 || data[2] != 0 { + return data, nil + } + case 27: + if data[1] != 0 || data[2] != 0 || data[3] != 0 || data[4] != 0 { + return data, nil + } + } + + // slow path: convert by re-encoding + // error checking is not required since `data` has been validataed + var s []byte + _ = decModeWithTagsForbidden.Unmarshal(data, &s) + return encMode.Marshal(s) +} diff --git a/vendor/github.com/veraison/go-cose/ecdsa.go b/vendor/github.com/veraison/go-cose/ecdsa.go index ade663805e..7e426be387 100644 --- a/vendor/github.com/veraison/go-cose/ecdsa.go +++ b/vendor/github.com/veraison/go-cose/ecdsa.go @@ -47,12 +47,16 @@ func (es *ecdsaKeySigner) Algorithm() Algorithm { return es.alg } -// Sign signs digest with the private key using entropy from rand. +// Sign signs message content with the private key using entropy from rand. // The resulting signature should follow RFC 8152 section 8.1, // although it does not follow the recommendation of being deterministic. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8.1 -func (es *ecdsaKeySigner) Sign(rand io.Reader, digest []byte) ([]byte, error) { +func (es *ecdsaKeySigner) Sign(rand io.Reader, content []byte) ([]byte, error) { + digest, err := es.alg.computeHash(content) + if err != nil { + return nil, err + } r, s, err := ecdsa.Sign(rand, es.key, digest) if err != nil { return nil, err @@ -72,11 +76,16 @@ func (es *ecdsaCryptoSigner) Algorithm() Algorithm { return es.alg } -// Sign signs digest with the private key, possibly using entropy from rand. +// Sign signs message content with the private key, possibly using entropy from +// rand. // The resulting signature should follow RFC 8152 section 8.1. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8.1 -func (es *ecdsaCryptoSigner) Sign(rand io.Reader, digest []byte) ([]byte, error) { +func (es *ecdsaCryptoSigner) Sign(rand io.Reader, content []byte) ([]byte, error) { + digest, err := es.alg.computeHash(content) + if err != nil { + return nil, err + } sigASN1, err := es.signer.Sign(rand, digest, nil) if err != nil { return nil, err @@ -133,14 +142,16 @@ func (ev *ecdsaVerifier) Algorithm() Algorithm { return ev.alg } -// Verify verifies digest with the public key, returning nil for success. +// Verify verifies message content with the public key, returning nil for +// success. // Otherwise, it returns ErrVerification. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8.1 -func (ev *ecdsaVerifier) Verify(digest []byte, signature []byte) error { - // verify digest size - if h, ok := ev.alg.hashFunc(); !ok || h.Size() != len(digest) { - return ErrVerification +func (ev *ecdsaVerifier) Verify(content []byte, signature []byte) error { + // compute digest + digest, err := ev.alg.computeHash(content) + if err != nil { + return err } // verify signature diff --git a/vendor/github.com/veraison/go-cose/ed25519.go b/vendor/github.com/veraison/go-cose/ed25519.go index f87deee1f9..ae88740f73 100644 --- a/vendor/github.com/veraison/go-cose/ed25519.go +++ b/vendor/github.com/veraison/go-cose/ed25519.go @@ -16,14 +16,15 @@ func (es *ed25519Signer) Algorithm() Algorithm { return AlgorithmEd25519 } -// Sign signs digest with the private key, possibly using entropy from rand. +// Sign signs message content with the private key, possibly using entropy from +// rand. // The resulting signature should follow RFC 8152 section 8.2. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8.2 -func (es *ed25519Signer) Sign(rand io.Reader, digest []byte) ([]byte, error) { +func (es *ed25519Signer) Sign(rand io.Reader, content []byte) ([]byte, error) { // crypto.Hash(0) must be passed as an option. // Reference: https://pkg.go.dev/crypto/ed25519#PrivateKey.Sign - return es.key.Sign(rand, digest, crypto.Hash(0)) + return es.key.Sign(rand, content, crypto.Hash(0)) } // ed25519Verifier is a Pure EdDSA based verifier with golang built-in keys. @@ -36,12 +37,13 @@ func (ev *ed25519Verifier) Algorithm() Algorithm { return AlgorithmEd25519 } -// Verify verifies digest with the public key, returning nil for success. +// Verify verifies message content with the public key, returning nil for +// success. // Otherwise, it returns ErrVerification. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8.2 -func (ev *ed25519Verifier) Verify(digest []byte, signature []byte) error { - if verified := ed25519.Verify(ev.key, digest, signature); !verified { +func (ev *ed25519Verifier) Verify(content []byte, signature []byte) error { + if verified := ed25519.Verify(ev.key, content, signature); !verified { return ErrVerification } return nil diff --git a/vendor/github.com/veraison/go-cose/errors.go b/vendor/github.com/veraison/go-cose/errors.go index ac9ba2744d..8c240e2854 100644 --- a/vendor/github.com/veraison/go-cose/errors.go +++ b/vendor/github.com/veraison/go-cose/errors.go @@ -7,12 +7,11 @@ var ( ErrAlgorithmMismatch = errors.New("algorithm mismatch") ErrAlgorithmNotFound = errors.New("algorithm not found") ErrAlgorithmNotSupported = errors.New("algorithm not supported") - ErrAlgorithmRegistered = errors.New("algorithm registered") ErrEmptySignature = errors.New("empty signature") ErrInvalidAlgorithm = errors.New("invalid algorithm") ErrMissingPayload = errors.New("missing payload") ErrNoSignatures = errors.New("no signatures attached") ErrUnavailableHashFunc = errors.New("hash function is not available") - ErrUnknownAlgorithm = errors.New("unknown algorithm") ErrVerification = errors.New("verification error") + ErrInvalidPubKey = errors.New("invalid public key") ) diff --git a/vendor/github.com/veraison/go-cose/rsa.go b/vendor/github.com/veraison/go-cose/rsa.go index dc7e7e3426..b63098cad0 100644 --- a/vendor/github.com/veraison/go-cose/rsa.go +++ b/vendor/github.com/veraison/go-cose/rsa.go @@ -19,14 +19,15 @@ func (rs *rsaSigner) Algorithm() Algorithm { return rs.alg } -// Sign signs digest with the private key, using entropy from rand. +// Sign signs message content with the private key, using entropy from rand. // The resulting signature should follow RFC 8152 section 8. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8 -func (rs *rsaSigner) Sign(rand io.Reader, digest []byte) ([]byte, error) { - hash, ok := rs.alg.hashFunc() - if !ok { - return nil, ErrInvalidAlgorithm +func (rs *rsaSigner) Sign(rand io.Reader, content []byte) ([]byte, error) { + hash := rs.alg.hashFunc() + digest, err := computeHash(hash, content) + if err != nil { + return nil, err } return rs.key.Sign(rand, digest, &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, // defined in RFC 8230 sec 2 @@ -47,14 +48,16 @@ func (rv *rsaVerifier) Algorithm() Algorithm { return rv.alg } -// Verify verifies digest with the public key, returning nil for success. +// Verify verifies message content with the public key, returning nil for +// success. // Otherwise, it returns ErrVerification. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8 -func (rv *rsaVerifier) Verify(digest []byte, signature []byte) error { - hash, ok := rv.alg.hashFunc() - if !ok { - return ErrInvalidAlgorithm +func (rv *rsaVerifier) Verify(content []byte, signature []byte) error { + hash := rv.alg.hashFunc() + digest, err := computeHash(hash, content) + if err != nil { + return err } if err := rsa.VerifyPSS(rv.key, hash, digest, signature, &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, // defined in RFC 8230 sec 2 diff --git a/vendor/github.com/veraison/go-cose/sign.go b/vendor/github.com/veraison/go-cose/sign.go index e9ca75916d..cd86d11869 100644 --- a/vendor/github.com/veraison/go-cose/sign.go +++ b/vendor/github.com/veraison/go-cose/sign.go @@ -11,10 +11,10 @@ import ( // signature represents a COSE_Signature CBOR object: // -// COSE_Signature = [ -// Headers, -// signature : bstr -// ] +// COSE_Signature = [ +// Headers, +// signature : bstr +// ] // // Reference: https://tools.ietf.org/html/rfc8152#section-4.1 type signature struct { @@ -33,11 +33,10 @@ var signaturePrefix = []byte{ // // Reference: https://tools.ietf.org/html/rfc8152#section-4.1 // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// type Signature struct { Headers Headers Signature []byte @@ -45,11 +44,10 @@ type Signature struct { // NewSignature returns a Signature with header initialized. // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func NewSignature() *Signature { return &Signature{ Headers: Headers{ @@ -61,11 +59,10 @@ func NewSignature() *Signature { // MarshalCBOR encodes Signature into a COSE_Signature object. // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (s *Signature) MarshalCBOR() ([]byte, error) { if s == nil { return nil, errors.New("cbor: MarshalCBOR on nil Signature pointer") @@ -87,11 +84,10 @@ func (s *Signature) MarshalCBOR() ([]byte, error) { // UnmarshalCBOR decodes a COSE_Signature object into Signature. // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (s *Signature) UnmarshalCBOR(data []byte) error { if s == nil { return errors.New("cbor: UnmarshalCBOR on nil Signature pointer") @@ -131,11 +127,10 @@ func (s *Signature) UnmarshalCBOR(data []byte) error { // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (s *Signature) Sign(rand io.Reader, signer Signer, protected cbor.RawMessage, payload, external []byte) error { if s == nil { return errors.New("signing nil Signature") @@ -158,11 +153,11 @@ func (s *Signature) Sign(rand io.Reader, signer Signer, protected cbor.RawMessag } // sign the message - digest, err := s.digestToBeSigned(alg, protected, payload, external) + toBeSigned, err := s.toBeSigned(protected, payload, external) if err != nil { return err } - sig, err := signer.Sign(rand, digest) + sig, err := signer.Sign(rand, toBeSigned) if err != nil { return err } @@ -178,11 +173,10 @@ func (s *Signature) Sign(rand io.Reader, signer Signer, protected cbor.RawMessag // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (s *Signature) Verify(verifier Verifier, protected cbor.RawMessage, payload, external []byte) error { if s == nil { return errors.New("verifying nil Signature") @@ -206,20 +200,17 @@ func (s *Signature) Verify(verifier Verifier, protected cbor.RawMessage, payload } // verify the message - digest, err := s.digestToBeSigned(alg, protected, payload, external) + toBeSigned, err := s.toBeSigned(protected, payload, external) if err != nil { return err } - return verifier.Verify(digest, s.Signature) + return verifier.Verify(toBeSigned, s.Signature) } -// digestToBeSigned constructs Sig_structure, computes ToBeSigned, and returns -// the digest of ToBeSigned. -// If the signing algorithm does not have a hash algorithm associated, -// ToBeSigned is returned instead. +// toBeSigned constructs Sig_structure, computes and returns ToBeSigned. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 -func (s *Signature) digestToBeSigned(alg Algorithm, bodyProtected cbor.RawMessage, payload, external []byte) ([]byte, error) { +func (s *Signature) toBeSigned(bodyProtected cbor.RawMessage, payload, external []byte) ([]byte, error) { // create a Sig_structure and populate it with the appropriate fields. // // Sig_structure = [ @@ -229,8 +220,16 @@ func (s *Signature) digestToBeSigned(alg Algorithm, bodyProtected cbor.RawMessag // external_aad : bstr, // payload : bstr // ] + bodyProtected, err := deterministicBinaryString(bodyProtected) + if err != nil { + return nil, err + } var signProtected cbor.RawMessage - signProtected, err := s.Headers.MarshalProtected() + signProtected, err = s.Headers.MarshalProtected() + if err != nil { + return nil, err + } + signProtected, err = deterministicBinaryString(signProtected) if err != nil { return nil, err } @@ -247,23 +246,16 @@ func (s *Signature) digestToBeSigned(alg Algorithm, bodyProtected cbor.RawMessag // create the value ToBeSigned by encoding the Sig_structure to a byte // string. - toBeSigned, err := encMode.Marshal(sigStructure) - if err != nil { - return nil, err - } - - // hash toBeSigned if there is a hash algorithm associated with the signing - // algorithm. - return alg.computeHash(toBeSigned) + return encMode.Marshal(sigStructure) } // signMessage represents a COSE_Sign CBOR object: // -// COSE_Sign = [ -// Headers, -// payload : bstr / nil, -// signatures : [+ COSE_Signature] -// ] +// COSE_Sign = [ +// Headers, +// payload : bstr / nil, +// signatures : [+ COSE_Signature] +// ] // // Reference: https://tools.ietf.org/html/rfc8152#section-4.1 type signMessage struct { @@ -284,11 +276,10 @@ var signMessagePrefix = []byte{ // // Reference: https://tools.ietf.org/html/rfc8152#section-4.1 // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// type SignMessage struct { Headers Headers Payload []byte @@ -297,11 +288,10 @@ type SignMessage struct { // NewSignMessage returns a SignMessage with header initialized. // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func NewSignMessage() *SignMessage { return &SignMessage{ Headers: Headers{ @@ -313,11 +303,10 @@ func NewSignMessage() *SignMessage { // MarshalCBOR encodes SignMessage into a COSE_Sign_Tagged object. // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (m *SignMessage) MarshalCBOR() ([]byte, error) { if m == nil { return nil, errors.New("cbor: MarshalCBOR on nil SignMessage pointer") @@ -351,11 +340,10 @@ func (m *SignMessage) MarshalCBOR() ([]byte, error) { // UnmarshalCBOR decodes a COSE_Sign_Tagged object into SignMessage. // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (m *SignMessage) UnmarshalCBOR(data []byte) error { if m == nil { return errors.New("cbor: UnmarshalCBOR on nil SignMessage pointer") @@ -405,11 +393,10 @@ func (m *SignMessage) UnmarshalCBOR(data []byte) error { // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (m *SignMessage) Sign(rand io.Reader, external []byte, signers ...Signer) error { if m == nil { return errors.New("signing nil SignMessage") @@ -451,11 +438,10 @@ func (m *SignMessage) Sign(rand io.Reader, external []byte, signers ...Signer) e // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 // -// Experimental +// # Experimental // // Notice: The COSE Sign API is EXPERIMENTAL and may be changed or removed in a // later release. -// func (m *SignMessage) Verify(external []byte, verifiers ...Verifier) error { if m == nil { return errors.New("verifying nil SignMessage") diff --git a/vendor/github.com/veraison/go-cose/sign1.go b/vendor/github.com/veraison/go-cose/sign1.go index a1e2771998..fa229e99f7 100644 --- a/vendor/github.com/veraison/go-cose/sign1.go +++ b/vendor/github.com/veraison/go-cose/sign1.go @@ -10,11 +10,11 @@ import ( // sign1Message represents a COSE_Sign1 CBOR object: // -// COSE_Sign1 = [ -// Headers, -// payload : bstr / nil, -// signature : bstr -// ] +// COSE_Sign1 = [ +// Headers, +// payload : bstr / nil, +// signature : bstr +// ] // // Reference: https://tools.ietf.org/html/rfc8152#section-4.2 type sign1Message struct { @@ -52,22 +52,11 @@ func NewSign1Message() *Sign1Message { // MarshalCBOR encodes Sign1Message into a COSE_Sign1_Tagged object. func (m *Sign1Message) MarshalCBOR() ([]byte, error) { - if m == nil { - return nil, errors.New("cbor: MarshalCBOR on nil Sign1Message pointer") - } - if len(m.Signature) == 0 { - return nil, ErrEmptySignature - } - protected, unprotected, err := m.Headers.marshal() + content, err := m.getContent() if err != nil { return nil, err } - content := sign1Message{ - Protected: protected, - Unprotected: unprotected, - Payload: m.Payload, - Signature: m.Signature, - } + return encMode.Marshal(cbor.Tag{ Number: CBORTagSign1Message, Content: content, @@ -85,28 +74,7 @@ func (m *Sign1Message) UnmarshalCBOR(data []byte) error { return errors.New("cbor: invalid COSE_Sign1_Tagged object") } - // decode to sign1Message and parse - var raw sign1Message - if err := decModeWithTagsForbidden.Unmarshal(data[1:], &raw); err != nil { - return err - } - if len(raw.Signature) == 0 { - return ErrEmptySignature - } - msg := Sign1Message{ - Headers: Headers{ - RawProtected: raw.Protected, - RawUnprotected: raw.Unprotected, - }, - Payload: raw.Payload, - Signature: raw.Signature, - } - if err := msg.Headers.UnmarshalFromRaw(); err != nil { - return err - } - - *m = msg - return nil + return m.doUnmarshal(data[1:]) } // Sign signs a Sign1Message using the provided Signer. @@ -138,11 +106,11 @@ func (m *Sign1Message) Sign(rand io.Reader, external []byte, signer Signer) erro } // sign the message - digest, err := m.digestToBeSigned(alg, external) + toBeSigned, err := m.toBeSigned(external) if err != nil { return err } - sig, err := signer.Sign(rand, digest) + sig, err := signer.Sign(rand, toBeSigned) if err != nil { return err } @@ -175,20 +143,17 @@ func (m *Sign1Message) Verify(external []byte, verifier Verifier) error { } // verify the message - digest, err := m.digestToBeSigned(alg, external) + toBeSigned, err := m.toBeSigned(external) if err != nil { return err } - return verifier.Verify(digest, m.Signature) + return verifier.Verify(toBeSigned, m.Signature) } -// digestToBeSigned constructs Sig_structure, computes ToBeSigned, and returns -// the digest of ToBeSigned. -// If the signing algorithm does not have a hash algorithm associated, -// ToBeSigned is returned instead. +// toBeSigned constructs Sig_structure, computes and returns ToBeSigned. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 -func (m *Sign1Message) digestToBeSigned(alg Algorithm, external []byte) ([]byte, error) { +func (m *Sign1Message) toBeSigned(external []byte) ([]byte, error) { // create a Sig_structure and populate it with the appropriate fields. // // Sig_structure = [ @@ -202,6 +167,10 @@ func (m *Sign1Message) digestToBeSigned(alg Algorithm, external []byte) ([]byte, if err != nil { return nil, err } + protected, err = deterministicBinaryString(protected) + if err != nil { + return nil, err + } if external == nil { external = []byte{} } @@ -214,14 +183,54 @@ func (m *Sign1Message) digestToBeSigned(alg Algorithm, external []byte) ([]byte, // create the value ToBeSigned by encoding the Sig_structure to a byte // string. - toBeSigned, err := encMode.Marshal(sigStructure) + return encMode.Marshal(sigStructure) +} + +func (m *Sign1Message) getContent() (sign1Message, error) { + if m == nil { + return sign1Message{}, errors.New("cbor: MarshalCBOR on nil Sign1Message pointer") + } + if len(m.Signature) == 0 { + return sign1Message{}, ErrEmptySignature + } + protected, unprotected, err := m.Headers.marshal() if err != nil { - return nil, err + return sign1Message{}, err + } + + content := sign1Message{ + Protected: protected, + Unprotected: unprotected, + Payload: m.Payload, + Signature: m.Signature, + } + + return content, nil +} + +func (m *Sign1Message) doUnmarshal(data []byte) error { + // decode to sign1Message and parse + var raw sign1Message + if err := decModeWithTagsForbidden.Unmarshal(data, &raw); err != nil { + return err + } + if len(raw.Signature) == 0 { + return ErrEmptySignature + } + msg := Sign1Message{ + Headers: Headers{ + RawProtected: raw.Protected, + RawUnprotected: raw.Unprotected, + }, + Payload: raw.Payload, + Signature: raw.Signature, + } + if err := msg.Headers.UnmarshalFromRaw(); err != nil { + return err } - // hash toBeSigned if there is a hash algorithm associated with the signing - // algorithm. - return alg.computeHash(toBeSigned) + *m = msg + return nil } // Sign1 signs a Sign1Message using the provided Signer. @@ -240,3 +249,71 @@ func Sign1(rand io.Reader, signer Signer, headers Headers, payload []byte, exter } return msg.MarshalCBOR() } + +type UntaggedSign1Message Sign1Message + +// MarshalCBOR encodes UntaggedSign1Message into a COSE_Sign1 object. +func (m *UntaggedSign1Message) MarshalCBOR() ([]byte, error) { + content, err := (*Sign1Message)(m).getContent() + if err != nil { + return nil, err + } + + return encMode.Marshal(content) +} + +// UnmarshalCBOR decodes a COSE_Sign1 object into an UnataggedSign1Message. +func (m *UntaggedSign1Message) UnmarshalCBOR(data []byte) error { + if m == nil { + return errors.New("cbor: UnmarshalCBOR on nil UntaggedSign1Message pointer") + } + + if len(data) == 0 { + return errors.New("cbor: zero length data") + } + + // fast message check - ensure the frist byte indicates a four-element array + if data[0] != sign1MessagePrefix[1] { + return errors.New("cbor: invalid COSE_Sign1 object") + } + + return (*Sign1Message)(m).doUnmarshal(data) +} + +// Sign signs an UnttaggedSign1Message using the provided Signer. +// The signature is stored in m.Signature. +// +// Note that m.Signature is only valid as long as m.Headers.Protected and +// m.Payload remain unchanged after calling this method. +// It is possible to modify m.Headers.Unprotected after signing, +// i.e., add counter signatures or timestamps. +// +// Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 +func (m *UntaggedSign1Message) Sign(rand io.Reader, external []byte, signer Signer) error { + return (*Sign1Message)(m).Sign(rand, external, signer) +} + +// Verify verifies the signature on the UntaggedSign1Message returning nil on success or +// a suitable error if verification fails. +// +// Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 +func (m *UntaggedSign1Message) Verify(external []byte, verifier Verifier) error { + return (*Sign1Message)(m).Verify(external, verifier) +} + +// Sign1Untagged signs an UntaggedSign1Message using the provided Signer. +// +// This method is a wrapper of `UntaggedSign1Message.Sign()`. +// +// Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-4.4 +func Sign1Untagged(rand io.Reader, signer Signer, headers Headers, payload []byte, external []byte) ([]byte, error) { + msg := UntaggedSign1Message{ + Headers: headers, + Payload: payload, + } + err := msg.Sign(rand, external, signer) + if err != nil { + return nil, err + } + return msg.MarshalCBOR() +} diff --git a/vendor/github.com/veraison/go-cose/signer.go b/vendor/github.com/veraison/go-cose/signer.go index aa8d7d1c93..674754670e 100644 --- a/vendor/github.com/veraison/go-cose/signer.go +++ b/vendor/github.com/veraison/go-cose/signer.go @@ -15,11 +15,12 @@ type Signer interface { // Algorithm returns the signing algorithm associated with the private key. Algorithm() Algorithm - // Sign signs digest with the private key, possibly using entropy from rand. + // Sign signs message content with the private key, possibly using entropy + // from rand. // The resulting signature should follow RFC 8152 section 8. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8 - Sign(rand io.Reader, digest []byte) ([]byte, error) + Sign(rand io.Reader, content []byte) ([]byte, error) } // NewSigner returns a signer with a given signing key. @@ -40,7 +41,7 @@ func NewSigner(alg Algorithm, key crypto.Signer) (Signer, error) { case AlgorithmPS256, AlgorithmPS384, AlgorithmPS512: vk, ok := key.Public().(*rsa.PublicKey) if !ok { - return nil, fmt.Errorf("%v: %w", alg, ErrAlgorithmMismatch) + return nil, fmt.Errorf("%v: %w", alg, ErrInvalidPubKey) } // RFC 8230 6.1 requires RSA keys having a minimum size of 2048 bits. // Reference: https://www.rfc-editor.org/rfc/rfc8230.html#section-6.1 @@ -54,7 +55,7 @@ func NewSigner(alg Algorithm, key crypto.Signer) (Signer, error) { case AlgorithmES256, AlgorithmES384, AlgorithmES512: vk, ok := key.Public().(*ecdsa.PublicKey) if !ok { - return nil, fmt.Errorf("%v: %w", alg, ErrAlgorithmMismatch) + return nil, fmt.Errorf("%v: %w", alg, ErrInvalidPubKey) } if sk, ok := key.(*ecdsa.PrivateKey); ok { return &ecdsaKeySigner{ @@ -69,7 +70,7 @@ func NewSigner(alg Algorithm, key crypto.Signer) (Signer, error) { }, nil case AlgorithmEd25519: if _, ok := key.Public().(ed25519.PublicKey); !ok { - return nil, fmt.Errorf("%v: %w", alg, ErrAlgorithmMismatch) + return nil, fmt.Errorf("%v: %w", alg, ErrInvalidPubKey) } return &ed25519Signer{ key: key, diff --git a/vendor/github.com/veraison/go-cose/verifier.go b/vendor/github.com/veraison/go-cose/verifier.go index 423723feb8..1c6e83b457 100644 --- a/vendor/github.com/veraison/go-cose/verifier.go +++ b/vendor/github.com/veraison/go-cose/verifier.go @@ -14,11 +14,12 @@ type Verifier interface { // Algorithm returns the signing algorithm associated with the public key. Algorithm() Algorithm - // Verify verifies digest with the public key, returning nil for success. + // Verify verifies message content with the public key, returning nil for + // success. // Otherwise, it returns ErrVerification. // // Reference: https://datatracker.ietf.org/doc/html/rfc8152#section-8 - Verify(digest, signature []byte) error + Verify(content, signature []byte) error } // NewVerifier returns a verifier with a given public key. @@ -29,7 +30,7 @@ func NewVerifier(alg Algorithm, key crypto.PublicKey) (Verifier, error) { case AlgorithmPS256, AlgorithmPS384, AlgorithmPS512: vk, ok := key.(*rsa.PublicKey) if !ok { - return nil, fmt.Errorf("%v: %w", alg, ErrAlgorithmMismatch) + return nil, fmt.Errorf("%v: %w", alg, ErrInvalidPubKey) } // RFC 8230 6.1 requires RSA keys having a minimun size of 2048 bits. // Reference: https://www.rfc-editor.org/rfc/rfc8230.html#section-6.1 @@ -43,7 +44,10 @@ func NewVerifier(alg Algorithm, key crypto.PublicKey) (Verifier, error) { case AlgorithmES256, AlgorithmES384, AlgorithmES512: vk, ok := key.(*ecdsa.PublicKey) if !ok { - return nil, fmt.Errorf("%v: %w", alg, ErrAlgorithmMismatch) + return nil, fmt.Errorf("%v: %w", alg, ErrInvalidPubKey) + } + if !vk.Curve.IsOnCurve(vk.X, vk.Y) { + return nil, errors.New("public key point is not on curve") } return &ecdsaVerifier{ alg: alg, @@ -52,7 +56,7 @@ func NewVerifier(alg Algorithm, key crypto.PublicKey) (Verifier, error) { case AlgorithmEd25519: vk, ok := key.(ed25519.PublicKey) if !ok { - return nil, fmt.Errorf("%v: %w", alg, ErrAlgorithmMismatch) + return nil, fmt.Errorf("%v: %w", alg, ErrInvalidPubKey) } return &ed25519Verifier{ key: vk, diff --git a/vendor/modules.txt b/vendor/modules.txt index 2047bdeda1..40ab9027ff 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -367,7 +367,7 @@ github.com/vektah/gqlparser/v2/lexer github.com/vektah/gqlparser/v2/parser github.com/vektah/gqlparser/v2/validator github.com/vektah/gqlparser/v2/validator/rules -# github.com/veraison/go-cose v1.0.0-rc.1 +# github.com/veraison/go-cose v1.1.0 ## explicit; go 1.18 github.com/veraison/go-cose # github.com/vishvananda/netlink v1.2.1-beta.2