1 package pkcs11helpers
2
3 import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rsa"
8 "encoding/asn1"
9 "errors"
10 "fmt"
11 "io"
12 "math/big"
13
14 "github.com/miekg/pkcs11"
15 )
16
17 type PKCtx interface {
18 GenerateKeyPair(pkcs11.SessionHandle, []*pkcs11.Mechanism, []*pkcs11.Attribute, []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error)
19 GetAttributeValue(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error)
20 SignInit(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error
21 Sign(pkcs11.SessionHandle, []byte) ([]byte, error)
22 GenerateRandom(pkcs11.SessionHandle, int) ([]byte, error)
23 FindObjectsInit(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error
24 FindObjects(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error)
25 FindObjectsFinal(sh pkcs11.SessionHandle) error
26 }
27
28
29
30 type Session struct {
31 Module PKCtx
32 Session pkcs11.SessionHandle
33 }
34
35 func Initialize(module string, slot uint, pin string) (*Session, error) {
36 ctx := pkcs11.New(module)
37 if ctx == nil {
38 return nil, errors.New("failed to load module")
39 }
40 err := ctx.Initialize()
41 if err != nil {
42 return nil, fmt.Errorf("couldn't initialize context: %s", err)
43 }
44
45 session, err := ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
46 if err != nil {
47 return nil, fmt.Errorf("couldn't open session: %s", err)
48 }
49
50 err = ctx.Login(session, pkcs11.CKU_USER, pin)
51 if err != nil {
52 return nil, fmt.Errorf("couldn't login: %s", err)
53 }
54
55 return &Session{ctx, session}, nil
56 }
57
58
59 var curveOIDs = map[string]asn1.ObjectIdentifier{
60 "P-256": {1, 2, 840, 10045, 3, 1, 7},
61 "P-384": {1, 3, 132, 0, 34},
62 }
63
64
65
66
67 func (s *Session) getPublicKeyID(label string, publicKey crypto.PublicKey) ([]byte, error) {
68 var template []*pkcs11.Attribute
69 switch key := publicKey.(type) {
70 case *rsa.PublicKey:
71 template = []*pkcs11.Attribute{
72 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
73 pkcs11.NewAttribute(pkcs11.CKA_LABEL, []byte(label)),
74 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_RSA),
75 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, key.N.Bytes()),
76 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, big.NewInt(int64(key.E)).Bytes()),
77 }
78 case *ecdsa.PublicKey:
79
80
81
82 rawValue := asn1.RawValue{
83 Tag: 4,
84 Bytes: elliptic.Marshal(key.Curve, key.X, key.Y),
85 }
86 marshalledPoint, err := asn1.Marshal(rawValue)
87 if err != nil {
88 return nil, err
89 }
90 curveOID, err := asn1.Marshal(curveOIDs[key.Curve.Params().Name])
91 if err != nil {
92 return nil, err
93 }
94 template = []*pkcs11.Attribute{
95 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
96 pkcs11.NewAttribute(pkcs11.CKA_LABEL, []byte(label)),
97 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC),
98 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, curveOID),
99 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, marshalledPoint),
100 }
101 default:
102 return nil, fmt.Errorf("unsupported public key of type %T", publicKey)
103 }
104
105 publicKeyHandle, err := s.FindObject(template)
106 if err != nil {
107 return nil, err
108 }
109
110 attrs, err := s.Module.GetAttributeValue(s.Session, publicKeyHandle, []*pkcs11.Attribute{
111 pkcs11.NewAttribute(pkcs11.CKA_ID, nil),
112 })
113 if err != nil {
114 return nil, err
115 }
116 if len(attrs) == 1 && attrs[0].Type == pkcs11.CKA_ID {
117 return attrs[0].Value, nil
118 }
119 return nil, fmt.Errorf("invalid result from GetAttributeValue")
120 }
121
122
123
124 func (s *Session) getPrivateKey(publicKeyID []byte) (pkcs11.ObjectHandle, error) {
125 return s.FindObject([]*pkcs11.Attribute{
126 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
127 pkcs11.NewAttribute(pkcs11.CKA_ID, publicKeyID),
128 })
129 }
130
131 func (s *Session) GetAttributeValue(object pkcs11.ObjectHandle, attributes []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
132 return s.Module.GetAttributeValue(s.Session, object, attributes)
133 }
134
135 func (s *Session) GenerateKeyPair(m []*pkcs11.Mechanism, pubAttrs []*pkcs11.Attribute, privAttrs []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) {
136 return s.Module.GenerateKeyPair(s.Session, m, pubAttrs, privAttrs)
137 }
138
139 func (s *Session) GetRSAPublicKey(object pkcs11.ObjectHandle) (*rsa.PublicKey, error) {
140
141 attrs, err := s.Module.GetAttributeValue(s.Session, object, []*pkcs11.Attribute{
142 pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil),
143 pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil),
144 })
145 if err != nil {
146 return nil, fmt.Errorf("Failed to retrieve key attributes: %s", err)
147 }
148
149
150 pubKey := &rsa.PublicKey{}
151 gotMod, gotExp := false, false
152 for _, a := range attrs {
153 switch a.Type {
154 case pkcs11.CKA_PUBLIC_EXPONENT:
155 pubKey.E = int(big.NewInt(0).SetBytes(a.Value).Int64())
156 gotExp = true
157 case pkcs11.CKA_MODULUS:
158 pubKey.N = big.NewInt(0).SetBytes(a.Value)
159 gotMod = true
160 }
161 }
162
163 if !gotExp || !gotMod {
164 return nil, errors.New("Couldn't retrieve modulus and exponent")
165 }
166 return pubKey, nil
167 }
168
169
170
171 var oidDERToCurve = map[string]elliptic.Curve{
172 "06052B81040021": elliptic.P224(),
173 "06082A8648CE3D030107": elliptic.P256(),
174 "06052B81040022": elliptic.P384(),
175 "06052B81040023": elliptic.P521(),
176 }
177
178 func (s *Session) GetECDSAPublicKey(object pkcs11.ObjectHandle) (*ecdsa.PublicKey, error) {
179
180 attrs, err := s.Module.GetAttributeValue(s.Session, object, []*pkcs11.Attribute{
181 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil),
182 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil),
183 })
184 if err != nil {
185 return nil, fmt.Errorf("Failed to retrieve key attributes: %s", err)
186 }
187
188 pubKey := &ecdsa.PublicKey{}
189 var pointBytes []byte
190 for _, a := range attrs {
191 switch a.Type {
192 case pkcs11.CKA_EC_PARAMS:
193 rCurve, present := oidDERToCurve[fmt.Sprintf("%X", a.Value)]
194 if !present {
195 return nil, errors.New("Unknown curve OID value returned")
196 }
197 pubKey.Curve = rCurve
198 case pkcs11.CKA_EC_POINT:
199 pointBytes = a.Value
200 }
201 }
202 if pointBytes == nil || pubKey.Curve == nil {
203 return nil, errors.New("Couldn't retrieve EC point and EC parameters")
204 }
205
206 x, y := elliptic.Unmarshal(pubKey.Curve, pointBytes)
207 if x == nil {
208
209
210
211 var point asn1.RawValue
212 _, err = asn1.Unmarshal(pointBytes, &point)
213 if err != nil {
214 return nil, fmt.Errorf("Failed to unmarshal returned CKA_EC_POINT: %s", err)
215 }
216 if len(point.Bytes) == 0 {
217 return nil, errors.New("Invalid CKA_EC_POINT value returned, OCTET string is empty")
218 }
219 x, y = elliptic.Unmarshal(pubKey.Curve, point.Bytes)
220 if x == nil {
221 return nil, errors.New("Invalid CKA_EC_POINT value returned, point is malformed")
222 }
223 }
224 pubKey.X, pubKey.Y = x, y
225
226 return pubKey, nil
227 }
228
229 type keyType int
230
231 const (
232 RSAKey keyType = iota
233 ECDSAKey
234 )
235
236
237
238 var hashIdentifiers = map[crypto.Hash][]byte{
239 crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
240 crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
241 crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
242 }
243
244 func (s *Session) Sign(object pkcs11.ObjectHandle, keyType keyType, digest []byte, hash crypto.Hash) ([]byte, error) {
245 if len(digest) != hash.Size() {
246 return nil, errors.New("digest length doesn't match hash length")
247 }
248
249 mech := make([]*pkcs11.Mechanism, 1)
250 switch keyType {
251 case RSAKey:
252 mech[0] = pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS, nil)
253 prefix, ok := hashIdentifiers[hash]
254 if !ok {
255 return nil, errors.New("unsupported hash function")
256 }
257 digest = append(prefix, digest...)
258 case ECDSAKey:
259 mech[0] = pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)
260 }
261
262 err := s.Module.SignInit(s.Session, mech, object)
263 if err != nil {
264 return nil, fmt.Errorf("failed to initialize signing operation: %s", err)
265 }
266 signature, err := s.Module.Sign(s.Session, digest)
267 if err != nil {
268 return nil, fmt.Errorf("failed to sign data: %s", err)
269 }
270
271 return signature, nil
272 }
273
274 var ErrNoObject = errors.New("no objects found matching provided template")
275
276
277
278
279 func (s *Session) FindObject(tmpl []*pkcs11.Attribute) (pkcs11.ObjectHandle, error) {
280 err := s.Module.FindObjectsInit(s.Session, tmpl)
281 if err != nil {
282 return 0, err
283 }
284 handles, _, err := s.Module.FindObjects(s.Session, 2)
285 if err != nil {
286 return 0, err
287 }
288 err = s.Module.FindObjectsFinal(s.Session)
289 if err != nil {
290 return 0, err
291 }
292 if len(handles) == 0 {
293 return 0, ErrNoObject
294 }
295 if len(handles) > 1 {
296 return 0, fmt.Errorf("too many objects (%d) that match the provided template", len(handles))
297 }
298 return handles[0], nil
299 }
300
301
302
303
304 type x509Signer struct {
305 session *Session
306 objectHandle pkcs11.ObjectHandle
307 keyType keyType
308
309 pub crypto.PublicKey
310 }
311
312
313
314
315 func (p *x509Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
316 signature, err := p.session.Sign(p.objectHandle, p.keyType, digest, opts.HashFunc())
317 if err != nil {
318 return nil, err
319 }
320
321 if p.keyType == ECDSAKey {
322
323
324 r := big.NewInt(0).SetBytes(signature[:len(signature)/2])
325 s := big.NewInt(0).SetBytes(signature[len(signature)/2:])
326 signature, err = asn1.Marshal(struct {
327 R, S *big.Int
328 }{R: r, S: s})
329 if err != nil {
330 return nil, fmt.Errorf("failed to convert signature to RFC 5480 format: %s", err)
331 }
332 }
333 return signature, nil
334 }
335
336 func (p *x509Signer) Public() crypto.PublicKey {
337 return p.pub
338 }
339
340
341
342 func (s *Session) NewSigner(label string, publicKey crypto.PublicKey) (crypto.Signer, error) {
343 var kt keyType
344 switch publicKey.(type) {
345 case *rsa.PublicKey:
346 kt = RSAKey
347 case *ecdsa.PublicKey:
348 kt = ECDSAKey
349 default:
350 return nil, fmt.Errorf("unsupported public key of type %T", publicKey)
351 }
352
353 publicKeyID, err := s.getPublicKeyID(label, publicKey)
354 if err != nil {
355 return nil, fmt.Errorf("looking up public key: %s", err)
356 }
357
358
359 privateKeyHandle, err := s.getPrivateKey(publicKeyID)
360 if err != nil {
361 return nil, fmt.Errorf("getting private key: %s", err)
362 }
363 return &x509Signer{
364 session: s,
365 objectHandle: privateKeyHandle,
366 keyType: kt,
367 pub: publicKey,
368 }, nil
369 }
370
371 func NewMock() *MockCtx {
372 return &MockCtx{}
373 }
374
375 func NewSessionWithMock() (*Session, *MockCtx) {
376 ctx := NewMock()
377 return &Session{ctx, 0}, ctx
378 }
379
380 type MockCtx struct {
381 GenerateKeyPairFunc func(pkcs11.SessionHandle, []*pkcs11.Mechanism, []*pkcs11.Attribute, []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error)
382 GetAttributeValueFunc func(pkcs11.SessionHandle, pkcs11.ObjectHandle, []*pkcs11.Attribute) ([]*pkcs11.Attribute, error)
383 SignInitFunc func(pkcs11.SessionHandle, []*pkcs11.Mechanism, pkcs11.ObjectHandle) error
384 SignFunc func(pkcs11.SessionHandle, []byte) ([]byte, error)
385 GenerateRandomFunc func(pkcs11.SessionHandle, int) ([]byte, error)
386 FindObjectsInitFunc func(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error
387 FindObjectsFunc func(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error)
388 FindObjectsFinalFunc func(sh pkcs11.SessionHandle) error
389 }
390
391 func (mc MockCtx) GenerateKeyPair(s pkcs11.SessionHandle, m []*pkcs11.Mechanism, a1 []*pkcs11.Attribute, a2 []*pkcs11.Attribute) (pkcs11.ObjectHandle, pkcs11.ObjectHandle, error) {
392 return mc.GenerateKeyPairFunc(s, m, a1, a2)
393 }
394
395 func (mc MockCtx) GetAttributeValue(s pkcs11.SessionHandle, o pkcs11.ObjectHandle, a []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
396 return mc.GetAttributeValueFunc(s, o, a)
397 }
398
399 func (mc MockCtx) SignInit(s pkcs11.SessionHandle, m []*pkcs11.Mechanism, o pkcs11.ObjectHandle) error {
400 return mc.SignInitFunc(s, m, o)
401 }
402
403 func (mc MockCtx) Sign(s pkcs11.SessionHandle, m []byte) ([]byte, error) {
404 return mc.SignFunc(s, m)
405 }
406
407 func (mc MockCtx) GenerateRandom(s pkcs11.SessionHandle, c int) ([]byte, error) {
408 return mc.GenerateRandomFunc(s, c)
409 }
410
411 func (mc MockCtx) FindObjectsInit(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error {
412 return mc.FindObjectsInitFunc(sh, temp)
413 }
414
415 func (mc MockCtx) FindObjects(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error) {
416 return mc.FindObjectsFunc(sh, max)
417 }
418
419 func (mc MockCtx) FindObjectsFinal(sh pkcs11.SessionHandle) error {
420 return mc.FindObjectsFinalFunc(sh)
421 }
422
View as plain text