1 package main
2
3 import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rand"
8 "crypto/rsa"
9 "crypto/x509"
10 "encoding/pem"
11 "math/big"
12 "os"
13 "path"
14 "strings"
15 "testing"
16
17 "github.com/letsencrypt/boulder/pkcs11helpers"
18 "github.com/letsencrypt/boulder/test"
19 "github.com/miekg/pkcs11"
20 )
21
22 func setupCtx() pkcs11helpers.MockCtx {
23 return pkcs11helpers.MockCtx{
24 GenerateKeyPairFunc: func(pkcs11.SessionHandle, []*pkcs11.Mechanism, []*pkcs11.Attribute, []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) {
25 return 0, 0, nil
26 },
27 SignInitFunc: func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error {
28 return nil
29 },
30 GenerateRandomFunc: func(pkcs11.SessionHandle, int) ([]byte, error) {
31 return []byte{1, 2, 3}, nil
32 },
33 FindObjectsInitFunc: func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
34 return nil
35 },
36 FindObjectsFunc: func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
37 return nil, false, nil
38 },
39 FindObjectsFinalFunc: func(pkcs11.SessionHandle) error {
40 return nil
41 },
42 }
43 }
44
45 func TestGenerateKeyRSA(t *testing.T) {
46 tmp := t.TempDir()
47
48 ctx := setupCtx()
49 rsaPriv, err := rsa.GenerateKey(rand.Reader, 1024)
50 test.AssertNotError(t, err, "Failed to generate a test RSA key")
51 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
52 return []*pkcs11.Attribute{
53 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, big.NewInt(int64(rsaPriv.E)).Bytes()),
54 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, rsaPriv.N.Bytes()),
55 }, nil
56 }
57 ctx.SignFunc = func(_ pkcs11.SessionHandle, msg []byte) ([]byte, error) {
58
59 return rsa.SignPKCS1v15(rand.Reader, rsaPriv, crypto.SHA256, msg[19:])
60 }
61 s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
62 keyPath := path.Join(tmp, "test-rsa-key.pem")
63 keyInfo, err := generateKey(s, "", keyPath, keyGenConfig{
64 Type: "rsa",
65 RSAModLength: 1024,
66 })
67 test.AssertNotError(t, err, "Failed to generate RSA key")
68 diskKeyBytes, err := os.ReadFile(keyPath)
69 test.AssertNotError(t, err, "Failed to load key from disk")
70 block, _ := pem.Decode(diskKeyBytes)
71 diskKey, err := x509.ParsePKIXPublicKey(block.Bytes)
72 test.AssertNotError(t, err, "Failed to parse disk key")
73 test.AssertDeepEquals(t, diskKey, keyInfo.key)
74 }
75
76 func setECGenerateFuncs(ctx *pkcs11helpers.MockCtx) {
77 ecPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
78 if err != nil {
79 panic(err)
80 }
81 ctx.GetAttributeValueFunc = func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
82 return []*pkcs11.Attribute{
83 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{6, 8, 42, 134, 72, 206, 61, 3, 1, 7}),
84 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, elliptic.Marshal(elliptic.P256(), ecPriv.X, ecPriv.Y)),
85 }, nil
86 }
87 ctx.SignFunc = func(_ pkcs11.SessionHandle, msg []byte) ([]byte, error) {
88 return ecPKCS11Sign(ecPriv, msg)
89 }
90 }
91
92 func TestGenerateKeyEC(t *testing.T) {
93 tmp := t.TempDir()
94
95 ctx := setupCtx()
96 setECGenerateFuncs(&ctx)
97 keyPath := path.Join(tmp, "test-ecdsa-key.pem")
98 s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
99 keyInfo, err := generateKey(s, "", keyPath, keyGenConfig{
100 Type: "ecdsa",
101 ECDSACurve: "P-256",
102 })
103 test.AssertNotError(t, err, "Failed to generate ECDSA key")
104 diskKeyBytes, err := os.ReadFile(keyPath)
105 test.AssertNotError(t, err, "Failed to load key from disk")
106 block, _ := pem.Decode(diskKeyBytes)
107 diskKey, err := x509.ParsePKIXPublicKey(block.Bytes)
108 test.AssertNotError(t, err, "Failed to parse disk key")
109 test.AssertDeepEquals(t, diskKey, keyInfo.key)
110 }
111
112 func setFindObjectsFuncs(label string, ctx *pkcs11helpers.MockCtx) {
113 var objectsFound []pkcs11.ObjectHandle
114 ctx.FindObjectsInitFunc = func(_ pkcs11.SessionHandle, template []*pkcs11.Attribute) error {
115 for _, attr := range template {
116 if attr.Type == pkcs11.CKA_LABEL && string(attr.Value) == label {
117 objectsFound = []pkcs11.ObjectHandle{1}
118 }
119 }
120 return nil
121 }
122 ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
123 return objectsFound, false, nil
124 }
125 ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
126 objectsFound = nil
127 return nil
128 }
129 }
130
131 func TestGenerateKeySlotHasSomethingWithLabel(t *testing.T) {
132 tmp := t.TempDir()
133
134 ctx := setupCtx()
135 label := "someLabel"
136 setFindObjectsFuncs(label, &ctx)
137 keyPath := path.Join(tmp, "should-not-exist.pem")
138 s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
139 _, err := generateKey(s, label, keyPath, keyGenConfig{
140 Type: "ecdsa",
141 ECDSACurve: "P-256",
142 })
143 test.AssertError(t, err, "expected failure for a slot with an object already in it")
144 test.Assert(t, strings.HasPrefix(err.Error(), "expected no preexisting objects with label"), "wrong error")
145 }
146
147 func TestGenerateKeySlotHasSomethingWithDifferentLabel(t *testing.T) {
148 tmp := t.TempDir()
149
150 ctx := setupCtx()
151 setECGenerateFuncs(&ctx)
152 setFindObjectsFuncs("someLabel", &ctx)
153 keyPath := path.Join(tmp, "should-not-exist.pem")
154 s := &pkcs11helpers.Session{Module: &ctx, Session: 0}
155 _, err := generateKey(s, "someOtherLabel", keyPath, keyGenConfig{
156 Type: "ecdsa",
157 ECDSACurve: "P-256",
158 })
159 test.AssertNotError(t, err, "expected success even though there was an object with a different label")
160 }
161
View as plain text