1 package pkcs11helpers
2
3 import (
4 "bytes"
5 "crypto"
6 "crypto/ecdsa"
7 "crypto/elliptic"
8 "crypto/rand"
9 "crypto/rsa"
10 "crypto/sha256"
11 "encoding/asn1"
12 "errors"
13 "math/big"
14 "strings"
15 "testing"
16
17 "github.com/letsencrypt/boulder/test"
18 "github.com/miekg/pkcs11"
19 )
20
21 func TestGetECDSAPublicKey(t *testing.T) {
22 ctx := &MockCtx{}
23 s := &Session{ctx, 0}
24
25
26 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
27 return nil, errors.New("yup")
28 }
29 _, err := s.GetECDSAPublicKey(0)
30 test.AssertError(t, err, "ecPub didn't fail on GetAttributeValue error")
31
32
33 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
34 return []*pkcs11.Attribute{}, nil
35 }
36 _, err = s.GetECDSAPublicKey(0)
37 test.AssertError(t, err, "ecPub didn't fail with empty attribute list")
38
39
40 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
41 return []*pkcs11.Attribute{
42 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{1, 2, 3}),
43 }, nil
44 }
45 _, err = s.GetECDSAPublicKey(0)
46 test.AssertError(t, err, "ecPub didn't fail with unknown curve")
47
48
49 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
50 return []*pkcs11.Attribute{
51 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}),
52 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{255}),
53 }, nil
54 }
55 _, err = s.GetECDSAPublicKey(0)
56 test.AssertError(t, err, "ecPub didn't fail with invalid EC point (invalid encoding)")
57
58
59 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
60 return []*pkcs11.Attribute{
61 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}),
62 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 0}),
63 }, nil
64 }
65 _, err = s.GetECDSAPublicKey(0)
66 test.AssertError(t, err, "ecPub didn't fail with invalid EC point (empty octet string)")
67
68
69 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
70 return []*pkcs11.Attribute{
71 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}),
72 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 4, 4, 1, 2, 3}),
73 }, nil
74 }
75 _, err = s.GetECDSAPublicKey(0)
76 test.AssertError(t, err, "ecPub didn't fail with invalid EC point (octet string, invalid contents)")
77
78
79 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
80 return []*pkcs11.Attribute{
81 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 5, 43, 129, 4, 0, 33}),
82 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 217, 225, 246, 210, 153, 134, 246, 104, 95, 79, 122, 206, 135, 241, 37, 114, 199, 87, 56, 167, 83, 56, 136, 174, 6, 145, 97, 239, 221, 49, 67, 148, 13, 126, 65, 90, 208, 195, 193, 171, 105, 40, 98, 132, 124, 30, 189, 215, 197, 178, 226, 166, 238, 240, 57, 215}),
83 }, nil
84 }
85 _, err = s.GetECDSAPublicKey(0)
86 test.AssertNotError(t, err, "ecPub failed with valid attributes (traditional encoding)")
87
88
89 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
90 return []*pkcs11.Attribute{
91 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 5, 43, 129, 4, 0, 33}),
92 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, []byte{4, 57, 4, 217, 225, 246, 210, 153, 134, 246, 104, 95, 79, 122, 206, 135, 241, 37, 114, 199, 87, 56, 167, 83, 56, 136, 174, 6, 145, 97, 239, 221, 49, 67, 148, 13, 126, 65, 90, 208, 195, 193, 171, 105, 40, 98, 132, 124, 30, 189, 215, 197, 178, 226, 166, 238, 240, 57, 215}),
93 }, nil
94 }
95 _, err = s.GetECDSAPublicKey(0)
96 test.AssertNotError(t, err, "ecPub failed with valid attributes (non-traditional encoding)")
97 }
98
99 func TestRSAPublicKey(t *testing.T) {
100 ctx := &MockCtx{}
101 s := &Session{ctx, 0}
102
103
104 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
105 return nil, errors.New("yup")
106 }
107 _, err := s.GetRSAPublicKey(0)
108 test.AssertError(t, err, "rsaPub didn't fail on GetAttributeValue error")
109
110
111 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
112 return []*pkcs11.Attribute{}, nil
113 }
114 _, err = s.GetRSAPublicKey(0)
115 test.AssertError(t, err, "rsaPub didn't fail with empty attribute list")
116
117
118 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
119 return []*pkcs11.Attribute{
120 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, []byte{1, 0, 1}),
121 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, []byte{255}),
122 }, nil
123 }
124 _, err = s.GetRSAPublicKey(0)
125 test.AssertNotError(t, err, "rsaPub failed with valid attributes")
126 }
127
128 func findObjectsInitOK(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
129 return nil
130 }
131
132 func findObjectsOK(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
133 return []pkcs11.ObjectHandle{1}, false, nil
134 }
135
136 func findObjectsFinalOK(pkcs11.SessionHandle) error {
137 return nil
138 }
139
140 func newMock() *MockCtx {
141 return &MockCtx{
142 FindObjectsInitFunc: findObjectsInitOK,
143 FindObjectsFunc: findObjectsOK,
144 FindObjectsFinalFunc: findObjectsFinalOK,
145 }
146 }
147
148 func newSessionWithMock() (*Session, *MockCtx) {
149 ctx := newMock()
150 return &Session{ctx, 0}, ctx
151 }
152
153 func TestFindObjectFailsOnFailedInit(t *testing.T) {
154 ctx := MockCtx{}
155 ctx.FindObjectsFinalFunc = findObjectsFinalOK
156 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
157 return []pkcs11.ObjectHandle{1}, false, nil
158 }
159
160
161 ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
162 return errors.New("broken")
163 }
164 s := &Session{ctx, 0}
165 _, err := s.FindObject(nil)
166 test.AssertError(t, err, "FindObject didn't fail when FindObjectsInit failed")
167 }
168
169 func TestFindObjectFailsOnFailedFindObjects(t *testing.T) {
170 ctx := MockCtx{}
171 ctx.FindObjectsInitFunc = findObjectsInitOK
172 ctx.FindObjectsFinalFunc = findObjectsFinalOK
173
174
175 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
176 return nil, false, errors.New("broken")
177 }
178 s := &Session{ctx, 0}
179 _, err := s.FindObject(nil)
180 test.AssertError(t, err, "FindObject didn't fail when FindObjects failed")
181 }
182
183 func TestFindObjectFailsOnNoHandles(t *testing.T) {
184 ctx := MockCtx{}
185 ctx.FindObjectsInitFunc = findObjectsInitOK
186 ctx.FindObjectsFinalFunc = findObjectsFinalOK
187
188
189 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
190 return []pkcs11.ObjectHandle{}, false, nil
191 }
192 s := &Session{ctx, 0}
193 _, err := s.FindObject(nil)
194 test.AssertEquals(t, err, ErrNoObject)
195 }
196
197 func TestFindObjectFailsOnMultipleHandles(t *testing.T) {
198 ctx := MockCtx{}
199 ctx.FindObjectsInitFunc = findObjectsInitOK
200 ctx.FindObjectsFinalFunc = findObjectsFinalOK
201
202
203 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
204 return []pkcs11.ObjectHandle{1, 2, 3}, false, nil
205 }
206 s := &Session{ctx, 0}
207 _, err := s.FindObject(nil)
208 test.AssertError(t, err, "FindObject didn't fail when FindObjects returns multiple handles")
209 test.Assert(t, strings.HasPrefix(err.Error(), "too many objects"), "FindObject failed with wrong error")
210 }
211
212 func TestFindObjectFailsOnFinalizeFailure(t *testing.T) {
213 ctx := MockCtx{}
214 ctx.FindObjectsInitFunc = findObjectsInitOK
215
216
217 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
218 return []pkcs11.ObjectHandle{1}, false, nil
219 }
220 ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
221 return errors.New("broken")
222 }
223 s := &Session{ctx, 0}
224 _, err := s.FindObject(nil)
225 test.AssertError(t, err, "FindObject didn't fail when FindObjectsFinal fails")
226 }
227
228 func TestFindObjectSucceeds(t *testing.T) {
229 ctx := MockCtx{}
230 ctx.FindObjectsInitFunc = findObjectsInitOK
231 ctx.FindObjectsFinalFunc = findObjectsFinalOK
232 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
233 return []pkcs11.ObjectHandle{1}, false, nil
234 }
235 s := &Session{ctx, 0}
236
237
238 handle, err := s.FindObject(nil)
239 test.AssertNotError(t, err, "FindObject failed when everything worked as expected")
240 test.AssertEquals(t, handle, pkcs11.ObjectHandle(1))
241 }
242
243 func TestX509Signer(t *testing.T) {
244 ctx := MockCtx{}
245
246
247
248 ctx.SignInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error {
249 return nil
250 }
251 tk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
252 test.AssertNotError(t, err, "Failed to generate test key")
253 ctx.SignFunc = func(_ pkcs11.SessionHandle, digest []byte) ([]byte, error) {
254 r, s, err := ecdsa.Sign(rand.Reader, tk, digest[:])
255 if err != nil {
256 return nil, err
257 }
258 rBytes := r.Bytes()
259 sBytes := s.Bytes()
260
261
262
263
264 switch {
265 case len(rBytes) < len(sBytes):
266 padding := make([]byte, len(sBytes)-len(rBytes))
267 rBytes = append(padding, rBytes...)
268 case len(rBytes) > len(sBytes):
269 padding := make([]byte, len(rBytes)-len(sBytes))
270 sBytes = append(padding, sBytes...)
271 }
272 return append(rBytes, sBytes...), nil
273 }
274 digest := sha256.Sum256([]byte("hello"))
275 s := &Session{ctx, 0}
276 signer := &x509Signer{session: s, keyType: ECDSAKey, pub: tk.Public()}
277 signature, err := signer.Sign(nil, digest[:], crypto.SHA256)
278 test.AssertNotError(t, err, "x509Signer.Sign failed")
279
280 var rfcFormat struct {
281 R, S *big.Int
282 }
283 rest, err := asn1.Unmarshal(signature, &rfcFormat)
284 test.AssertNotError(t, err, "asn1.Unmarshal failed trying to parse signature")
285 test.Assert(t, len(rest) == 0, "Signature had trailing garbage")
286 verified := ecdsa.Verify(&tk.PublicKey, digest[:], rfcFormat.R, rfcFormat.S)
287 test.Assert(t, verified, "Failed to verify RFC format signature")
288
289 test.AssertEquals(t, signer.Public(), tk.Public())
290 }
291
292 func TestGetKeyWhenLabelIsWrong(t *testing.T) {
293 s, ctx := newSessionWithMock()
294 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1}
295 rightLabel := "label"
296 var objectsToReturn []pkcs11.ObjectHandle
297
298 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, attr []*pkcs11.Attribute) error {
299 objectsToReturn = []pkcs11.ObjectHandle{1}
300 for _, a := range attr {
301 if a.Type == pkcs11.CKA_LABEL && !bytes.Equal(a.Value, []byte(rightLabel)) {
302 objectsToReturn = nil
303 }
304 }
305 return nil
306 }
307 ctx.FindObjectsFunc = func(_ pkcs11.SessionHandle, _ int) ([]pkcs11.ObjectHandle, bool, error) {
308 return objectsToReturn, false, nil
309 }
310 ctx.FindObjectsFinalFunc = func(_ pkcs11.SessionHandle) error {
311 return nil
312 }
313
314 _, err := s.NewSigner("wrong-label", pubKey)
315 test.AssertError(t, err, "newSigner didn't fail when label was a mismatch for public key")
316 expected := "no objects found matching provided template"
317 if !strings.Contains(err.Error(), expected) {
318 t.Errorf("expected error to contain %q but it was %q", expected, err)
319 }
320 }
321
322 func TestGetKeyWhenGetAttributeValueFails(t *testing.T) {
323 s, ctx := newSessionWithMock()
324 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1}
325
326
327 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
328 return nil, errors.New("broken")
329 }
330 _, err := s.NewSigner("label", pubKey)
331 test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type failed")
332 }
333
334 func TestGetKeyWhenGetAttributeValueReturnsNone(t *testing.T) {
335 s, ctx := newSessionWithMock()
336 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1}
337
338 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
339 return nil, errors.New("broken")
340 }
341
342 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
343 return nil, nil
344 }
345 _, err := s.NewSigner("label", pubKey)
346 test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key type returned no attributes")
347 }
348
349 func TestGetKeyWhenFindObjectForPublicKeyFails(t *testing.T) {
350 s, ctx := newSessionWithMock()
351 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1}
352
353
354 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
355 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC)}, nil
356 }
357 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
358 if bytes.Equal(tmpl[0].Value, []byte{2, 0, 0, 0, 0, 0, 0, 0}) {
359 return errors.New("broken")
360 }
361 return nil
362 }
363 _, err := s.NewSigner("label", pubKey)
364 test.AssertError(t, err, "newSigner didn't fail when FindObject for public key handle failed")
365 }
366
367 func TestGetKeyWhenFindObjectForPrivateKeyReturnsUnknownType(t *testing.T) {
368 s, ctx := newSessionWithMock()
369 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1}
370
371
372 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, tmpl []*pkcs11.Attribute) error {
373 return nil
374 }
375 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
376 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{2, 0, 0, 0, 0, 0, 0, 0})}, nil
377 }
378 _, err := s.NewSigner("label", pubKey)
379 test.AssertError(t, err, "newSigner didn't fail when GetAttributeValue for private key returned unknown key type")
380 }
381
382 func TestGetKeyWhenFindObjectForPrivateKeyFails(t *testing.T) {
383 s, ctx := newSessionWithMock()
384 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1}
385
386
387 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
388 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{0, 0, 0, 0, 0, 0, 0, 0})}, nil
389 }
390 _, err := s.NewSigner("label", pubKey)
391 test.AssertError(t, err, "newSigner didn't fail when GetRSAPublicKey fails")
392
393
394 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
395 return []*pkcs11.Attribute{pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, []byte{3, 0, 0, 0, 0, 0, 0, 0})}, nil
396 }
397 _, err = s.NewSigner("label", pubKey)
398 test.AssertError(t, err, "newSigner didn't fail when GetECDSAPublicKey fails")
399 }
400
401 func TestGetKeySucceeds(t *testing.T) {
402 s, ctx := newSessionWithMock()
403 pubKey := &rsa.PublicKey{N: big.NewInt(1), E: 1}
404
405
406 ctx.GetAttributeValueFunc = func(_ pkcs11.SessionHandle, _ pkcs11.ObjectHandle, attrs []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
407 var returns []*pkcs11.Attribute
408 for _, attr := range attrs {
409 switch attr.Type {
410 case pkcs11.CKA_ID:
411 returns = append(returns, pkcs11.NewAttribute(pkcs11.CKA_ID, []byte{99}))
412 default:
413 return nil, errors.New("GetAttributeValue got unexpected attribute type")
414 }
415 }
416 return returns, nil
417 }
418 _, err := s.NewSigner("label", pubKey)
419 test.AssertNotError(t, err, "newSigner failed when everything worked properly")
420 }
421
View as plain text