mirror of
https://github.com/fleetdm/fleet
synced 2026-05-22 16:39:01 +00:00
201 lines
4.3 KiB
Go
201 lines
4.3 KiB
Go
|
|
package httpsig
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bufio"
|
||
|
|
"bytes"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/remitly-oss/httpsig-go/sigtest"
|
||
|
|
)
|
||
|
|
|
||
|
|
// FuzzSigningOptions fuzzes the basic user input to SigningOptions
|
||
|
|
func FuzzSigningOptions1(f *testing.F) {
|
||
|
|
testcases := [][]string{
|
||
|
|
{"", "", "", ""},
|
||
|
|
{"", "0", "0", "\xde"},
|
||
|
|
{"", "\n", "0", "0"},
|
||
|
|
{"", "", "0", "@"},
|
||
|
|
{"", "@query-param", "0", "0"},
|
||
|
|
{string(Algo_ECDSA_P256_SHA256), "@query", "0", "0"},
|
||
|
|
{"any", "@query", "0", "0"},
|
||
|
|
{string(Algo_ED25519), "@query", "0", "0"},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range testcases {
|
||
|
|
f.Add(tc[0], tc[1], tc[2], tc[3])
|
||
|
|
}
|
||
|
|
|
||
|
|
reqtxt, err := os.ReadFile("testdata/rfc-test-request.txt")
|
||
|
|
if err != nil {
|
||
|
|
f.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
f.Fuzz(func(t *testing.T, algo, label, keyID, tag string) {
|
||
|
|
t.Logf("Label: %s\n", label)
|
||
|
|
t.Logf("keyid: %s\n", keyID)
|
||
|
|
t.Logf("tag: %s\n", tag)
|
||
|
|
|
||
|
|
fields := Fields(label, keyID, tag)
|
||
|
|
fields = append(fields, SignedField{
|
||
|
|
Name: label,
|
||
|
|
Parameters: map[string]any{
|
||
|
|
keyID: tag,
|
||
|
|
},
|
||
|
|
})
|
||
|
|
privKey := sigtest.ReadTestPrivateKey(t, "test-key-ed25519.key")
|
||
|
|
so := SigningProfile{
|
||
|
|
Algorithm: Algo_ED25519,
|
||
|
|
Fields: Fields(label, keyID, tag),
|
||
|
|
Metadata: []Metadata{MetaKeyID, MetaTag},
|
||
|
|
Label: label,
|
||
|
|
}
|
||
|
|
sk := SigningKey{
|
||
|
|
Key: privKey,
|
||
|
|
MetaKeyID: keyID,
|
||
|
|
MetaTag: tag,
|
||
|
|
}
|
||
|
|
if so.validate(sk) != nil {
|
||
|
|
// Catching invalidate signing options is good.
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(reqtxt)))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
err = Sign(req, so, sk)
|
||
|
|
if err != nil {
|
||
|
|
if _, ok := err.(*SignatureError); ok {
|
||
|
|
// Handled error
|
||
|
|
return
|
||
|
|
}
|
||
|
|
// Unhandled error
|
||
|
|
t.Error(err)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func FuzzSigningOptionsFields(f *testing.F) {
|
||
|
|
testcases := [][]string{
|
||
|
|
{"", "", ""},
|
||
|
|
{"0", "0", "\xde"},
|
||
|
|
{"\n", "0", "0"},
|
||
|
|
{"", "0", "@"},
|
||
|
|
{"@query-param", "name", "0"},
|
||
|
|
{"@query", "0", "0"},
|
||
|
|
{"@method", "", ""},
|
||
|
|
{"@status", "", ""},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range testcases {
|
||
|
|
f.Add(tc[0], tc[1], tc[2])
|
||
|
|
}
|
||
|
|
|
||
|
|
reqtxt, err := os.ReadFile("testdata/rfc-test-request.txt")
|
||
|
|
if err != nil {
|
||
|
|
f.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
f.Fuzz(func(t *testing.T, field, tagName, tagValue string) {
|
||
|
|
t.Logf("field: %s\n", field)
|
||
|
|
t.Logf("tag: %s:%s\n", tagName, tagValue)
|
||
|
|
fields := []SignedField{}
|
||
|
|
if tagName == "" {
|
||
|
|
fields = append(fields, SignedField{
|
||
|
|
Name: field,
|
||
|
|
})
|
||
|
|
} else {
|
||
|
|
fields = append(fields, SignedField{
|
||
|
|
Name: field,
|
||
|
|
Parameters: map[string]any{
|
||
|
|
tagName: tagValue,
|
||
|
|
},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
so := SigningProfile{
|
||
|
|
Algorithm: Algo_ED25519,
|
||
|
|
Fields: fields,
|
||
|
|
}
|
||
|
|
sk := SigningKey{
|
||
|
|
Key: sigtest.ReadTestPrivateKey(t, "test-key-ed25519.key"),
|
||
|
|
}
|
||
|
|
if so.validate(sk) != nil {
|
||
|
|
// Catching invalidate signing options is good.
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(reqtxt)))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
err = Sign(req, so, sk)
|
||
|
|
if err != nil {
|
||
|
|
if _, ok := err.(*SignatureError); ok {
|
||
|
|
// Handled error
|
||
|
|
return
|
||
|
|
}
|
||
|
|
// Unhandled error
|
||
|
|
t.Error(err)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func FuzzExtractSignatures(f *testing.F) {
|
||
|
|
testcases := []struct {
|
||
|
|
SignatureHeader string
|
||
|
|
SignatureInputHeader string
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
SignatureHeader: "",
|
||
|
|
SignatureInputHeader: "",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
SignatureHeader: "sig-b24=(\"@status\" \"content-type\" \"content-digest\" \"content-length\");created=1618884473;keyid=\"test-key-ecc-p256\"",
|
||
|
|
SignatureInputHeader: "sig-b24=:wNmSUAhwb5LxtOtOpNa6W5xj067m5hFrj0XQ4fvpaCLx0NKocgPquLgyahnzDnDAUy5eCdlYUEkLIj+32oiasw==:",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range testcases {
|
||
|
|
f.Add(tc.SignatureHeader, tc.SignatureInputHeader)
|
||
|
|
}
|
||
|
|
|
||
|
|
reqtxt, err := os.ReadFile("testdata/rfc-test-request.txt")
|
||
|
|
if err != nil {
|
||
|
|
f.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
f.Fuzz(func(t *testing.T, sigHeader, sigInputHeader string) {
|
||
|
|
t.Logf("signature header: %s\n", sigHeader)
|
||
|
|
t.Logf("signature input header: %s\n", sigInputHeader)
|
||
|
|
|
||
|
|
req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(reqtxt)))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
req.Header.Set("signature", sigHeader)
|
||
|
|
req.Header.Set("signature-input", sigInputHeader)
|
||
|
|
|
||
|
|
sigSFV, err := parseSignaturesFromRequest(req.Header)
|
||
|
|
if err != nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
for _, label := range sigSFV.Sigs.Names() {
|
||
|
|
_, err = unmarshalSignature(sigSFV, label)
|
||
|
|
if err != nil {
|
||
|
|
if _, ok := err.(*SignatureError); ok {
|
||
|
|
// Handled error
|
||
|
|
return
|
||
|
|
}
|
||
|
|
// Unhandled error
|
||
|
|
t.Error(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|