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..46e40a39 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 @@ -33,8 +34,8 @@ func (e *Envelope) Sign(req *signature.SignRequest) ([]byte, error) { // Returns the payload to be signed and SignerInfo object containing the information // about the signature. func (e *Envelope) Verify() (*signature.Payload, *signature.SignerInfo, error) { - if len(e.Raw) == 0 { - return nil, nil, &signature.MalformedSignatureError{} + if err := e.preVerifyValidation(); err != nil { + return nil, nil, err } return e.Envelope.Verify() @@ -45,7 +46,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. @@ -72,6 +81,15 @@ func (e *Envelope) SignerInfo() (*signature.SignerInfo, error) { return signerInfo, nil } +// preVerifyValidation performs validation before verification of internal envelope. +func (e *Envelope) preVerifyValidation() error { + if len(e.Raw) == 0 { + return &signature.MalformedSignatureError{} + } + + return e.validatePayload() +} + // validatePayload performs validation of the payload. func (e *Envelope) validatePayload() error { payload, err := e.Envelope.Payload() @@ -100,7 +118,17 @@ func validateSignRequest(req *signature.SignRequest) error { 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,16 +168,16 @@ 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 { return &signature.MalformedSignatureError{ Msg: fmt.Sprintf("payload content type: {%s} not supported", payload.ContentType), } } + if len(payload.Content) == 0 { + return &signature.MalformedSignatureError{Msg: "content not present"} + } + return nil } 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) {