-
Notifications
You must be signed in to change notification settings - Fork 1
/
licensefile-ecdsa.go
156 lines (135 loc) · 4.23 KB
/
licensefile-ecdsa.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
package licensefile
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"fmt"
"golang.org/x/exp/slices"
)
// GenerateKeyPairECDSA creates and returns a new ECDSA private and public key. We
// don't just accept an elliptic.Curve as an input because this overall code base does
// not support every curve type.
func GenerateKeyPairECDSA(k KeyPairAlgoType) (private, public []byte, err error) {
//Make sure an ECDSA key pair type was provided.
if !slices.Contains(keyPairECDSATypes, k) {
err = fmt.Errorf("invalid ECDSA key pair type, should be one of '%s', got '%s'", keyPairRSATypes, k)
return
}
//Set correct bit size based on algo type.
var curve elliptic.Curve
switch k {
case KeyPairAlgoECDSAP256:
curve = elliptic.P256()
case KeyPairAlgoECDSAP384:
curve = elliptic.P384()
case KeyPairAlgoECDSAP521:
curve = elliptic.P521()
}
//Generate key pair.
pk, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return
}
//Encode the private key.
x509PrivateKey, err := x509.MarshalECPrivateKey(pk)
if err != nil {
return
}
pemBlockPrivateKey := &pem.Block{
Type: "PRIVATE KEY",
Bytes: x509PrivateKey,
}
private = pem.EncodeToMemory(pemBlockPrivateKey)
//Encode the public key.
x509PublicKey, err := x509.MarshalPKIXPublicKey(&pk.PublicKey)
if err != nil {
return
}
pemBlockPublicKey := &pem.Block{
Type: "PUBLIC KEY",
Bytes: x509PublicKey,
}
public = pem.EncodeToMemory(pemBlockPublicKey)
return
}
// SignECDSA signs File with the provided ECDSA private key. The generated signature
// will be set in the Signature field of File. You would need to call File.Marshal()
// after this func completes to return/serve the license key file. The private key
// must be decrypted, if needed, prior to being provided.
func (f *File) SignECDSA(privateKey []byte, keyPairAlgo KeyPairAlgoType) (err error) {
//Make sure a valid ECDSA algo type was provided.
if !slices.Contains(keyPairECDSATypes, keyPairAlgo) {
err = fmt.Errorf("invalid key pair algorithm, should be one of '%s', got '%s'", keyPairECDSATypes, keyPairAlgo)
return
}
//Hash.
h, err := f.hash(keyPairAlgo)
if err != nil {
return
}
//Sign the hash.
//Decode the private key.
pemBlock, _ := pem.Decode(privateKey)
x509Key, err := x509.ParseECPrivateKey(pemBlock.Bytes)
if err != nil {
return
}
//Generate signature.
sig, err := ecdsa.SignASN1(rand.Reader, x509Key, h[:])
if err != nil {
return
}
//Encode the signature and set to the Signature field.
f.encodeSignature(sig)
return
}
// VerifySignatureECDSA checks if a File's signature is valid by checking it against
// the ECDSA public key.
//
// This DOES NOT check if a File is expired. You should call Expired() on the File
// after calling this func.
//
// This uses a copy of the File since need to remove the Signature field prior to
// hashing and verification but we don't want to modify the original File so it can
// be used as it was parsed/unmarshalled.
func (f File) VerifySignatureECDSA(publicKey []byte, keyPairAlgo KeyPairAlgoType) (err error) {
//Make sure a valid ECDSA algo type was provided.
if !slices.Contains(keyPairECDSATypes, keyPairAlgo) {
err = fmt.Errorf("invalid key pair algorithm, should be one of '%s', got '%s'", keyPairECDSATypes, keyPairAlgo)
return
}
//Get the decoded signature and remove the signature from the File.
decodedSig, err := f.decodeSignature()
if err != nil {
return
}
f.Signature = ""
//Hash.
h, err := f.hash(keyPairAlgo)
if err != nil {
return
}
//Decode the public key.
pemBlock, _ := pem.Decode(publicKey)
x509Key, err := x509.ParsePKIXPublicKey(pemBlock.Bytes)
if err != nil {
return
}
//Verify signature.
//Note type conversion for x509Key. ParsePKIXPublicKey returns an interface.
valid := ecdsa.VerifyASN1(x509Key.(*ecdsa.PublicKey), h[:], decodedSig)
if !valid {
err = ErrBadSignature
}
return
}
// VerifyECDSA calls VerifySignatureECDSA().
//
// Deprecated: This func is here just for legacy situations since the old
// VerifyECDSA() func was renamed to VerifySignatureECDSA() for better clarity.
// Use VerifySignatureECDSA() instead.
func (f *File) VerifyECDSA(publicKey []byte, keyPairAlgo KeyPairAlgoType) (err error) {
return f.VerifySignatureECDSA(publicKey, keyPairAlgo)
}