Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/templates/template_sign.go
2070 views
1
package templates
2
3
import (
4
"bytes"
5
"os"
6
"path/filepath"
7
"strings"
8
"sync"
9
10
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
11
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
12
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
13
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
14
"github.com/projectdiscovery/nuclei/v3/pkg/templates/extensions"
15
"github.com/projectdiscovery/nuclei/v3/pkg/templates/signer"
16
"github.com/projectdiscovery/nuclei/v3/pkg/types"
17
"github.com/projectdiscovery/utils/errkit"
18
)
19
20
// Due to file references in sensitive fields of template
21
// ex: javascript code in flow or bash command in code.Source etc
22
// signing / verifying template is only possible after loading the template
23
// with these fields resolved
24
25
var (
26
defaultOpts *types.Options = types.DefaultOptions()
27
initOnce = sync.OnceFunc(func() {
28
_ = protocolstate.Init(defaultOpts)
29
_ = protocolinit.Init(defaultOpts)
30
})
31
ErrNotATemplate = errkit.New("given filePath is not a template", "tag", "signer")
32
)
33
34
// UseOptionsForSigner sets the options to use for signing templates
35
// instead of default options
36
func UseOptionsForSigner(opts *types.Options) {
37
defaultOpts = opts
38
}
39
40
// New Signer/Verification logic requires it to load content of file references
41
// and this is done respecting sandbox restrictions to avoid any security issues
42
// AllowLocalFileAccess is a function that allows local file access by disabling sandbox restrictions
43
// and **MUST** be called before signing / verifying any templates for intialization
44
func TemplateSignerLFA() {
45
defaultOpts.AllowLocalFileAccess = true
46
}
47
48
// VerifyTemplateSignature verifies the signature of the template
49
// using default signers
50
func VerifyTemplateSignature(templatePath string) (bool, error) {
51
template, _, err := getTemplate(templatePath)
52
if err != nil {
53
return false, err
54
}
55
return template.Verified, nil
56
}
57
58
// SignTemplate signs the tempalate using custom signer
59
func SignTemplate(templateSigner *signer.TemplateSigner, templatePath string) error {
60
// sign templates requires code files such as javsacript bash command to be included
61
// in template hence we first load template and append such resolved file references to content
62
initOnce()
63
64
// signing is only supported on yaml nuclei templates
65
if !strings.HasSuffix(templatePath, extensions.YAML) {
66
return ErrNotATemplate
67
}
68
69
template, bin, err := getTemplate(templatePath)
70
if err != nil {
71
return errkit.Wrap(err, "failed to get template from disk")
72
}
73
if len(template.Workflows) > 0 {
74
// signing workflows is not supported at least yet
75
return ErrNotATemplate
76
}
77
if !template.Verified {
78
_, content := signer.ExtractSignatureAndContent(bin)
79
signatureData, err := templateSigner.Sign(bin, template)
80
if err != nil {
81
return err
82
}
83
buff := bytes.NewBuffer(content)
84
buff.WriteString("\n" + signatureData)
85
return os.WriteFile(templatePath, buff.Bytes(), 0644)
86
}
87
return nil
88
}
89
90
func getTemplate(templatePath string) (*Template, []byte, error) {
91
catalog := disk.NewCatalog(filepath.Dir(templatePath))
92
executerOpts := &protocols.ExecutorOptions{
93
Catalog: catalog,
94
Options: defaultOpts,
95
TemplatePath: templatePath,
96
}
97
bin, err := os.ReadFile(templatePath)
98
if err != nil {
99
return nil, bin, err
100
}
101
template, err := ParseTemplateFromReader(bytes.NewReader(bin), nil, executerOpts)
102
if err != nil {
103
return nil, bin, errkit.Wrap(err, "failed to parse template")
104
}
105
return template, bin, nil
106
}
107
108