Skip to content

Commit a873bb0

Browse files
committed
More testing
1 parent 47c426a commit a873bb0

File tree

5 files changed

+298
-30
lines changed

5 files changed

+298
-30
lines changed

crypto.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,9 @@ func NewEd25519Verifier(keyID string, key *ed25519.PublicKey, config *VerifyConf
336336
// is documented in that package. Set config to nil for a default configuration.
337337
// Fields is the list of required headers and fields, which may be empty (but this is typically insecure).
338338
func NewJWSVerifier(alg jwa.SignatureAlgorithm, key interface{}, keyID string, config *VerifyConfig, fields Fields) (*Verifier, error) {
339+
if alg == jwa.NoSignature {
340+
return nil, fmt.Errorf("the NONE signing algorithm is expressly disallowed")
341+
}
339342
verifier, err := jws.NewVerifier(alg)
340343
if err != nil {
341344
return nil, err

crypto_test.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"crypto/rand"
55
"crypto/rsa"
66
"github.com/lestrrat-go/jwx/jwa"
7+
"github.com/lestrrat-go/jwx/jws"
78
"reflect"
89
"strings"
910
"testing"
@@ -210,3 +211,144 @@ func TestForeignSigner(t *testing.T) {
210211
t.Errorf("verification error: %s", err)
211212
}
212213
}
214+
215+
func makeRSAPrivateKey() *rsa.PrivateKey {
216+
priv, _ := rsa.GenerateKey(rand.Reader, 2048)
217+
return priv
218+
}
219+
func TestNewRSASigner1(t *testing.T) {
220+
type args struct {
221+
keyID string
222+
key *rsa.PrivateKey
223+
config *SignConfig
224+
fields Fields
225+
}
226+
key := makeRSAPrivateKey()
227+
tests := []struct {
228+
name string
229+
args args
230+
want *Signer
231+
wantErr bool
232+
}{
233+
{
234+
name: "happy path",
235+
args: args{
236+
keyID: "key100",
237+
key: key,
238+
config: nil,
239+
fields: *NewFields(),
240+
},
241+
want: &Signer{
242+
keyID: "key100",
243+
key: key,
244+
alg: "rsa-v1_5-sha256",
245+
config: NewSignConfig(),
246+
fields: Fields{},
247+
foreignSigner: nil,
248+
},
249+
wantErr: false,
250+
},
251+
{
252+
name: "nil fields",
253+
args: args{
254+
keyID: "key100",
255+
key: key,
256+
config: nil,
257+
fields: nil,
258+
},
259+
want: nil,
260+
wantErr: true,
261+
},
262+
}
263+
for _, tt := range tests {
264+
t.Run(tt.name, func(t *testing.T) {
265+
got, err := NewRSASigner(tt.args.keyID, tt.args.key, tt.args.config, tt.args.fields)
266+
if (err != nil) != tt.wantErr {
267+
t.Errorf("NewRSASigner() error = %v, wantErr %v", err, tt.wantErr)
268+
return
269+
}
270+
if !reflect.DeepEqual(got, tt.want) {
271+
t.Errorf("NewRSASigner() got = %v, want %v", got, tt.want)
272+
}
273+
})
274+
}
275+
}
276+
277+
func TestNewJWSVerifier(t *testing.T) {
278+
type args struct {
279+
alg jwa.SignatureAlgorithm
280+
key interface{}
281+
keyID string
282+
config *VerifyConfig
283+
fields Fields
284+
}
285+
verifier, _ := jws.NewVerifier("HS256")
286+
tests := []struct {
287+
name string
288+
args args
289+
want *Verifier
290+
wantErr bool
291+
}{
292+
{
293+
name: "happy path",
294+
args: args{
295+
alg: jwa.SignatureAlgorithm("HS256"),
296+
key: "1234",
297+
keyID: "key200",
298+
config: NewVerifyConfig(),
299+
fields: *NewFields(),
300+
},
301+
want: &Verifier{
302+
keyID: "key200",
303+
key: "1234",
304+
alg: "HS256",
305+
config: NewVerifyConfig(),
306+
fields: *NewFields(),
307+
foreignVerifier: verifier,
308+
},
309+
wantErr: false,
310+
},
311+
{
312+
name: "none",
313+
args: args{
314+
alg: jwa.NoSignature,
315+
key: "1234",
316+
keyID: "key200",
317+
config: NewVerifyConfig(),
318+
fields: *NewFields(),
319+
},
320+
want: nil,
321+
wantErr: true,
322+
},
323+
{
324+
name: "bad verifier",
325+
args: args{
326+
alg: jwa.SignatureAlgorithm("bad"),
327+
key: "1234",
328+
keyID: "key200",
329+
config: NewVerifyConfig(),
330+
fields: *NewFields(),
331+
},
332+
want: nil,
333+
wantErr: true,
334+
},
335+
}
336+
for _, tt := range tests {
337+
t.Run(tt.name, func(t *testing.T) {
338+
got, err := NewJWSVerifier(tt.args.alg, tt.args.key, tt.args.keyID, tt.args.config, tt.args.fields)
339+
if (err != nil) != tt.wantErr {
340+
t.Errorf("NewJWSVerifier() error = %v, wantErr %v", err, tt.wantErr)
341+
return
342+
}
343+
if got != nil {
344+
got.foreignVerifier = nil
345+
}
346+
if tt.want != nil {
347+
tt.want.foreignVerifier = nil
348+
}
349+
if !reflect.DeepEqual(got, tt.want) {
350+
t.Errorf("NewJWSVerifier() got = %v, want %v", got, tt.want)
351+
}
352+
})
353+
}
354+
}

fields.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
// cases, NewFields followed by a chain of Add... methods.
1111
type Fields []field
1212

13+
// The SFV representation of a field is name;flagName="flagValue"
1314
type field struct {
1415
name string
1516
flagName, flagValue string
@@ -27,8 +28,7 @@ func (f *field) String() string {
2728
func HeaderList(hs []string) Fields {
2829
var f []field
2930
for _, h := range hs {
30-
hd := strings.ToLower(h) // loop variable scope pitfall!
31-
f = append(f, field{hd, "", ""})
31+
f = append(f, *fromHeaderName(h))
3232
}
3333
return f
3434
}
@@ -52,21 +52,9 @@ func (fs *Fields) AddHeader(hdr string) *Fields {
5252
return fs
5353
}
5454

55-
// addHeaderAndFlag appends a header name, a flag and a value. This eventually results
56-
// in the signature input "header-name";name="val"
57-
func (fs *Fields) addHeaderAndFlag(hdr, flagName, flagValue string) *Fields {
58-
h := strings.ToLower(hdr)
59-
fn := strings.ToLower(flagName)
60-
fv := flagValue
61-
*fs = append(*fs, field{h, fn, fv})
62-
return fs
63-
}
64-
6555
func fromQueryParam(qp string) *field {
6656
q := strings.ToLower(qp)
67-
name := "@query-params"
68-
flagName := "name"
69-
f := field{name, flagName, q}
57+
f := field{"@query-params", "name", q}
7058
return &f
7159
}
7260

signatures.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Package httpsign signs HTTP requests and responses as defined in draft-ietf-httpbis-message-signatures.
22
// See https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-07.html.
33
//
4-
// For client-side message signing, use the Client wrapper. Alternatively, use SignRequest, VerifyResponse directly,
5-
// but this is more complicated.
4+
// For client-side message signing and verification, use the Client wrapper.
5+
// Alternatively, use SignRequest, VerifyResponse directly, but this is more complicated.
66
// For server-side operation,
77
// WrapHandler installs a wrapper around a normal HTTP message handler.
88
package httpsign
@@ -17,21 +17,21 @@ import (
1717
)
1818

1919
func signMessage(config SignConfig, signatureName string, signer Signer, parsedMessage parsedMessage,
20-
fields Fields) (sigInputHeader string, signature string, err error) {
20+
fields Fields) (signatureInputHeader, signature, signatureInput string, err error) {
2121
sigParams, err := generateSigParams(&config, signer.keyID, signer.alg, signer.foreignSigner, fields)
2222
if err != nil {
23-
return "", "", err
23+
return "", "", "", err
2424
}
25-
sigInputHeader = fmt.Sprintf("%s=%s", signatureName, sigParams)
26-
signatureInput, err := generateSignatureInput(parsedMessage, fields, sigParams)
25+
signatureInputHeader = fmt.Sprintf("%s=%s", signatureName, sigParams)
26+
signatureInput, err = generateSignatureInput(parsedMessage, fields, sigParams)
2727
if err != nil {
28-
return "", "", err
28+
return "", "", "", err
2929
}
3030
signature, err = generateSignature(signatureName, signer, signatureInput)
3131
if err != nil {
32-
return "", "", err
32+
return "", "", "", err
3333
}
34-
return sigInputHeader, signature, nil
34+
return signatureInputHeader, signature, signatureInput, nil
3535
}
3636

3737
func generateSignature(name string, signer Signer, input string) (string, error) {
@@ -155,19 +155,25 @@ func generateSigParams(config *SignConfig, keyID, alg string, foreignSigner inte
155155
//
156156
// SignRequest signs an HTTP request. Returns the Signature-Input and the Signature header values.
157157
//
158-
func SignRequest(signatureName string, signer Signer, req *http.Request) (signatureInput, signature string, err error) {
158+
func SignRequest(signatureName string, signer Signer, req *http.Request) (signatureInputHeader, signature string, err error) {
159+
signatureInputHeader, signature, _, err = signRequestDebug(signatureName, signer, req)
160+
return
161+
}
162+
163+
// Same as SignRequest, but also returns the raw signature input string
164+
func signRequestDebug(signatureName string, signer Signer, req *http.Request) (signatureInputHeader, signature, signatureInput string, err error) {
159165
if req == nil {
160-
return "", "", fmt.Errorf("nil request")
166+
return "", "", "", fmt.Errorf("nil request")
161167
}
162168
if signatureName == "" {
163-
return "", "", fmt.Errorf("empty signature name")
169+
return "", "", "", fmt.Errorf("empty signature name")
164170
}
165171
if signer.config.requestResponse != nil {
166-
return "", "", fmt.Errorf("use request-response only to sign responses")
172+
return "", "", "", fmt.Errorf("use request-response only to sign responses")
167173
}
168174
parsedMessage, err := parseRequest(req)
169175
if err != nil {
170-
return "", "", err
176+
return "", "", "", err
171177
}
172178
return signMessage(*signer.config, signatureName, signer, *parsedMessage, signer.fields)
173179
}
@@ -187,7 +193,8 @@ func SignResponse(signatureName string, signer Signer, res *http.Response) (sign
187193
return "", "", err
188194
}
189195
extendedFields := addPseudoHeaders(parsedMessage, signer.config.requestResponse, signer.fields)
190-
return signMessage(*signer.config, signatureName, signer, *parsedMessage, extendedFields)
196+
signatureInput, signature, _, err = signMessage(*signer.config, signatureName, signer, *parsedMessage, extendedFields)
197+
return
191198
}
192199

193200
// Handle the special header-like @request-response

0 commit comments

Comments
 (0)