-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathverify.go
More file actions
147 lines (128 loc) · 3.96 KB
/
verify.go
File metadata and controls
147 lines (128 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package httpsignature
import (
"bytes"
"fmt"
"io"
"net/http"
"github.com/cordialsys/offchain/pkg/httpsignature/verifier"
"github.com/gofiber/fiber/v2"
)
type VerifyArgs struct {
Body []byte
Method string
Path string
Query string
Signature string
SignatureInput string
ContentDigest string
Headers http.Header
}
func VerifyRaw(args VerifyArgs, verifier verifier.VerifierI, requiredHeaders ...string) (signatureInput *SigParams, err error) {
contentDigest, err := ParseContentDigest(args.ContentDigest)
if err != nil {
return nil, err
}
signature, err := ParseSignature(args.Signature)
if err != nil {
return nil, err
}
signatureInput, err = ParseSigParams(args.SignatureInput)
if err != nil {
return nil, err
}
hasPath := false
hasMethod := false
hasQuery := false
for _, component := range signatureInput.Components {
switch component {
case "@path":
hasPath = true
case "@method":
hasMethod = true
case "@query":
hasQuery = true
}
}
if !hasPath {
return nil, fmt.Errorf("missing path in signature input")
}
if !hasMethod {
return nil, fmt.Errorf("missing method in signature input")
}
if !hasQuery {
return nil, fmt.Errorf("missing query in signature input")
}
for _, header := range requiredHeaders {
hasHeader := false
for _, component := range signatureInput.Components {
if component == header {
hasHeader = true
break
}
}
if !hasHeader {
return nil, fmt.Errorf("missing required header in signature input: %s", header)
}
}
recalculatedContentDigest := NewContentDigest(args.Body)
if !bytes.Equal(recalculatedContentDigest.Digest, contentDigest.Digest) {
return nil, fmt.Errorf("content-digest mismatch")
}
sigBase := SigbaseFrom(signatureInput, args.Method, args.Path, args.Query, args.Headers, contentDigest)
message, err := sigBase.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize signature base: %w", err)
}
ok := verifier.Verify([]byte(message), signature.Signature)
if !ok {
return nil, fmt.Errorf("signature invalid")
}
return signatureInput, nil
}
func Verify(req *http.Request, verifier verifier.VerifierI, requiredHeaders ...string) (signatureInput *SigParams, err error) {
// var bodyBytes []byte
var verifyArgs VerifyArgs
if req.Body != nil {
verifyArgs.Body, _ = io.ReadAll(req.Body)
req.Body = io.NopCloser(bytes.NewBuffer(verifyArgs.Body))
}
if req.Header.Get(HeaderContentDigest) == "" {
return nil, fmt.Errorf("missing content-digest header")
}
if req.Header.Get(HeaderSignature) == "" {
return nil, fmt.Errorf("missing signature header")
}
if req.Header.Get(HeaderSignatureInput) == "" {
return nil, fmt.Errorf("missing signature-input header")
}
verifyArgs.Signature = req.Header.Get(HeaderSignature)
verifyArgs.SignatureInput = req.Header.Get(HeaderSignatureInput)
verifyArgs.ContentDigest = req.Header.Get(HeaderContentDigest)
verifyArgs.Method = req.Method
verifyArgs.Path = req.URL.Path
verifyArgs.Query = req.URL.RawQuery
verifyArgs.Headers = req.Header
return VerifyRaw(verifyArgs, verifier, requiredHeaders...)
}
func VerifyFiber(c *fiber.Ctx, verifier verifier.VerifierI, requiredHeaders ...string) (signatureInput *SigParams, err error) {
// var bodyBytes []byte
var verifyArgs VerifyArgs
verifyArgs.Body = c.Body()
if c.Get(HeaderContentDigest) == "" {
return nil, fmt.Errorf("missing content-digest header")
}
if c.Get(HeaderSignature) == "" {
return nil, fmt.Errorf("missing signature header")
}
if c.Get(HeaderSignatureInput) == "" {
return nil, fmt.Errorf("missing signature-input header")
}
verifyArgs.Signature = c.Get(HeaderSignature)
verifyArgs.SignatureInput = c.Get(HeaderSignatureInput)
verifyArgs.ContentDigest = c.Get(HeaderContentDigest)
verifyArgs.Method = c.Method()
verifyArgs.Path = c.Path()
verifyArgs.Query = string(c.Request().URI().QueryString())
verifyArgs.Headers = c.GetReqHeaders()
return VerifyRaw(verifyArgs, verifier, requiredHeaders...)
}