@@ -11,7 +11,6 @@ import (
11
11
"errors"
12
12
"fmt"
13
13
"os"
14
- "regexp"
15
14
"strings"
16
15
"sync"
17
16
@@ -21,18 +20,21 @@ import (
21
20
)
22
21
23
22
var (
24
- ReDigest = regexp .MustCompile (`(?m)^#\sdigest:\s.+$` )
25
23
ErrUnknownAlgorithm = errors .New ("unknown algorithm" )
26
24
SignaturePattern = "# digest: "
27
25
SignatureFmt = SignaturePattern + "%x" + ":%v" // `#digest: <signature>:<fragment>`
28
26
)
29
27
30
- func RemoveSignatureFromData (data []byte ) []byte {
31
- return bytes .Trim (ReDigest .ReplaceAll (data , []byte ("" )), "\n " )
32
- }
33
-
34
- func GetSignatureFromData (data []byte ) []byte {
35
- return ReDigest .Find (data )
28
+ // ExtractSignatureAndContent extracts the signature (if present) and returns the content without the signature
29
+ func ExtractSignatureAndContent (data []byte ) (signature , content []byte ) {
30
+ dataStr := string (data )
31
+ if idx := strings .LastIndex (dataStr , SignaturePattern ); idx != - 1 {
32
+ signature = []byte (strings .TrimSpace (dataStr [idx :]))
33
+ content = []byte (strings .TrimSpace (dataStr [:idx ]))
34
+ } else {
35
+ content = data
36
+ }
37
+ return
36
38
}
37
39
38
40
// SignableTemplate is a template that can be signed
@@ -69,26 +71,29 @@ func (t *TemplateSigner) GetUserFragment() string {
69
71
70
72
// Sign signs the given template with the template signer and returns the signature
71
73
func (t * TemplateSigner ) Sign (data []byte , tmpl SignableTemplate ) (string , error ) {
74
+ existingSignature , content := ExtractSignatureAndContent (data )
75
+
72
76
// while re-signing template check if it has a code protocol
73
77
// if it does then verify that it is signed by current signer
74
78
// if not then return error
75
79
if tmpl .HasCodeProtocol () {
76
- sig := GetSignatureFromData (data )
77
- arr := strings .SplitN (string (sig ), ":" , 3 )
78
- if len (arr ) == 2 {
79
- // signature has no fragment
80
- return "" , errorutil .NewWithTag ("signer" , "re-signing code templates are not allowed for security reasons." )
81
- }
82
- if len (arr ) == 3 {
83
- // signature has fragment verify if it is equal to current fragment
84
- fragment := t .GetUserFragment ()
85
- if fragment != arr [2 ] {
80
+ if len (existingSignature ) > 0 {
81
+ arr := strings .SplitN (string (existingSignature ), ":" , 3 )
82
+ if len (arr ) == 2 {
83
+ // signature has no fragment
86
84
return "" , errorutil .NewWithTag ("signer" , "re-signing code templates are not allowed for security reasons." )
87
85
}
86
+ if len (arr ) == 3 {
87
+ // signature has fragment verify if it is equal to current fragment
88
+ fragment := t .GetUserFragment ()
89
+ if fragment != arr [2 ] {
90
+ return "" , errorutil .NewWithTag ("signer" , "re-signing code templates are not allowed for security reasons." )
91
+ }
92
+ }
88
93
}
89
94
}
90
95
91
- buff := bytes .NewBuffer (RemoveSignatureFromData ( data ) )
96
+ buff := bytes .NewBuffer (content )
92
97
// if file has any imports process them
93
98
for _ , file := range tmpl .GetFileImports () {
94
99
bin , err := os .ReadFile (file )
@@ -123,20 +128,24 @@ func (t *TemplateSigner) sign(data []byte) (string, error) {
123
128
124
129
// Verify verifies the given template with the template signer
125
130
func (t * TemplateSigner ) Verify (data []byte , tmpl SignableTemplate ) (bool , error ) {
126
- digestData := ReDigest .Find (data )
127
- if len (digestData ) == 0 {
128
- return false , errors .New ("digest not found" )
131
+ signature , content := ExtractSignatureAndContent (data )
132
+ if len (signature ) == 0 {
133
+ return false , errors .New ("no signature found" )
134
+ }
135
+
136
+ if ! bytes .HasPrefix (signature , []byte (SignaturePattern )) {
137
+ return false , errors .New ("signature must be at the end of the template" )
129
138
}
130
139
131
- digestData = bytes .TrimSpace (bytes .TrimPrefix (digestData , []byte (SignaturePattern )))
140
+ digestData : = bytes .TrimSpace (bytes .TrimPrefix (signature , []byte (SignaturePattern )))
132
141
// remove fragment from digest as it is used for re-signing purposes only
133
142
digestString := strings .TrimSuffix (string (digestData ), ":" + t .GetUserFragment ())
134
143
digest , err := hex .DecodeString (digestString )
135
144
if err != nil {
136
145
return false , err
137
146
}
138
147
139
- buff := bytes .NewBuffer (RemoveSignatureFromData ( data ) )
148
+ buff := bytes .NewBuffer (content )
140
149
// if file has any imports process them
141
150
for _ , file := range tmpl .GetFileImports () {
142
151
bin , err := os .ReadFile (file )
0 commit comments