Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/protocols/http/signer/aws-sign.go
2072 views
1
package signer
2
3
import (
4
"context"
5
"crypto/sha256"
6
"encoding/hex"
7
"errors"
8
"io"
9
"net/http"
10
"time"
11
12
"github.com/aws/aws-sdk-go-v2/aws"
13
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
14
awsconfig "github.com/aws/aws-sdk-go-v2/config"
15
"github.com/aws/aws-sdk-go-v2/credentials"
16
"github.com/projectdiscovery/gologger"
17
"github.com/projectdiscovery/utils/errkit"
18
)
19
20
const defaultEmptyPayloadHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
21
22
// AWSOptions
23
type AWSOptions struct {
24
AwsID string
25
AwsSecretToken string
26
Service string
27
Region string
28
}
29
30
// Validate Signature Arguments
31
func (a *AWSOptions) Validate() error {
32
if a.Service == "" {
33
return errors.New("aws service cannot be empty")
34
}
35
if a.Region == "" {
36
return errors.New("aws region cannot be empty")
37
}
38
39
return nil
40
}
41
42
// AWS v4 signer
43
type AWSSigner struct {
44
creds *aws.Credentials
45
signer *v4.Signer
46
options *AWSOptions
47
}
48
49
// SignHTTP
50
func (a *AWSSigner) SignHTTP(ctx context.Context, request *http.Request) error {
51
if region, ok := ctx.Value(SignerArg("region")).(string); ok && region != "" {
52
a.options.Region = region
53
}
54
if service, ok := ctx.Value(SignerArg("service")).(string); ok && service != "" {
55
a.options.Service = service
56
}
57
if err := a.options.Validate(); err != nil {
58
return err
59
}
60
// contentHash is sha256 hash of response body
61
contentHash := a.getPayloadHash(request)
62
if err := a.signer.SignHTTP(ctx, *a.creds, request, contentHash, a.options.Service, a.options.Region, time.Now()); err != nil {
63
return errkit.Wrap(err, "failed to sign http request using aws v4 signer")
64
}
65
// add x-amz-content-sha256 header to request
66
request.Header.Set("x-amz-content-sha256", contentHash)
67
return nil
68
}
69
70
// getPayloadHash returns hex encoded SHA-256 of request body
71
func (a *AWSSigner) getPayloadHash(request *http.Request) string {
72
if request.Body == nil {
73
// Default Hash of Empty Payload
74
return defaultEmptyPayloadHash
75
}
76
77
// no need to close request body since it is a reusablereadercloser
78
bin, err := io.ReadAll(request.Body)
79
if err != nil {
80
gologger.Error().Msgf("aws signer: failed to read request body: %s", err)
81
}
82
sha256Hash := sha256.Sum256(bin)
83
return hex.EncodeToString(sha256Hash[:])
84
}
85
86
// NewAwsSigner
87
func NewAwsSigner(opts *AWSOptions) (*AWSSigner, error) {
88
credcache := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(opts.AwsID, opts.AwsSecretToken, ""))
89
awscred, err := credcache.Retrieve(context.TODO())
90
if err != nil {
91
return nil, err
92
}
93
return &AWSSigner{
94
creds: &awscred,
95
options: opts,
96
signer: v4.NewSigner(),
97
}, nil
98
}
99
100
// NewAwsSignerFromConfig
101
func NewAwsSignerFromConfig(opts *AWSOptions) (*AWSSigner, error) {
102
/*
103
NewAwsSignerFromConfig fetches credentials from both
104
1. Environment Variables (old & new)
105
2. Shared Credentials ($HOME/.aws)
106
*/
107
cfg, err := awsconfig.LoadDefaultConfig(context.TODO())
108
if err != nil {
109
return nil, err
110
}
111
credcache := aws.NewCredentialsCache(cfg.Credentials)
112
awscred, err := credcache.Retrieve(context.TODO())
113
if err != nil {
114
return nil, err
115
}
116
return &AWSSigner{
117
creds: &awscred,
118
options: opts,
119
signer: v4.NewSigner(func(signer *v4.SignerOptions) {
120
// signer.DisableURIPathEscaping = true
121
}),
122
}, nil
123
}
124
125
var AwsSkipList = map[string]interface{}{
126
"region": struct{}{},
127
}
128
129
var AwsDefaultVars = map[string]interface{}{
130
"region": "us-east-2",
131
"service": "sts",
132
}
133
134
var AwsInternalOnlyVars = map[string]interface{}{
135
"aws-id": struct{}{},
136
"aws-secret": struct{}{},
137
}
138
139