-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot sign/verify digests anymore (think Merkle tree, ledger, detached payload) #120
Comments
Hi @ivarprudnikov. The current On the other hand, the built-in signers and verifiers (provided by As a matter of fact, the following a sample implementation of a type ecdsaKeySigner struct {
alg Algorithm
key *ecdsa.PrivateKey
}
func (es *ecdsaKeySigner) Algorithm() Algorithm {
return es.alg
}
func (es *ecdsaKeySigner) Sign(rand io.Reader, content []byte) ([]byte, error) {
r, s, err := ecdsa.Sign(rand, es.key, digest)
if err != nil {
return nil, err
}
return encodeECDSASignature(es.key.Curve, r, s)
}
func encodeECDSASignature(curve elliptic.Curve, r, s *big.Int) ([]byte, error) {
n := (curve.Params().N.BitLen() + 7) / 8
sig := make([]byte, n*2)
if err := I2OSP(r, sig[:n]); err != nil {
return nil, err
}
if err := I2OSP(s, sig[n:]); err != nil {
return nil, err
}
return sig, nil
} And the following a sample implementation of a type ecdsaVerifier struct {
alg Algorithm
key *ecdsa.PublicKey
}
func (ev *ecdsaVerifier) Algorithm() Algorithm {
return ev.alg
}
func (ev *ecdsaVerifier) Verify(content []byte, signature []byte) error {
r, s, err := decodeECDSASignature(ev.key.Curve, signature)
if err != nil {
return ErrVerification
}
if verified := ecdsa.Verify(ev.key, digest, r, s); !verified {
return ErrVerification
}
return nil
}
func decodeECDSASignature(curve elliptic.Curve, sig []byte) (r, s *big.Int, err error) {
n := (curve.Params().N.BitLen() + 7) / 8
if len(sig) != n*2 {
return nil, nil, fmt.Errorf("invalid signature length: %d", len(sig))
}
return OS2IP(sig[:n]), OS2IP(sig[n:]), nil
} |
Yet the user needs to implement similar:
This is what I want to avoid as a user of the library and to make it more user friendly for other use cases. |
I see that those ECDSA encode/decode functions are a little bit tricky to implement right.
Could you clarify which other use cases? We could expose a new function, e.g. |
It was a reference to what I wrote in the main issue at the top. Is there a reason not to expose |
Those functions are an implementation detail, not part of the cose spec. IMO if we finally support sign/verify digested payloads it should by via |
@ivarprudnikov, @shizhMSFT, what do you think about |
I think the approach works but the name sounds odd and slightly confusing. It is a difficult one to nail it though, maybe |
I'm actually confused with the goal of this issue. According to RFC 9052 section 4.4, the canonical CBOR encoded |
@shizhMSFT if the idea is to stick to the letter then there is another thing not strictly related to pure cose but to other ecosystem components like receipts where a cose signature is being countersigned. In that case the |
Thank @ivarprudnikov for the elaboration. The scenario you've mentioned is not a typical COSE signing or verification process. Thus, proposing something like Instead of having a new constructor, how about having the following interfaces: type DigestSigner interface {
// Algorithm returns the signing algorithm associated with the private key.
Algorithm() Algorithm
// SignDigest signs message digest with the private key, possibly using
// entropy from rand.
// The resulting signature should follow RFC 8152 section 8.
SignDigest(rand io.Reader, digest []byte) ([]byte, error)
}
type DigestVerifier interface {
// Algorithm returns the signing algorithm associated with the public key.
Algorithm() Algorithm
// VerifyDigest verifies message digest with the public key, returning nil
// for success.
// Otherwise, it returns ErrVerification.
VerifyDigest(digest, signature []byte) error
} Then let The example code can be signer, err := cose.NewSigner(cose.AlgorithmES256, privateKey)
if err != nil {
return nil, err
}
digestSigner, ok := signer.(DigestSigner)
if ok {
sig, err := digestSigner.SignDigest(rand.Reader, digest)
// further process
} else {
// digest signing is not supported. e.g. ed25519
} |
@shizhMSFT agree, looks good. But is the suggestion to implement |
@ivarprudnikov Yes for |
The implementation which allowed to sign the digests was removed in #100 in favor of passing raw content.
There are some cases when the user does not have content:
toBeSigned
, creates a hash and sends to a servicetoBeSigned
is slightly different to the cose oneIs there a chance to extend the interfaces
Signer
andVerifier
to allow digests again, similar toecdsa.Sign
andecdsa.VerifyASN1
?The text was updated successfully, but these errors were encountered: