-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsignature.go
174 lines (144 loc) · 4.71 KB
/
signature.go
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package ocmf_go
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
)
type SignatureMimeType string
const (
SignatureMimeTypeDer = SignatureMimeType("application/x-der")
)
type SignatureEncoding string
const (
SignatureEncodingBase64 = SignatureEncoding("base64")
SignatureEncodingHex = SignatureEncoding("hex")
)
func isValidSignatureEncoding(encoding SignatureEncoding) bool {
switch encoding {
case SignatureEncodingBase64, SignatureEncodingHex:
return true
default:
return false
}
}
type SignatureAlgorithm string
const (
SignatureAlgorithmECDSAsecp192k1SHA256 = SignatureAlgorithm("ECDSA-secp192k1-SHA256")
SignatureAlgorithmECDSAsecp256k1SHA256 = SignatureAlgorithm("ECDSA-secp256k1-SHA256")
SignatureAlgorithmECDSAsecp384r1SHA256 = SignatureAlgorithm("ECDSA-secp384r1-SHA256")
SignatureAlgorithmECDSAbrainpool256r11SHA256 = SignatureAlgorithm("ECDSA-brainpool256r1-SHA256")
SignatureAlgorithmECDSAsecp256r1SHA256 = SignatureAlgorithm("ECDSA-secp256r1-SHA256")
SignatureAlgorithmECDSAsecp192r1SHA256 = SignatureAlgorithm("ECDSA-secp192r1-SHA256")
)
func isValidSignatureAlgorithm(algorithm SignatureAlgorithm) bool {
switch algorithm {
case SignatureAlgorithmECDSAsecp192k1SHA256,
SignatureAlgorithmECDSAsecp256k1SHA256,
SignatureAlgorithmECDSAsecp384r1SHA256,
SignatureAlgorithmECDSAbrainpool256r11SHA256,
SignatureAlgorithmECDSAsecp256r1SHA256,
SignatureAlgorithmECDSAsecp192r1SHA256:
return true
default:
return false
}
}
type Signature struct {
Algorithm SignatureAlgorithm `json:"SA" validate:"required,signatureAlgorithm"`
Encoding SignatureEncoding `json:"SE,omitempty" validate:"required,signatureEncoding"`
MimeType SignatureMimeType `json:"SM,omitempty" validate:"required,oneof=application/x-der"`
Data string `json:"SD" validate:"required"`
}
func NewDefaultSignature() *Signature {
return &Signature{
Algorithm: SignatureAlgorithmECDSAsecp256r1SHA256,
Encoding: SignatureEncodingHex,
MimeType: SignatureMimeTypeDer,
}
}
func (s *Signature) Validate() error {
return signatureValidator.Struct(s)
}
func (s *Signature) Sign(payload PayloadSection, privateKey *ecdsa.PrivateKey) error {
if privateKey == nil {
return errors.New("private key is required")
}
// Marshal payload
payloadBytes, err := json.Marshal(payload)
if err != nil {
return errors.Wrap(err, "failed to marshal payload")
}
switch s.Algorithm {
case SignatureAlgorithmECDSAsecp192k1SHA256:
case SignatureAlgorithmECDSAsecp256k1SHA256:
case SignatureAlgorithmECDSAsecp384r1SHA256:
case SignatureAlgorithmECDSAbrainpool256r11SHA256:
case SignatureAlgorithmECDSAsecp256r1SHA256:
default:
return fmt.Errorf("unsupported signature algorithm: %s", s.Algorithm)
}
// Hash data
messageHash := sha256.Sum256(payloadBytes)
// Sign data
sign, err := ecdsa.SignASN1(rand.Reader, privateKey, messageHash[:])
if err != nil {
return errors.Wrap(err, "failed to sign data")
}
var signedData string
// Encode signed data
switch s.Encoding {
case SignatureEncodingBase64:
signedData = base64.StdEncoding.EncodeToString(sign)
case SignatureEncodingHex:
signedData = hex.EncodeToString(sign)
default:
return fmt.Errorf("unsupported signature encoding: %s", s.Encoding)
}
s.Data = signedData
return nil
}
func (s *Signature) Verify(payload PayloadSection, publicKey *ecdsa.PublicKey) (bool, error) {
var decoded []byte
if publicKey == nil {
return false, errors.New("public key is required")
}
// Decode the signature
switch s.Encoding {
case SignatureEncodingBase64:
decodedString, err := base64.StdEncoding.DecodeString(s.Data)
if err != nil {
return false, errors.Wrap(err, "failed to decode base64 data")
}
decoded = decodedString
case SignatureEncodingHex:
decodedString, err := hex.DecodeString(s.Data)
if err != nil {
return false, errors.Wrap(err, "failed to decode hex data")
}
decoded = decodedString
default:
return false, fmt.Errorf("unsupported signature encoding: %s", s.Encoding)
}
switch s.Algorithm {
case SignatureAlgorithmECDSAsecp192k1SHA256:
case SignatureAlgorithmECDSAsecp256k1SHA256:
case SignatureAlgorithmECDSAsecp384r1SHA256:
case SignatureAlgorithmECDSAbrainpool256r11SHA256:
case SignatureAlgorithmECDSAsecp256r1SHA256:
default:
return false, fmt.Errorf("unsupported signature algorithm: %s", s.Algorithm)
}
payloadBytes, err := json.Marshal(payload)
if err != nil {
return false, errors.Wrap(err, "failed to marshal payload")
}
// Hash the payload to compare with the signature
messageHash := sha256.Sum256(payloadBytes)
// Verify signature
return ecdsa.VerifyASN1(publicKey, messageHash[:], decoded), nil
}