Skip to content
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

doc: add signature documents #39

Merged
merged 2 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 20 additions & 19 deletions signature/algorithm.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (
"fmt"
)

// Algorithm lists supported algorithms.
// Algorithm defines the signature algorithm.
type Algorithm int

// One of following supported specs
// https://github.com/notaryproject/notaryproject/blob/main/signature-specification.md#algorithm-selection
// Signature algorithms supported by this library.
//
// Reference: https://github.com/notaryproject/notaryproject/blob/main/signature-specification.md#algorithm-selection
const (
AlgorithmPS256 Algorithm = 1 + iota // RSASSA-PSS with SHA-256
AlgorithmPS384 // RSASSA-PSS with SHA-384
Expand All @@ -22,20 +23,7 @@ const (
AlgorithmES512 // ECDSA on secp521r1 with SHA-512
)

// Hash returns the corresponding crypto hash algorithm.
func (alg Algorithm) Hash() crypto.Hash {
switch alg {
case AlgorithmPS256, AlgorithmES256:
return crypto.SHA256
case AlgorithmPS384, AlgorithmES384:
return crypto.SHA384
case AlgorithmPS512, AlgorithmES512:
return crypto.SHA512
}
return 0
}

// KeyType defines the key type
// KeyType defines the key type.
type KeyType int

const (
Expand All @@ -49,7 +37,20 @@ type KeySpec struct {
Size int
}

// ExtractKeySpec extracts keySpec from the signing certificate
// Hash returns the hash function of the algorithm.
func (alg Algorithm) Hash() crypto.Hash {
switch alg {
case AlgorithmPS256, AlgorithmES256:
return crypto.SHA256
case AlgorithmPS384, AlgorithmES384:
return crypto.SHA384
case AlgorithmPS512, AlgorithmES512:
return crypto.SHA512
}
return 0
}

// ExtractKeySpec extracts KeySpec from the signing certificate.
func ExtractKeySpec(signingCert *x509.Certificate) (KeySpec, error) {
switch key := signingCert.PublicKey.(type) {
case *rsa.PublicKey:
Expand Down Expand Up @@ -80,7 +81,7 @@ func ExtractKeySpec(signingCert *x509.Certificate) (KeySpec, error) {
return KeySpec{}, fmt.Errorf("invalid public key type")
}

// SignatureAlgorithm returns the signing algorithm associated with KeyType k.
// SignatureAlgorithm returns the signing algorithm associated with the KeySpec.
func (k KeySpec) SignatureAlgorithm() Algorithm {
switch k.Type {
case KeyTypeEC:
Expand Down
21 changes: 13 additions & 8 deletions signature/envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package signature

import "fmt"

// Envelope provides functions to basic functions to manipulate signatures
// Envelope provides functions to basic functions to manipulate signatures.
type Envelope interface {
// Sign generates and sign the envelope according to the sign request.
Sign(req *SignRequest) ([]byte, error)
Expand All @@ -20,22 +20,26 @@ type Envelope interface {
SignerInfo() (*SignerInfo, error)
}

// NewEnvelopeFunc defines a function to create a new Envelope
// NewEnvelopeFunc defines a function to create a new Envelope.
type NewEnvelopeFunc func() Envelope

// ParseEnvelopeFunc defines a function to create a new Envelope with given
// envelope bytes
// ParseEnvelopeFunc defines a function that takes envelope bytes to create
// an Envelope.
type ParseEnvelopeFunc func([]byte) (Envelope, error)

// envelopeFunc wraps functions to create and parsenew envelopes.
type envelopeFunc struct {
newFunc NewEnvelopeFunc
parseFunc ParseEnvelopeFunc
}

// envelopeFuncs maps envelope media type to corresponding constructors and
// parsers.
var envelopeFuncs = make(map[string]envelopeFunc)

// RegisterEnvelopeType registers newFunc and parseFunc for the given mediaType
// Thoese functions are intended to be called when creating a new envelope
// RegisterEnvelopeType registers newFunc and parseFunc for the given mediaType.
// Those functions are intended to be called when creating a new envelope.
// It will be called while inializing the built-in envelopes(JWS/COSE).
func RegisterEnvelopeType(mediaType string, newFunc NewEnvelopeFunc, parseFunc ParseEnvelopeFunc) error {
if newFunc == nil || parseFunc == nil {
return fmt.Errorf("required functions not provided")
Expand All @@ -59,7 +63,7 @@ func RegisteredEnvelopeTypes() []string {
return types
}

// NewEnvelope returns an envelope of given media type
// NewEnvelope generates an envelope of given media type.
func NewEnvelope(mediaType string) (Envelope, error) {
envelopeFunc, ok := envelopeFuncs[mediaType]
if !ok {
Expand All @@ -68,7 +72,8 @@ func NewEnvelope(mediaType string) (Envelope, error) {
return envelopeFunc.newFunc(), nil
}

// NewEnvelope returns an envelope generated by given bytes and media type
// NewEnvelope generates an envelope by given envelope bytes with specified
// media type.
func ParseEnvelope(mediaType string, envelopeBytes []byte) (Envelope, error) {
envelopeFunc, ok := envelopeFuncs[mediaType]
if !ok {
Expand Down
17 changes: 12 additions & 5 deletions signature/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type MalformedSignatureError struct {
Msg string
}

// Error returns the error message.
// Error returns the error message or the default message if not provided.
func (e *MalformedSignatureError) Error() string {
if e.Msg != "" {
return e.Msg
Expand All @@ -22,7 +22,7 @@ type UnsupportedSigningKeyError struct {
Msg string
}

// Error returns the error message.
// Error returns the error message or the default message if not provided.
func (e *UnsupportedSigningKeyError) Error() string {
if e.Msg != "" {
return e.Msg
Expand Down Expand Up @@ -54,6 +54,7 @@ type MalformedSignRequestError struct {
Msg string
}

// Error returns the error message or the default message if not provided.
func (e *MalformedSignRequestError) Error() string {
if e.Msg != "" {
return e.Msg
Expand All @@ -66,26 +67,31 @@ type SignatureAlgoNotSupportedError struct {
Alg string
}

// Error returns the formatted error message.
func (e *SignatureAlgoNotSupportedError) Error() string {
return fmt.Sprintf("signature algorithm %q is not supported", e.Alg)
}

// SignatureIntegrityError is used when the Signature associated is no longer valid.
// SignatureIntegrityError is used when the signature associated is no longer
// valid.
type SignatureIntegrityError struct {
Err error
}

// Error returns the formatted error message.
func (e *SignatureIntegrityError) Error() string {
return fmt.Sprintf("signature is invalid. Error: %s", e.Err.Error())
}

// Unwrap unwraps the internal error.
func (e *SignatureIntegrityError) Unwrap() error {
return e.Err
}

// SignatureNotFoundError is used when signature envelope is not present.
type SignatureNotFoundError struct{}

// Error returns the default error message.
func (e *SignatureNotFoundError) Error() string {
return "signature envelope is not present"
}
Expand All @@ -94,6 +100,7 @@ func (e *SignatureNotFoundError) Error() string {
// trusted certificates.
type SignatureAuthenticityError struct{}

// Error returns the default error message.
func (e *SignatureAuthenticityError) Error() string {
return "signature is not produced by a trusted signer"
}
Expand All @@ -113,7 +120,7 @@ type EnvelopeKeyRepeatedError struct {
Key string
}

// Error returns the formatted error message
// Error returns the formatted error message.
func (e *EnvelopeKeyRepeatedError) Error() string {
return fmt.Sprintf("repeated key: `%s` exists in the envelope.", e.Key)
return fmt.Sprintf("repeated key: %q exists in the envelope.", e.Key)
}
23 changes: 16 additions & 7 deletions signature/internal/base/envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ type Envelope struct {
Raw []byte // raw signature
}

// Sign generates signature using given SignRequest.
// Sign generates signature in terms of given SignRequest.
//
// Reference: https://github.com/notaryproject/notaryproject/blob/main/signing-and-verification-workflow.md#signing-steps
func (e *Envelope) Sign(req *signature.SignRequest) ([]byte, error) {
// Sanitize request
req.SigningTime = req.SigningTime.Truncate(time.Second)
Expand All @@ -33,10 +35,14 @@ func (e *Envelope) Sign(req *signature.SignRequest) ([]byte, error) {
return e.Raw, nil
}

// Verify performs integrity and other signature specification related validations.
// Returns the payload to be signed and SignerInfo object containing the information
// about the signature.
// Verify performs integrity and other signature specification related
// validations.
// It returns the payload to be signed and SignerInfo object containing the
// information about the signature.
//
// Reference: https://github.com/notaryproject/notaryproject/blob/main/trust-store-trust-policy-specification.md#steps
func (e *Envelope) Verify() (*signature.Payload, *signature.SignerInfo, error) {
// validation before the core verify process.
if len(e.Raw) == 0 {
return nil, nil, &signature.MalformedSignatureError{}
}
Expand All @@ -45,11 +51,13 @@ func (e *Envelope) Verify() (*signature.Payload, *signature.SignerInfo, error) {
return nil, nil, err
}

// core verify process.
payload, signerInfo, err := e.Envelope.Verify()
if err != nil {
return nil, nil, err
}

// validation after the core verify process.
if err = validatePayload(payload); err != nil {
return nil, nil, err
}
Expand All @@ -61,7 +69,7 @@ func (e *Envelope) Verify() (*signature.Payload, *signature.SignerInfo, error) {
return payload, signerInfo, nil
}

// Payload returns the payload to be signed.
// Payload returns the validated payload to be signed.
func (e *Envelope) Payload() (*signature.Payload, error) {
if len(e.Raw) == 0 {
return nil, &signature.MalformedSignatureError{Msg: "raw signature is empty"}
Expand All @@ -77,7 +85,7 @@ func (e *Envelope) Payload() (*signature.Payload, error) {
return payload, nil
}

// SignerInfo returns information about the Signature envelope.
// SignerInfo returns validated information about the signature envelope.
func (e *Envelope) SignerInfo() (*signature.SignerInfo, error) {
if len(e.Raw) == 0 {
return nil, &signature.MalformedSignatureError{Msg: "raw signature is empty"}
Expand Down Expand Up @@ -211,7 +219,8 @@ func validateCertificateChain(certChain []*x509.Certificate, signTime time.Time,
return nil
}

// getSignatureAlgorithm picks up a recommended signing algorithm for given certificate.
// getSignatureAlgorithm picks up a recommended signing algorithm for given
// certificate.
func getSignatureAlgorithm(signingCert *x509.Certificate) (signature.Algorithm, error) {
keySpec, err := signature.ExtractKeySpec(signingCert)
if err != nil {
Expand Down
33 changes: 20 additions & 13 deletions signature/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,34 @@ import (
"fmt"
)

// Signer is used to sign bytes generated after creating signature envelope.
// Signer is used to sign bytes generated after signature envelope created.
type Signer interface {
// Sign signs the digest and returns the raw signature
// Sign signs the digest and returns the raw signature.
Sign(digest []byte) ([]byte, error)
// CertificateChain returns the certificate chain
CertificateChain() ([]*x509.Certificate, error) // note: check signature first
// KeySpec returns the key specification

// CertificateChain returns the certificate chain.
CertificateChain() ([]*x509.Certificate, error)

// KeySpec returns the key specification.
KeySpec() (KeySpec, error)
}

// LocalSigner is used by built-in signers to sign only
// LocalSigner is used by built-in signers to sign only.
type LocalSigner interface {
Signer
// PrivateKey returns the private key

// PrivateKey returns the private key.
PrivateKey() crypto.PrivateKey
}

// signer is a LocalSigner implementation.
type signer struct {
keySpec KeySpec
key crypto.PrivateKey
certs []*x509.Certificate
}

// NewLocalSigner returns a new signer with certificates and private key
// NewLocalSigner returns a new signer with given certificates and private key.
func NewLocalSigner(certs []*x509.Certificate, key crypto.PrivateKey) (LocalSigner, error) {
if len(certs) == 0 {
return nil, &MalformedArgumentError{
Expand Down Expand Up @@ -80,29 +84,32 @@ func isKeyPair(priv crypto.PrivateKey, pub crypto.PublicKey, keySpec KeySpec) bo
}
}

// Sign signs the digest and returns the raw signature
// Sign signs the digest and returns the raw signature.
// This implementation should never be used by built-in signers.
func (s *signer) Sign(digest []byte) ([]byte, error) {
return nil, fmt.Errorf("local signer doesn't support Sign with digest")
return nil, fmt.Errorf("local signer doesn't support sign with digest")
}

// CertificateChain returns the certificate chain
// CertificateChain returns the certificate chain.
func (s *signer) CertificateChain() ([]*x509.Certificate, error) {
return s.certs, nil
}

// KeySpec returns the key specification
// KeySpec returns the key specification.
func (s *signer) KeySpec() (KeySpec, error) {
return s.keySpec, nil
}

// PrivateKey returns the private key
// PrivateKey returns the private key.
func (s *signer) PrivateKey() crypto.PrivateKey {
return s.key
}

// VerifyAuthenticity verifies the certificate chain in the given SignerInfo
// with one of the trusted certificates and returns a certificate that matches
// with one of the certificates in the SignerInfo.
//
// Reference: https://github.com/notaryproject/notaryproject/blob/main/trust-store-trust-policy-specification.md#steps
func VerifyAuthenticity(signerInfo *SignerInfo, trustedCerts []*x509.Certificate) (*x509.Certificate, error) {
if len(trustedCerts) == 0 {
return nil, &MalformedArgumentError{Param: "trustedCerts"}
Expand Down
Loading