Skip to content

Make Sign1 and Verify1 difficult to misuse #64

@qmuntal

Description

@qmuntal

Problem statement

NCC Group found a (known) footgun in our API:

The library does not prevent a user from manually populating the signature field or modifying the protected header after calling Sign() to potentially violate this requirement.

Example:

msg, _ := cose.Sign1(rand.Reader, signer, protected, []byte("hello world"), nil)
msg.Signature = []byte("footgun!") // <-------
sig, _ := msg.MarshalCBOR()

The same applies to Verify():

var msg cose.Sign1Message
msg.UnmarshalCBOR(sig)
msg.Signature = nil  // <------- footgun
msg.Verify(nil, verifier)

We initially added Sign1 and Verify1 to make it easier to sign and verify messages, but with the current signature they don't prevent user to misuse go-cose.

Proposal

Me proposal is to change these two functions so they don't work with Sign1Message but just deal with cbor-marshaled messages:

func Sign1(rand io.Reader, signer Signer, header Headers, payload []byte, external []byte) (cbor_msg []byte, err error)

func Verify1(verifier Verifier, cbor_msg []byte, external []byte) error

With this change, users that don't need the flexibility of Sign1Message won't need to even know it exist, as the signature would be represented an opaque, difficult-to-misuse, []byte.

Worth nothing that users can still misuse Sign1Message.Sign() and Sign1Message.Verify(), but keeping them as-is allow advanced users to do their custom marshalling or validations.

Edited: Update Sign1 proposed API.
Edit2: Notice that the proposed signature is very similar to .Net's static CoseSign1Message.Sign(...).
Edit3: Verify1 is proposed to be removed as per thread discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions