-
Notifications
You must be signed in to change notification settings - Fork 85
/
symmetric.go
366 lines (321 loc) · 10.6 KB
/
symmetric.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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
// Copyright 2024 Thales Group
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package crypto11
import (
"errors"
"github.com/miekg/pkcs11"
)
// SymmetricGenParams holds a consistent (key type, mechanism) key generation pair.
type SymmetricGenParams struct {
// Key type (CKK_...)
KeyType uint
// Key generation mechanism (CKM_..._KEY_GEN)
GenMech uint
}
// SymmetricCipher represents information about a symmetric cipher.
type SymmetricCipher struct {
// Possible key generation parameters
// (For HMAC this varies between PKCS#11 implementations.)
GenParams []SymmetricGenParams
// Block size in bytes
BlockSize int
// True if encryption supported
Encrypt bool
// True if MAC supported
MAC bool
// ECB mechanism (CKM_..._ECB)
ECBMech uint
// CBC mechanism (CKM_..._CBC)
CBCMech uint
// CBC mechanism with PKCS#7 padding (CKM_..._CBC)
CBCPKCSMech uint
// GCM mechanism (CKM_..._GCM)
GCMMech uint
}
// CipherAES describes the AES cipher. Use this with the
// GenerateSecretKey... functions.
var CipherAES = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_AES,
GenMech: pkcs11.CKM_AES_KEY_GEN,
},
},
BlockSize: 16,
Encrypt: true,
MAC: false,
ECBMech: pkcs11.CKM_AES_ECB,
CBCMech: pkcs11.CKM_AES_CBC,
CBCPKCSMech: pkcs11.CKM_AES_CBC_PAD,
GCMMech: pkcs11.CKM_AES_GCM,
}
// CipherDES3 describes the three-key triple-DES cipher. Use this with the
// GenerateSecretKey... functions.
var CipherDES3 = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_DES3,
GenMech: pkcs11.CKM_DES3_KEY_GEN,
},
},
BlockSize: 8,
Encrypt: true,
MAC: false,
ECBMech: pkcs11.CKM_DES3_ECB,
CBCMech: pkcs11.CKM_DES3_CBC,
CBCPKCSMech: pkcs11.CKM_DES3_CBC_PAD,
GCMMech: 0,
}
// CipherGeneric describes the CKK_GENERIC_SECRET key type. Use this with the
// GenerateSecretKey... functions.
//
// The spec promises that this mechanism can be used to perform HMAC
// operations, although implementations vary;
// CipherHMACSHA1 and so on may give better results.
var CipherGeneric = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_GENERIC_SECRET,
GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
},
},
BlockSize: 64,
Encrypt: false,
MAC: true,
ECBMech: 0,
CBCMech: 0,
GCMMech: 0,
}
// CipherHMACSHA1 describes the CKK_SHA_1_HMAC key type. Use this with the
// GenerateSecretKey... functions.
var CipherHMACSHA1 = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_SHA_1_HMAC,
GenMech: CKM_NC_SHA_1_HMAC_KEY_GEN,
},
{
KeyType: pkcs11.CKK_GENERIC_SECRET,
GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
},
},
BlockSize: 64,
Encrypt: false,
MAC: true,
ECBMech: 0,
CBCMech: 0,
GCMMech: 0,
}
// CipherHMACSHA224 describes the CKK_SHA224_HMAC key type. Use this with the
// GenerateSecretKey... functions.
var CipherHMACSHA224 = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_SHA224_HMAC,
GenMech: CKM_NC_SHA224_HMAC_KEY_GEN,
},
{
KeyType: pkcs11.CKK_GENERIC_SECRET,
GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
},
},
BlockSize: 64,
Encrypt: false,
MAC: true,
ECBMech: 0,
CBCMech: 0,
GCMMech: 0,
}
// CipherHMACSHA256 describes the CKK_SHA256_HMAC key type. Use this with the
// GenerateSecretKey... functions.
var CipherHMACSHA256 = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_SHA256_HMAC,
GenMech: CKM_NC_SHA256_HMAC_KEY_GEN,
},
{
KeyType: pkcs11.CKK_GENERIC_SECRET,
GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
},
},
BlockSize: 64,
Encrypt: false,
MAC: true,
ECBMech: 0,
CBCMech: 0,
GCMMech: 0,
}
// CipherHMACSHA384 describes the CKK_SHA384_HMAC key type. Use this with the
// GenerateSecretKey... functions.
var CipherHMACSHA384 = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_SHA384_HMAC,
GenMech: CKM_NC_SHA384_HMAC_KEY_GEN,
},
{
KeyType: pkcs11.CKK_GENERIC_SECRET,
GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
},
},
BlockSize: 64,
Encrypt: false,
MAC: true,
ECBMech: 0,
CBCMech: 0,
GCMMech: 0,
}
// CipherHMACSHA512 describes the CKK_SHA512_HMAC key type. Use this with the
// GenerateSecretKey... functions.
var CipherHMACSHA512 = &SymmetricCipher{
GenParams: []SymmetricGenParams{
{
KeyType: pkcs11.CKK_SHA512_HMAC,
GenMech: CKM_NC_SHA512_HMAC_KEY_GEN,
},
{
KeyType: pkcs11.CKK_GENERIC_SECRET,
GenMech: pkcs11.CKM_GENERIC_SECRET_KEY_GEN,
},
},
BlockSize: 128,
Encrypt: false,
MAC: true,
ECBMech: 0,
CBCMech: 0,
GCMMech: 0,
}
// Ciphers is a map of PKCS#11 key types (CKK_...) to symmetric cipher information.
var Ciphers = map[int]*SymmetricCipher{
pkcs11.CKK_AES: CipherAES,
pkcs11.CKK_DES3: CipherDES3,
pkcs11.CKK_GENERIC_SECRET: CipherGeneric,
pkcs11.CKK_SHA_1_HMAC: CipherHMACSHA1,
pkcs11.CKK_SHA224_HMAC: CipherHMACSHA224,
pkcs11.CKK_SHA256_HMAC: CipherHMACSHA256,
pkcs11.CKK_SHA384_HMAC: CipherHMACSHA384,
pkcs11.CKK_SHA512_HMAC: CipherHMACSHA512,
}
// SecretKey contains a reference to a loaded PKCS#11 symmetric key object.
//
// A *SecretKey implements the cipher.Block interface, allowing it be used
// as the argument to cipher.NewCBCEncrypter and similar methods.
// For bulk operation this is very inefficient;
// using NewCBCEncrypterCloser, NewCBCEncrypter or NewCBC from this package is
// much faster.
type SecretKey struct {
pkcs11Object
// Symmetric cipher information
Cipher *SymmetricCipher
}
// GenerateSecretKey creates an secret key of given length and type. The id parameter is used to
// set CKA_ID and must be non-nil.
func (c *Context) GenerateSecretKey(id []byte, bits int, cipher *SymmetricCipher) (*SecretKey, error) {
if c.closed.Get() {
return nil, errClosed
}
template, err := NewAttributeSetWithID(id)
if err != nil {
return nil, err
}
return c.GenerateSecretKeyWithAttributes(template, bits, cipher)
}
// GenerateSecretKey creates an secret key of given length and type. The id and label parameters are used to
// set CKA_ID and CKA_LABEL respectively and must be non-nil.
func (c *Context) GenerateSecretKeyWithLabel(id, label []byte, bits int, cipher *SymmetricCipher) (*SecretKey, error) {
if c.closed.Get() {
return nil, errClosed
}
template, err := NewAttributeSetWithIDAndLabel(id, label)
if err != nil {
return nil, err
}
return c.GenerateSecretKeyWithAttributes(template, bits, cipher)
}
// GenerateSecretKeyWithAttributes creates an secret key of given length and type. After this function returns, template
// will contain the attributes applied to the key. If required attributes are missing, they will be set to a default
// value.
func (c *Context) GenerateSecretKeyWithAttributes(template AttributeSet, bits int, cipher *SymmetricCipher) (k *SecretKey, err error) {
if c.closed.Get() {
return nil, errClosed
}
err = c.withSession(func(session *pkcs11Session) error {
// CKK_*_HMAC exists but there is no specific corresponding CKM_*_KEY_GEN
// mechanism. Therefore we attempt both CKM_GENERIC_SECRET_KEY_GEN and
// vendor-specific mechanisms.
template.AddIfNotPresent([]*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_SECRET_KEY),
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
pkcs11.NewAttribute(pkcs11.CKA_SIGN, cipher.MAC),
pkcs11.NewAttribute(pkcs11.CKA_VERIFY, cipher.MAC),
pkcs11.NewAttribute(pkcs11.CKA_ENCRYPT, cipher.Encrypt), // Not supported on CloudHSM
pkcs11.NewAttribute(pkcs11.CKA_DECRYPT, cipher.Encrypt), // Not supported on CloudHSM
pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true),
pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false),
})
if bits > 0 {
_ = template.Set(pkcs11.CKA_VALUE_LEN, bits/8) // safe for an int
}
for n, genMech := range cipher.GenParams {
_ = template.Set(CkaKeyType, genMech.KeyType)
mech := []*pkcs11.Mechanism{pkcs11.NewMechanism(genMech.GenMech, nil)}
privHandle, err := session.ctx.GenerateKey(session.handle, mech, template.ToSlice())
if err == nil {
k = &SecretKey{pkcs11Object{privHandle, c}, cipher}
return nil
}
// As a special case, AWS CloudHSM does not accept CKA_ENCRYPT and CKA_DECRYPT on a
// Generic Secret key. If we are in that special case, try again without those attributes.
if e, ok := err.(pkcs11.Error); ok && e == pkcs11.CKR_ARGUMENTS_BAD && genMech.GenMech == pkcs11.CKM_GENERIC_SECRET_KEY_GEN {
adjustedTemplate := template.Copy()
adjustedTemplate.Unset(CkaEncrypt)
adjustedTemplate.Unset(CkaDecrypt)
privHandle, err = session.ctx.GenerateKey(session.handle, mech, adjustedTemplate.ToSlice())
if err == nil {
// Store the actual attributes
template.cloneFrom(adjustedTemplate)
k = &SecretKey{pkcs11Object{privHandle, c}, cipher}
return nil
}
}
if n == len(cipher.GenParams)-1 {
// If we have tried all available gen params, we should return a sensible error. So we skip the
// retry logic below and return directly.
return err
}
// nShield returns CKR_TEMPLATE_INCONSISTENT if if doesn't like the CKK/CKM combination.
// AWS CloudHSM returns CKR_ATTRIBUTE_VALUE_INVALID in the same circumstances.
if e, ok := err.(pkcs11.Error); ok &&
e == pkcs11.CKR_TEMPLATE_INCONSISTENT || e == pkcs11.CKR_ATTRIBUTE_VALUE_INVALID {
continue
}
return err
}
// We can only get here if there were no GenParams
return errors.New("cipher must have GenParams")
})
return
}
// Delete deletes the secret key from the token.
func (key *SecretKey) Delete() error {
return key.pkcs11Object.Delete()
}