Skip to content
This repository has been archived by the owner on Feb 27, 2023. It is now read-only.

Commit

Permalink
Address @csstaub comments
Browse files Browse the repository at this point in the history
  • Loading branch information
bifurcation committed Oct 8, 2015
1 parent 4b2d821 commit abb992d
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 59 deletions.
4 changes: 2 additions & 2 deletions jwe.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {
// Check that there is not a nonce in the unprotected headers
if (parsed.Unprotected != nil && parsed.Unprotected.Nonce != "") ||
(parsed.Header != nil && parsed.Header.Nonce != "") {
return nil, fmt.Errorf("square/go-jose: Nonce parameter included in unprotected header")
return nil, ErrUnprotectedNonce
}

if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
Expand All @@ -159,7 +159,7 @@ func (parsed *rawJsonWebEncryption) sanitized() (*JsonWebEncryption, error) {

// Check that there is not a nonce in the unprotected header
if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.Nonce != "" {
return nil, fmt.Errorf("square/go-jose: Nonce parameter included in unprotected header")
return nil, ErrUnprotectedNonce
}

obj.recipients[r].header = parsed.Recipients[r].Header
Expand Down
58 changes: 29 additions & 29 deletions jwe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,16 @@ func TestRejectUnprotectedJWENonce(t *testing.T) {

// Flattened JSON
input := `{
"header": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
"header": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
_, err := ParseEncrypted(input)
if err == nil {
t.Error("JWE with an unprotected nonce parsed as valid.")
Expand All @@ -172,16 +172,16 @@ func TestRejectUnprotectedJWENonce(t *testing.T) {
}

input = `{
"unprotected": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
"unprotected": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
_, err = ParseEncrypted(input)
if err == nil {
t.Error("JWE with an unprotected nonce parsed as valid.")
Expand All @@ -191,15 +191,15 @@ func TestRejectUnprotectedJWENonce(t *testing.T) {

// Full JSON
input = `{
"header": { "alg": "XYZ", "enc": "XYZ" },
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter",
"recipients": [{
"header": { "nonce": "should-cause-an-error" },
"encrypted_key": "does-not-matter"
}]
"header": { "alg": "XYZ", "enc": "XYZ" },
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter",
"recipients": [{
"header": { "nonce": "should-cause-an-error" },
"encrypted_key": "does-not-matter"
}]
}`
_, err = ParseEncrypted(input)
if err == nil {
Expand Down
6 changes: 3 additions & 3 deletions jws.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func parseSignedFull(input string) (*JsonWebSignature, error) {
// sanitized produces a cleaned-up JWS object from the raw JSON.
func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
if parsed.Payload == nil {
return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
return nil, ErrUnprotectedNonce
}

obj := &JsonWebSignature{
Expand All @@ -126,7 +126,7 @@ func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
}

if parsed.Header != nil && parsed.Header.Nonce != "" {
return nil, fmt.Errorf("square/go-jose: Nonce parameter included in unprotected header")
return nil, ErrUnprotectedNonce
}

signature.header = parsed.Header
Expand Down Expand Up @@ -161,7 +161,7 @@ func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {

// Check that there is not a nonce in the unprotected header
if sig.Header != nil && sig.Header.Nonce != "" {
return nil, fmt.Errorf("square/go-jose: Nonce parameter included in unprotected header")
return nil, ErrUnprotectedNonce
}

obj.Signatures[i].Signature = sig.Signature.bytes()
Expand Down
20 changes: 10 additions & 10 deletions jws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,29 +95,29 @@ func TestRejectUnprotectedJWSNonce(t *testing.T) {

// Flattened JSON
input := `{
"header": { "nonce": "should-cause-an-error" },
"payload": "does-not-matter",
"signature": "does-not-matter"
"header": { "nonce": "should-cause-an-error" },
"payload": "does-not-matter",
"signature": "does-not-matter"
}`
_, err := ParseSigned(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
} else if err != ErrUnprotectedNonce {
t.Errorf("Improper error for unprotected nonce: %v", err)
}

// Full JSON
input = `{
"payload": "does-not-matter",
"signatures": [{
"header": { "nonce": "should-cause-an-error" },
"signature": "does-not-matter"
}]
"payload": "does-not-matter",
"signatures": [{
"header": { "nonce": "should-cause-an-error" },
"signature": "does-not-matter"
}]
}`
_, err = ParseSigned(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
} else if err != ErrUnprotectedNonce {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
}
Expand Down
4 changes: 4 additions & 0 deletions shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ var (
// trying to compact-serialize an object which can't be represented in
// compact form.
ErrNotSupported = errors.New("square/go-jose: compact serialization not supported for object")

// ErrUnprotectedNonce indicates that while parsing a JWS or JWE object, a
// nonce header parameter was included in an unprotected header object.
ErrUnprotectedNonce = errors.New("square/go-jose: Nonce parameter included in unprotected header")
)

// Key management algorithms
Expand Down
32 changes: 18 additions & 14 deletions signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,21 @@ import (
"fmt"
)

// NonceSource represents a source of random nonces to go into JWS objects
type NonceSource interface {
Nonce() (string, error)
}

// Signer represents a signer which takes a payload and produces a signed JWS object.
type Signer interface {
Sign(payload []byte) (*JsonWebSignature, error)
AddNonces(nonces []string)
AddNonceSource(source NonceSource)
}

// MultiSigner represents a signer which supports multiple recipients.
type MultiSigner interface {
Sign(payload []byte) (*JsonWebSignature, error)
AddNonces(nonces []string)
AddNonceSource(source NonceSource)
AddRecipient(alg SignatureAlgorithm, signingKey interface{}) error
}

Expand All @@ -44,8 +49,8 @@ type payloadVerifier interface {
}

type genericSigner struct {
recipients []recipientSigInfo
nonces []string
recipients []recipientSigInfo
nonceSource NonceSource
}

type recipientSigInfo struct {
Expand Down Expand Up @@ -141,13 +146,12 @@ func (ctx *genericSigner) Sign(payload []byte) (*JsonWebSignature, error) {
protected.Kid = recipient.publicKey.KeyID
}

if ctx.nonces != nil {
if len(ctx.nonces) == 0 {
return nil, fmt.Errorf("square/go-jose: Nonce required but no nonces available")
if ctx.nonceSource != nil {
nonce, err := ctx.nonceSource.Nonce()
if err != nil {
return nil, fmt.Errorf("square/go-jose: Error generating nonce: %v", err)
}

protected.Nonce = ctx.nonces[0]
ctx.nonces = ctx.nonces[1:]
protected.Nonce = nonce
}

serializedProtected := mustSerializeJSON(protected)
Expand All @@ -168,11 +172,11 @@ func (ctx *genericSigner) Sign(payload []byte) (*JsonWebSignature, error) {
return obj, nil
}

// AddNonces provides or updates a nonce pool to the first recipients.
// AddNonceSource provides or updates a nonce pool to the first recipients.
// After this method is called, the signer will consume one nonce per
// signature, returning an error if there are no nonces left in the pool.
func (ctx *genericSigner) AddNonces(nonces []string) {
ctx.nonces = append(ctx.nonces, nonces...)
// signature, returning an error it is unable to get a nonce.
func (ctx *genericSigner) AddNonceSource(source NonceSource) {
ctx.nonceSource = source
}

// Verify validates the signature on the object and returns the payload.
Expand Down
8 changes: 7 additions & 1 deletion signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,20 @@ import (
"testing"
)

type staticNonceSource string

func (sns staticNonceSource) Nonce() (string, error) {
return string(sns), nil
}

func RoundtripJWS(sigAlg SignatureAlgorithm, serializer func(*JsonWebSignature) (string, error), corrupter func(*JsonWebSignature), signingKey interface{}, verificationKey interface{}, nonce string) error {
signer, err := NewSigner(sigAlg, signingKey)
if err != nil {
return fmt.Errorf("error on new signer: %s", err)
}

if nonce != "" {
signer.AddNonces([]string{nonce})
signer.AddNonceSource(staticNonceSource(nonce))
}

input := []byte("Lorem ipsum dolor sit amet")
Expand Down

0 comments on commit abb992d

Please sign in to comment.