1
2
3
4 package pkcs11
5
6
7
8
9 import (
10 "bytes"
11 "fmt"
12 "log"
13 "math/big"
14 "os"
15 "testing"
16 )
17
18
26
27 var lib = "/usr/lib/softhsm/libsofthsm2.so"
28
29 func setenv(t *testing.T) *Ctx {
30 if x := os.Getenv("SOFTHSM_LIB"); x != "" {
31 lib = x
32 }
33 t.Logf("loading %s", lib)
34 p := New(lib)
35 if p == nil {
36 t.Fatal("Failed to init lib")
37 }
38 return p
39 }
40
41 func TestSetenv(t *testing.T) {
42 wd, _ := os.Getwd()
43 os.Setenv("SOFTHSM_CONF", wd+"/softhsm.conf")
44
45 if x := os.Getenv("SOFTHSM_LIB"); x != "" {
46 lib = x
47 }
48 p := New(lib)
49 if p == nil {
50 t.Fatal("Failed to init pkcs11")
51 }
52 p.Destroy()
53 return
54 }
55
56 func getSession(p *Ctx, t *testing.T) SessionHandle {
57 if e := p.Initialize(); e != nil {
58 t.Fatalf("init error %s\n", e)
59 }
60 slots, e := p.GetSlotList(true)
61 if e != nil {
62 t.Fatalf("slots %s\n", e)
63 }
64 session, e := p.OpenSession(slots[0], CKF_SERIAL_SESSION|CKF_RW_SESSION)
65 if e != nil {
66 t.Fatalf("session %s\n", e)
67 }
68 if e := p.Login(session, CKU_USER, pin); e != nil {
69 t.Fatalf("user pin %s\n", e)
70 }
71 return session
72 }
73
74 func TestInitialize(t *testing.T) {
75 p := setenv(t)
76 if e := p.Initialize(); e != nil {
77 t.Fatalf("init error %s\n", e)
78 }
79 p.Finalize()
80 p.Destroy()
81 }
82
83 func TestNew(t *testing.T) {
84 if p := New(""); p != nil {
85 t.Fatalf("init should have failed, got %v\n", p)
86 }
87 if p := New("/does/not/exist"); p != nil {
88 t.Fatalf("init should have failed, got %v\n", p)
89 }
90 }
91
92 func finishSession(p *Ctx, session SessionHandle) {
93 p.Logout(session)
94 p.CloseSession(session)
95 p.Finalize()
96 p.Destroy()
97 }
98
99 func TestGetInfo(t *testing.T) {
100 p := setenv(t)
101 session := getSession(p, t)
102 defer finishSession(p, session)
103 info, err := p.GetInfo()
104 if err != nil {
105 t.Fatalf("non zero error %s\n", err)
106 }
107 if info.ManufacturerID != "SoftHSM" {
108 t.Fatal("ID should be SoftHSM")
109 }
110 t.Logf("%+v\n", info)
111 }
112
113 func TestFindObject(t *testing.T) {
114 p := setenv(t)
115 session := getSession(p, t)
116 defer finishSession(p, session)
117
118 tokenLabel := "TestFindObject"
119
120
121 generateRSAKeyPair(t, p, session, tokenLabel, false)
122
123 template := []*Attribute{NewAttribute(CKA_LABEL, tokenLabel)}
124 if e := p.FindObjectsInit(session, template); e != nil {
125 t.Fatalf("failed to init: %s\n", e)
126 }
127 obj, _, e := p.FindObjects(session, 2)
128 if e != nil {
129 t.Fatalf("failed to find: %s\n", e)
130 }
131 if e := p.FindObjectsFinal(session); e != nil {
132 t.Fatalf("failed to finalize: %s\n", e)
133 }
134 if len(obj) != 2 {
135 t.Fatal("should have found two objects")
136 }
137 }
138
139 func TestGetAttributeValue(t *testing.T) {
140 p := setenv(t)
141 session := getSession(p, t)
142 defer finishSession(p, session)
143
144 pbk, _ := generateRSAKeyPair(t, p, session, "GetAttributeValue", false)
145
146 template := []*Attribute{
147 NewAttribute(CKA_PUBLIC_EXPONENT, nil),
148 NewAttribute(CKA_MODULUS_BITS, nil),
149 NewAttribute(CKA_MODULUS, nil),
150 NewAttribute(CKA_LABEL, nil),
151 }
152 attr, err := p.GetAttributeValue(session, ObjectHandle(pbk), template)
153 if err != nil {
154 t.Fatalf("err %s\n", err)
155 }
156 for i, a := range attr {
157 t.Logf("attr %d, type %d, valuelen %d", i, a.Type, len(a.Value))
158 if a.Type == CKA_MODULUS {
159 mod := big.NewInt(0)
160 mod.SetBytes(a.Value)
161 t.Logf("modulus %s\n", mod.String())
162 }
163 }
164 }
165
166 func TestDigest(t *testing.T) {
167 p := setenv(t)
168 session := getSession(p, t)
169 defer finishSession(p, session)
170 t.Run("Simple", func(t *testing.T) {
171
172 testDigest(t, p, session, []byte("this is a string"), "517592df8fec3ad146a79a9af153db2a4d784ec5")
173 })
174 t.Run("Empty", func(t *testing.T) {
175
176 testDigest(t, p, session, []byte{}, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
177 })
178 }
179
180 func testDigest(t *testing.T, p *Ctx, session SessionHandle, input []byte, expected string) {
181 e := p.DigestInit(session, []*Mechanism{NewMechanism(CKM_SHA_1, nil)})
182 if e != nil {
183 t.Fatalf("DigestInit: %s\n", e)
184 }
185
186 hash, e := p.Digest(session, input)
187 if e != nil {
188 t.Fatalf("digest: %s\n", e)
189 }
190 hex := ""
191 for _, d := range hash {
192 hex += fmt.Sprintf("%02x", d)
193 }
194 if hex != expected {
195 t.Fatalf("wrong digest: %s", hex)
196 }
197 }
198
199 func TestDigestUpdate(t *testing.T) {
200 p := setenv(t)
201 session := getSession(p, t)
202 defer finishSession(p, session)
203 t.Run("Simple", func(t *testing.T) {
204
205 testDigestUpdate(t, p, session, [][]byte{[]byte("this is "), []byte("a string")}, "517592df8fec3ad146a79a9af153db2a4d784ec5")
206 })
207 t.Run("Empty", func(t *testing.T) {
208
209 testDigestUpdate(t, p, session, [][]byte{{}}, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
210 })
211 }
212
213 func testDigestUpdate(t *testing.T, p *Ctx, session SessionHandle, inputs [][]byte, expected string) {
214 if e := p.DigestInit(session, []*Mechanism{NewMechanism(CKM_SHA_1, nil)}); e != nil {
215 t.Fatalf("DigestInit: %s\n", e)
216 }
217 for _, input := range inputs {
218 if e := p.DigestUpdate(session, input); e != nil {
219 t.Fatalf("DigestUpdate: %s\n", e)
220 }
221 }
222 hash, e := p.DigestFinal(session)
223 if e != nil {
224 t.Fatalf("DigestFinal: %s\n", e)
225 }
226 hex := ""
227 for _, d := range hash {
228 hex += fmt.Sprintf("%02x", d)
229 }
230 if hex != expected {
231 t.Fatalf("wrong digest: %s", hex)
232 }
233 }
234
235
248 func generateRSAKeyPair(t *testing.T, p *Ctx, session SessionHandle, tokenLabel string, tokenPersistent bool) (ObjectHandle, ObjectHandle) {
249
259
260 publicKeyTemplate := []*Attribute{
261 NewAttribute(CKA_CLASS, CKO_PUBLIC_KEY),
262 NewAttribute(CKA_KEY_TYPE, CKK_RSA),
263 NewAttribute(CKA_TOKEN, tokenPersistent),
264 NewAttribute(CKA_VERIFY, true),
265 NewAttribute(CKA_PUBLIC_EXPONENT, []byte{1, 0, 1}),
266 NewAttribute(CKA_MODULUS_BITS, 2048),
267 NewAttribute(CKA_LABEL, tokenLabel),
268 }
269 privateKeyTemplate := []*Attribute{
270 NewAttribute(CKA_TOKEN, tokenPersistent),
271 NewAttribute(CKA_SIGN, true),
272 NewAttribute(CKA_LABEL, tokenLabel),
273 NewAttribute(CKA_SENSITIVE, true),
274 NewAttribute(CKA_EXTRACTABLE, true),
275 }
276 pbk, pvk, e := p.GenerateKeyPair(session,
277 []*Mechanism{NewMechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, nil)},
278 publicKeyTemplate, privateKeyTemplate)
279 if e != nil {
280 t.Fatalf("failed to generate keypair: %s\n", e)
281 }
282
283 return pbk, pvk
284 }
285
286 func TestGenerateKeyPair(t *testing.T) {
287 p := setenv(t)
288 session := getSession(p, t)
289 defer finishSession(p, session)
290 tokenLabel := "TestGenerateKeyPair"
291 generateRSAKeyPair(t, p, session, tokenLabel, false)
292 }
293
294 func TestSign(t *testing.T) {
295 p := setenv(t)
296 session := getSession(p, t)
297 defer finishSession(p, session)
298
299 tokenLabel := "TestSign"
300 _, pvk := generateRSAKeyPair(t, p, session, tokenLabel, false)
301
302 p.SignInit(session, []*Mechanism{NewMechanism(CKM_SHA1_RSA_PKCS, nil)}, pvk)
303 _, e := p.Sign(session, []byte("Sign me!"))
304 if e != nil {
305 t.Fatalf("failed to sign: %s\n", e)
306 }
307 }
308
309
318 func destroyObject(t *testing.T, p *Ctx, session SessionHandle, searchToken string, class uint) (err error) {
319 template := []*Attribute{
320 NewAttribute(CKA_LABEL, searchToken),
321 NewAttribute(CKA_CLASS, class)}
322
323 if e := p.FindObjectsInit(session, template); e != nil {
324 t.Fatalf("failed to init: %s\n", e)
325 }
326 obj, _, e := p.FindObjects(session, 1)
327 if e != nil || len(obj) == 0 {
328 t.Fatalf("failed to find objects")
329 }
330 if e := p.FindObjectsFinal(session); e != nil {
331 t.Fatalf("failed to finalize: %s\n", e)
332 }
333
334 if e := p.DestroyObject(session, obj[0]); e != nil {
335 t.Fatalf("DestroyObject failed: %s\n", e)
336 }
337 return
338 }
339
340
341 func TestDestroyObject(t *testing.T) {
342 p := setenv(t)
343 session := getSession(p, t)
344 defer finishSession(p, session)
345
346 generateRSAKeyPair(t, p, session, "TestDestroyKey", true)
347 if e := destroyObject(t, p, session, "TestDestroyKey", CKO_PUBLIC_KEY); e != nil {
348 t.Fatalf("Failed to destroy object: %s\n", e)
349 }
350 if e := destroyObject(t, p, session, "TestDestroyKey", CKO_PRIVATE_KEY); e != nil {
351 t.Fatalf("Failed to destroy object: %s\n", e)
352 }
353
354 }
355
356 func TestSymmetricEncryption(t *testing.T) {
357 p := setenv(t)
358 session := getSession(p, t)
359 defer finishSession(p, session)
360 if info, err := p.GetInfo(); err != nil {
361 t.Errorf("GetInfo: %v", err)
362 return
363 } else if info.ManufacturerID == "SoftHSM" && info.LibraryVersion.Major < 2 {
364 t.Skipf("AES not implemented on SoftHSM")
365 }
366 tokenLabel := "TestGenerateKey"
367 keyTemplate := []*Attribute{
368 NewAttribute(CKA_TOKEN, false),
369 NewAttribute(CKA_ENCRYPT, true),
370 NewAttribute(CKA_DECRYPT, true),
371 NewAttribute(CKA_LABEL, tokenLabel),
372 NewAttribute(CKA_SENSITIVE, true),
373 NewAttribute(CKA_EXTRACTABLE, true),
374 NewAttribute(CKA_VALUE_LEN, 16),
375 }
376 key, err := p.GenerateKey(session,
377 []*Mechanism{NewMechanism(CKM_AES_KEY_GEN, nil)},
378 keyTemplate)
379 if err != nil {
380 t.Fatalf("failed to generate keypair: %s\n", err)
381 }
382 t.Run("Encrypt", func(t *testing.T) {
383 t.Run("ECB", func(t *testing.T) {
384 testEncrypt(t, p, session, key, CKM_AES_ECB, make([]byte, 32), nil)
385 })
386 t.Run("CBC", func(t *testing.T) {
387 testEncrypt(t, p, session, key, CKM_AES_CBC, make([]byte, 32), make([]byte, 16))
388 })
389 t.Run("CBC-PAD", func(t *testing.T) {
390 testEncrypt(t, p, session, key, CKM_AES_CBC_PAD, make([]byte, 31), make([]byte, 16))
391 })
392
397 })
398 t.Run("EncryptUpdate", func(t *testing.T) {
399 t.Run("ECB", func(t *testing.T) {
400 testEncryptUpdate(t, p, session, key, CKM_AES_ECB, [][]byte{make([]byte, 32), make([]byte, 16)}, nil)
401 })
402 t.Run("CBC", func(t *testing.T) {
403 testEncryptUpdate(t, p, session, key, CKM_AES_CBC, [][]byte{make([]byte, 32), make([]byte, 16)}, make([]byte, 16))
404 })
405 t.Run("CBC-PAD", func(t *testing.T) {
406 testEncryptUpdate(t, p, session, key, CKM_AES_CBC_PAD, [][]byte{make([]byte, 11), make([]byte, 20)}, make([]byte, 16))
407 })
408
413 })
414 }
415
416 func testEncrypt(t *testing.T, p *Ctx, session SessionHandle, key ObjectHandle, mech uint, plaintext []byte, iv []byte) {
417 var err error
418 if err = p.EncryptInit(session, []*Mechanism{NewMechanism(mech, iv)}, key); err != nil {
419 t.Fatalf("EncryptInit: %s\n", err)
420 }
421 var ciphertext []byte
422 if ciphertext, err = p.Encrypt(session, plaintext); err != nil {
423 t.Fatalf("Encrypt: %s\n", err)
424 }
425 if err = p.DecryptInit(session, []*Mechanism{NewMechanism(mech, iv)}, key); err != nil {
426 t.Fatalf("DecryptInit: %s\n", err)
427 }
428 var decrypted []byte
429 if decrypted, err = p.Decrypt(session, ciphertext); err != nil {
430 t.Fatalf("Decrypt: %s\n", err)
431 }
432 if bytes.Compare(plaintext, decrypted) != 0 {
433 t.Fatalf("Plaintext mismatch")
434 }
435 }
436
437 func testEncryptUpdate(t *testing.T, p *Ctx, session SessionHandle, key ObjectHandle, mech uint, plaintexts [][]byte, iv []byte) {
438 var err error
439 if err = p.EncryptInit(session, []*Mechanism{NewMechanism(mech, iv)}, key); err != nil {
440 t.Fatalf("EncryptInit: %s\n", err)
441 }
442 var ciphertexts [][]byte
443 var output, plaintext []byte
444 for _, input := range plaintexts {
445 plaintext = append(plaintext, input...)
446 if output, err = p.EncryptUpdate(session, input); err != nil {
447 t.Fatalf("EncryptUpdate: %s\n", err)
448 }
449 ciphertexts = append(ciphertexts, output)
450 }
451 if output, err = p.EncryptFinal(session); err != nil {
452 t.Fatalf("EncryptFinal: %s\n", err)
453 }
454 ciphertexts = append(ciphertexts, output)
455 if err = p.DecryptInit(session, []*Mechanism{NewMechanism(mech, iv)}, key); err != nil {
456 t.Fatalf("DecryptInit: %s\n", err)
457 }
458 var decrypted []byte
459 for _, input := range ciphertexts {
460 if len(input) == 0 {
461 continue
462 }
463 if output, err = p.DecryptUpdate(session, input); err != nil {
464 t.Fatalf("DecryptUpdate: %s\n", err)
465 }
466 decrypted = append(decrypted, output...)
467 }
468 if output, err = p.DecryptFinal(session); err != nil {
469 t.Fatalf("DecryptFinal: %s\n", err)
470 }
471 decrypted = append(decrypted, output...)
472 if bytes.Compare(plaintext, decrypted) != 0 {
473 t.Fatalf("Plaintext mismatch")
474 }
475 }
476
477
478
479 func ExampleCtx_Sign() {
480 if x := os.Getenv("SOFTHSM_LIB"); x != "" {
481 lib = x
482 }
483 p := New(lib)
484 if p == nil {
485 log.Fatal("Failed to init lib")
486 }
487
488 p.Initialize()
489 defer p.Destroy()
490 defer p.Finalize()
491 slots, _ := p.GetSlotList(true)
492 session, _ := p.OpenSession(slots[0], CKF_SERIAL_SESSION|CKF_RW_SESSION)
493 defer p.CloseSession(session)
494 p.Login(session, CKU_USER, "1234")
495 defer p.Logout(session)
496 publicKeyTemplate := []*Attribute{
497 NewAttribute(CKA_CLASS, CKO_PUBLIC_KEY),
498 NewAttribute(CKA_KEY_TYPE, CKK_RSA),
499 NewAttribute(CKA_TOKEN, false),
500 NewAttribute(CKA_ENCRYPT, true),
501 NewAttribute(CKA_PUBLIC_EXPONENT, []byte{3}),
502 NewAttribute(CKA_MODULUS_BITS, 1024),
503 NewAttribute(CKA_LABEL, "ExampleSign"),
504 }
505 privateKeyTemplate := []*Attribute{
506 NewAttribute(CKA_CLASS, CKO_PRIVATE_KEY),
507 NewAttribute(CKA_KEY_TYPE, CKK_RSA),
508 NewAttribute(CKA_TOKEN, false),
509 NewAttribute(CKA_PRIVATE, true),
510 NewAttribute(CKA_SIGN, true),
511 NewAttribute(CKA_LABEL, "ExampleSign"),
512 }
513 _, priv, err := p.GenerateKeyPair(session,
514 []*Mechanism{NewMechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, nil)},
515 publicKeyTemplate, privateKeyTemplate)
516 if err != nil {
517 log.Fatal(err)
518 }
519 p.SignInit(session, []*Mechanism{NewMechanism(CKM_SHA1_RSA_PKCS, nil)}, priv)
520
521 data := []byte("Lets sign this data")
522
523 _, err = p.Sign(session, data)
524 if err != nil {
525 log.Fatal(err)
526 }
527
528 fmt.Printf("It works!")
529
530 }
531
532
533
View as plain text