From 168b6116114a6cf39d6e22a4f83ecaaab0b1b2c1 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Mon, 15 Aug 2022 17:06:52 +0800 Subject: [PATCH] refactor: add common logic to base envelope (#35) * refactor: add common logic to base envelope Signed-off-by: Binbin Li * feat: add payload and signerInfo verification in Verify Signed-off-by: Binbin Li Signed-off-by: Binbin Li Co-authored-by: Binbin Li --- signature/algorithm.go | 14 +++++++ signature/envelope.go | 17 ++++++-- signature/internal/base/envelope.go | 61 +++++++++++++++++++++-------- signature/jws/signer.go | 2 +- signature/jws/utils.go | 13 ------ 5 files changed, 74 insertions(+), 33 deletions(-) diff --git a/signature/algorithm.go b/signature/algorithm.go index 457a0240..b8665b52 100644 --- a/signature/algorithm.go +++ b/signature/algorithm.go @@ -1,6 +1,7 @@ package signature import ( + "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/x509" @@ -35,6 +36,19 @@ type KeySpec struct { Size int } +// 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) { diff --git a/signature/envelope.go b/signature/envelope.go index 2561a3a4..1f497cfd 100644 --- a/signature/envelope.go +++ b/signature/envelope.go @@ -13,7 +13,7 @@ type Envelope interface { // NewEnvelopeFunc defines a function to create a new Envelope type NewEnvelopeFunc func() Envelope -// ParseEnvelopeFunc defines a function to create a new Envelope with given +// ParseEnvelopeFunc defines a function to create a new Envelope with given // envelope bytes type ParseEnvelopeFunc func([]byte) (Envelope, error) @@ -30,7 +30,7 @@ func RegisterEnvelopeType(mediaType string, newFunc NewEnvelopeFunc, parseFunc P if newFunc == nil || parseFunc == nil { return fmt.Errorf("required functions not provided") } - + envelopeFuncs[mediaType] = envelopeFunc{ newFunc: newFunc, parseFunc: parseFunc, @@ -38,6 +38,17 @@ func RegisterEnvelopeType(mediaType string, newFunc NewEnvelopeFunc, parseFunc P return nil } +// RegisteredEnvelopeTypes lists registered envelope media types. +func RegisteredEnvelopeTypes() []string { + types := []string{} + + for envelopeType := range envelopeFuncs { + types = append(types, envelopeType) + } + + return types +} + // NewEnvelope returns an envelope of given media type func NewEnvelope(mediaType string) (Envelope, error) { envelopeFunc, ok := envelopeFuncs[mediaType] @@ -54,4 +65,4 @@ func ParseEnvelope(mediaType string, envelopeBytes []byte) (Envelope, error) { return nil, fmt.Errorf("envelope is not set for type: %s", mediaType) } return envelopeFunc.parseFunc(envelopeBytes) -} \ No newline at end of file +} diff --git a/signature/internal/base/envelope.go b/signature/internal/base/envelope.go index c38c4fe5..98dc1290 100644 --- a/signature/internal/base/envelope.go +++ b/signature/internal/base/envelope.go @@ -22,6 +22,7 @@ func (e *Envelope) Sign(req *signature.SignRequest) ([]byte, error) { if err != nil { return nil, err } + e.Raw, err = e.Envelope.Sign(req) if err != nil { return nil, err @@ -37,7 +38,24 @@ func (e *Envelope) Verify() (*signature.Payload, *signature.SignerInfo, error) { return nil, nil, &signature.MalformedSignatureError{} } - return e.Envelope.Verify() + if err := e.validatePayload(); err != nil { + return nil, nil, err + } + + payload, signerInfo, err := e.Envelope.Verify() + if err != nil { + return nil, nil, err + } + + if err = validatePayload(payload); err != nil { + return nil, nil, err + } + + if err = validateSignerInfo(signerInfo); err != nil { + return nil, nil, err + } + + return payload, signerInfo, nil } // Payload returns the payload to be signed. @@ -45,7 +63,15 @@ func (e *Envelope) Payload() (*signature.Payload, error) { if len(e.Raw) == 0 { return nil, &signature.MalformedSignatureError{Msg: "raw signature is empty"} } - return e.Envelope.Payload() + payload, err := e.Envelope.Payload() + if err != nil { + return nil, err + } + + if err = validatePayload(payload); err != nil { + return nil, err + } + return payload, nil } // SignerInfo returns information about the Signature envelope. @@ -65,10 +91,6 @@ func (e *Envelope) SignerInfo() (*signature.SignerInfo, error) { return nil, err } - if err := e.validatePayload(); err != nil { - return nil, err - } - return signerInfo, nil } @@ -92,15 +114,21 @@ func validateSignRequest(req *signature.SignRequest) error { return err } - if len(req.Payload.Content) == 0 { - return &signature.MalformedSignatureError{Msg: "payload not present"} - } - if req.Signer == nil { return &signature.MalformedSignatureError{Msg: "signer is nil"} } - return nil + certs, err := req.Signer.CertificateChain() + if err != nil { + return err + } + + keySpec, err := req.Signer.KeySpec() + if err != nil { + return err + } + + return validateCertificateChain(certs, req.SigningTime, keySpec.SignatureAlgorithm()) } // validateSignerInfo performs basic set of validations on SignerInfo struct. @@ -140,11 +168,12 @@ func validateSigningTime(signingTime, expireTime time.Time) error { // validatePayload performs validation of the payload. func validatePayload(payload *signature.Payload) error { - if len(payload.Content) == 0 { - return &signature.MalformedSignatureError{Msg: "content not present"} - } - - if payload.ContentType != signature.MediaTypePayloadV1 { + switch payload.ContentType { + case signature.MediaTypePayloadV1: + if len(payload.Content) == 0 { + return &signature.MalformedSignatureError{Msg: "content not present"} + } + default: return &signature.MalformedSignatureError{ Msg: fmt.Sprintf("payload content type: {%s} not supported", payload.ContentType), } diff --git a/signature/jws/signer.go b/signature/jws/signer.go index ca512fc5..73a6f0a5 100644 --- a/signature/jws/signer.go +++ b/signature/jws/signer.go @@ -19,7 +19,7 @@ func (s *JwsSigner) Sign(digest []byte) ([]byte, error) { if err != nil { return nil, err } - hasher := hash(keySpec.SignatureAlgorithm()) + hasher := keySpec.SignatureAlgorithm().Hash() h := hasher.New() h.Write(digest) hash := h.Sum(nil) diff --git a/signature/jws/utils.go b/signature/jws/utils.go index 5a8ff7a6..987f327f 100644 --- a/signature/jws/utils.go +++ b/signature/jws/utils.go @@ -112,19 +112,6 @@ func mergeMaps(maps ...map[string]interface{}) map[string]interface{} { return result } -func hash(algorithm signature.Algorithm) crypto.Hash { - var hash crypto.Hash - switch algorithm { - case signature.AlgorithmPS256, signature.AlgorithmES256: - hash = crypto.SHA256 - case signature.AlgorithmPS384, signature.AlgorithmES384: - hash = crypto.SHA384 - case signature.AlgorithmPS512, signature.AlgorithmES512: - hash = crypto.SHA512 - } - return hash -} - // getSigningMethod picks up a recommended algorithm for given public keys. func getSigningMethod(key crypto.PublicKey) (jwt.SigningMethod, error) { switch key := key.(type) {