-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcose.go
280 lines (244 loc) · 8.06 KB
/
cose.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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
package warp
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"encoding/asn1"
"encoding/binary"
"math/big"
"github.com/fxamacker/cbor/v2"
)
//COSEKey represents a key decoded from COSE format.
type COSEKey struct {
Kty int `cbor:"1,keyasint,omitempty"`
Kid []byte `cbor:"2,keyasint,omitempty"`
Alg int `cbor:"3,keyasint,omitempty"`
KeyOpts int `cbor:"4,keyasint,omitempty"`
IV []byte `cbor:"5,keyasint,omitempty"`
CrvOrNOrK cbor.RawMessage `cbor:"-1,keyasint,omitempty"` // K for symmetric keys, Crv for elliptic curve keys, N for RSA modulus
XOrE cbor.RawMessage `cbor:"-2,keyasint,omitempty"` // X for curve x-coordinate, E for RSA public exponent
Y cbor.RawMessage `cbor:"-3,keyasint,omitempty"` // Y for curve y-cooridate
D []byte `cbor:"-4,keyasint,omitempty"`
}
//COSEAlgorithmIdentifier is a number identifying a cryptographic algorithm
type COSEAlgorithmIdentifier int
//enum values for COSEAlgorithmIdentifier type
const (
AlgorithmRS1 COSEAlgorithmIdentifier = -65535
AlgorithmRS512 COSEAlgorithmIdentifier = -259
AlgorithmRS384 COSEAlgorithmIdentifier = -258
AlgorithmRS256 COSEAlgorithmIdentifier = -257
AlgorithmPS512 COSEAlgorithmIdentifier = -39
AlgorithmPS384 COSEAlgorithmIdentifier = -38
AlgorithmPS256 COSEAlgorithmIdentifier = -37
AlgorithmES512 COSEAlgorithmIdentifier = -36
AlgorithmES384 COSEAlgorithmIdentifier = -35
AlgorithmEdDSA COSEAlgorithmIdentifier = -8
AlgorithmES256 COSEAlgorithmIdentifier = -7
)
//COSEEllipticCurve is a number identifying an elliptic curve
type COSEEllipticCurve int
//enum values for COSEEllipticCurve type
const (
CurveP256 COSEEllipticCurve = 1
CurveP384 COSEEllipticCurve = 2
CurveP521 COSEEllipticCurve = 3
)
//COSEKeyType is a number identifying a key type
type COSEKeyType int
//enum values for COSEKeyType type
const (
KeyTypeOKP COSEKeyType = 1
KeyTypeEC2 COSEKeyType = 2
KeyTypeRSA COSEKeyType = 3
)
//VerifySignature verifies a signature using a provided COSEKey, message, and
//signature
func VerifySignature(rawKey cbor.RawMessage, message, sig []byte) error {
coseKey := COSEKey{}
err := cbor.Unmarshal(rawKey, &coseKey)
if err != nil {
return ErrVerifySignature.Wrap(ErrDecodeCOSEKey.Wrap(err))
}
publicKey, err := DecodePublicKey(&coseKey)
if err != nil {
return ErrVerifySignature.Wrap(err)
}
switch COSEAlgorithmIdentifier(coseKey.Alg) {
case AlgorithmES256,
AlgorithmES384,
AlgorithmES512:
pk, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
return ErrVerifySignature.Wrap(NewError("Invalid public key type for ECDSA algorithm"))
}
switch COSEAlgorithmIdentifier(coseKey.Alg) {
case AlgorithmES256:
return verifyECDSASignature(pk, crypto.SHA256, message, sig)
case AlgorithmES384:
return verifyECDSASignature(pk, crypto.SHA384, message, sig)
case AlgorithmES512:
return verifyECDSASignature(pk, crypto.SHA512, message, sig)
}
case AlgorithmRS1,
AlgorithmRS512,
AlgorithmRS384,
AlgorithmRS256,
AlgorithmPS512,
AlgorithmPS384,
AlgorithmPS256:
pk, ok := publicKey.(*rsa.PublicKey)
if !ok {
return ErrVerifySignature.Wrap(NewError("Invalid public key type for RSA algorithm"))
}
switch COSEAlgorithmIdentifier(coseKey.Alg) {
case AlgorithmRS1:
return verifyRSAPKCS1v15Signature(pk, crypto.SHA1, message, sig)
case AlgorithmRS256:
return verifyRSAPKCS1v15Signature(pk, crypto.SHA256, message, sig)
case AlgorithmRS384:
return verifyRSAPKCS1v15Signature(pk, crypto.SHA384, message, sig)
case AlgorithmRS512:
return verifyRSAPKCS1v15Signature(pk, crypto.SHA512, message, sig)
case AlgorithmPS256:
return verifyRSAPSSSignature(pk, crypto.SHA256, message, sig)
case AlgorithmPS384:
return verifyRSAPSSSignature(pk, crypto.SHA384, message, sig)
case AlgorithmPS512:
return verifyRSAPSSSignature(pk, crypto.SHA512, message, sig)
}
case AlgorithmEdDSA:
pk, ok := publicKey.(ed25519.PublicKey)
if !ok {
return ErrVerifySignature.Wrap(NewError("Invalid public key type for EdDSA algorithm"))
}
if ed25519.Verify(pk, message, sig) {
return nil
}
return ErrVerifySignature.Wrap(NewError("EdDSA signature verification failed"))
}
return ErrVerifySignature.Wrap(NewError("COSE algorithm ID %d not supported", coseKey.Alg))
}
//DecodePublicKey parses a crypto.PublicKey from a COSEKey
func DecodePublicKey(coseKey *COSEKey) (crypto.PublicKey, error) {
var publicKey crypto.PublicKey
switch COSEKeyType(coseKey.Kty) {
case KeyTypeOKP:
k, err := decodeEd25519PublicKey(coseKey)
if err != nil {
return nil, ErrDecodeCOSEKey.Wrap(err)
}
publicKey = k
case KeyTypeEC2:
k, err := decodeECDSAPublicKey(coseKey)
if err != nil {
return nil, ErrDecodeCOSEKey.Wrap(err)
}
publicKey = k
case KeyTypeRSA:
k, err := decodeRSAPublicKey(coseKey)
if err != nil {
return nil, ErrDecodeCOSEKey.Wrap(err)
}
publicKey = k
default:
return nil, ErrDecodeCOSEKey.Wrap(NewError("COSE key type %d not supported", coseKey.Kty))
}
return publicKey, nil
}
func decodeECDSAPublicKey(coseKey *COSEKey) (*ecdsa.PublicKey, error) {
var curve elliptic.Curve
var curveID int
if err := cbor.Unmarshal(coseKey.CrvOrNOrK, &curveID); err != nil {
return nil, NewError("Error decoding elliptic curve ID").Wrap(err)
}
switch COSEEllipticCurve(curveID) {
case CurveP256:
curve = elliptic.P256()
case CurveP384:
curve = elliptic.P384()
case CurveP521:
curve = elliptic.P521()
default:
return nil, NewError("COSE elliptic curve %d not supported", curveID)
}
var xBytes, yBytes []byte
if err := cbor.Unmarshal(coseKey.XOrE, &xBytes); err != nil {
return nil, NewError("Error decoding elliptic X parameter").Wrap(err)
}
if err := cbor.Unmarshal(coseKey.Y, &yBytes); err != nil {
return nil, NewError("Error decoding elliptic Y parameter").Wrap(err)
}
x, y := big.NewInt(0), big.NewInt(0)
x = x.SetBytes(xBytes)
y = y.SetBytes(yBytes)
return &ecdsa.PublicKey{
Curve: curve,
X: x,
Y: y,
}, nil
}
func verifyECDSASignature(pubKey *ecdsa.PublicKey, hash crypto.Hash, message, sig []byte) error {
type ECDSASignature struct {
R, S *big.Int
}
ecdsaSig := ECDSASignature{}
_, err := asn1.Unmarshal(sig, &ecdsaSig)
if err != nil {
return ErrVerifySignature.Wrap(NewError("Unable to parse ECDSA signature").Wrap(err))
}
hasher := hash.New()
hasher.Write(message)
if ecdsa.Verify(pubKey, hasher.Sum(nil), ecdsaSig.R, ecdsaSig.S) {
return nil
}
return ErrVerifySignature.Wrap(NewError("ECDSA signature verification failed"))
}
func decodeRSAPublicKey(coseKey *COSEKey) (*rsa.PublicKey, error) {
var nBytes, eBytes []byte
if err := cbor.Unmarshal(coseKey.CrvOrNOrK, &nBytes); err != nil {
return nil, NewError("Error unmarshaling RSA modulus").Wrap(err)
}
if err := cbor.Unmarshal(coseKey.XOrE, &eBytes); err != nil {
return nil, NewError("Error unmarshaling RSA exponent").Wrap(err)
}
n := big.NewInt(0)
var e int32
n = n.SetBytes(nBytes)
if err := binary.Read(bytes.NewBuffer(eBytes), binary.BigEndian, &e); err != nil {
return nil, NewError("Error decoding RSA exponent").Wrap(err)
}
return &rsa.PublicKey{
N: n,
E: int(e),
}, nil
}
func verifyRSAPKCS1v15Signature(pubKey *rsa.PublicKey, hash crypto.Hash, message, sig []byte) error {
hasher := hash.New()
hasher.Write(message)
err := rsa.VerifyPKCS1v15(pubKey, hash, hasher.Sum(nil), sig)
if err != nil {
return ErrVerifySignature.Wrap(NewError("RSA signature verification failed").Wrap(err))
}
return nil
}
func verifyRSAPSSSignature(pubKey *rsa.PublicKey, hash crypto.Hash, message, sig []byte) error {
hasher := hash.New()
hasher.Write(message)
err := rsa.VerifyPSS(pubKey, hash, hasher.Sum(nil), sig, nil)
if err != nil {
return ErrVerifySignature.Wrap(NewError("RSA signature verification failed").Wrap(err))
}
return nil
}
func decodeEd25519PublicKey(coseKey *COSEKey) (ed25519.PublicKey, error) {
var kBytes []byte
if err := cbor.Unmarshal(coseKey.XOrE, &kBytes); err != nil {
return nil, NewError("Error unmarshaling Ed25519 public key").Wrap(err)
}
k := ed25519.PublicKey(kBytes)
return k, nil
}