1 package p11
2
3 import (
4 "errors"
5 "sync"
6
7 "github.com/miekg/pkcs11"
8 )
9
10
11 var ErrNoObjectsFound = errors.New("no objects found")
12
13
14 var ErrTooManyObjectsFound = errors.New("too many objects matching template")
15
16
17 type Session interface {
18
19
20
21
22
23
24
25
26
27 Login(pin string) error
28
29 LoginSecurityOfficer(pin string) error
30
31 LoginAs(userType uint, pin string) error
32
33 Logout() error
34
35 Close() error
36
37
38 CreateObject(template []*pkcs11.Attribute) (Object, error)
39
40
41
42 FindObject(template []*pkcs11.Attribute) (Object, error)
43
44 FindObjects(template []*pkcs11.Attribute) ([]Object, error)
45
46
47
48 GenerateKeyPair(request GenerateKeyPairRequest) (*KeyPair, error)
49
50 GenerateRandom(length int) ([]byte, error)
51
52
53 InitPIN(pin string) error
54
55
56 SetPIN(old, new string) error
57 }
58
59 type sessionImpl struct {
60 sync.Mutex
61 ctx *pkcs11.Ctx
62 handle pkcs11.SessionHandle
63 }
64
65 func (s *sessionImpl) FindPrivateKey(label string) (PrivateKey, error) {
66 obj, err := s.findObjectWithClassAndLabel(pkcs11.CKO_PRIVATE_KEY, label)
67 if err != nil {
68 return PrivateKey(obj), err
69 }
70 return PrivateKey(obj), nil
71 }
72
73 func (s *sessionImpl) FindPublicKey(label string) (PublicKey, error) {
74 obj, err := s.findObjectWithClassAndLabel(pkcs11.CKO_PUBLIC_KEY, label)
75 if err != nil {
76 return PublicKey(obj), err
77 }
78 return PublicKey(obj), nil
79 }
80
81 func (s *sessionImpl) FindSecretKey(label string) (SecretKey, error) {
82 obj, err := s.findObjectWithClassAndLabel(pkcs11.CKO_SECRET_KEY, label)
83 if err != nil {
84 return SecretKey(obj), err
85 }
86 return SecretKey(obj), nil
87 }
88
89 func (s *sessionImpl) findObjectWithClassAndLabel(class uint, label string) (Object, error) {
90 return s.FindObject([]*pkcs11.Attribute{
91 pkcs11.NewAttribute(pkcs11.CKA_CLASS, class),
92 pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
93 })
94 }
95
96 func (s *sessionImpl) FindObject(template []*pkcs11.Attribute) (Object, error) {
97 objects, err := s.FindObjects(template)
98 if err != nil {
99 return Object{}, err
100 }
101 if len(objects) > 1 {
102 return Object{}, ErrTooManyObjectsFound
103 }
104 return objects[0], nil
105 }
106
107 func (s *sessionImpl) FindObjects(template []*pkcs11.Attribute) ([]Object, error) {
108 s.Lock()
109 defer s.Unlock()
110 if err := s.ctx.FindObjectsInit(s.handle, template); err != nil {
111 return nil, err
112 }
113
114 var results []Object
115 for {
116 objectHandles, _, err := s.ctx.FindObjects(s.handle, 100)
117 if err != nil {
118 _ = s.ctx.FindObjectsFinal(s.handle)
119 return nil, err
120 } else if len(objectHandles) == 0 {
121 break
122 }
123 i := len(results)
124 results = append(results, make([]Object, len(objectHandles))...)
125 for j, objectHandle := range objectHandles {
126 results[i+j] = Object{
127 session: s,
128 objectHandle: objectHandle,
129 }
130 }
131 }
132 if err := s.ctx.FindObjectsFinal(s.handle); err != nil {
133 return nil, err
134 } else if len(results) == 0 {
135 return nil, ErrNoObjectsFound
136 }
137 return results, nil
138 }
139
140 func (s *sessionImpl) Close() error {
141 s.Lock()
142 defer s.Unlock()
143 return s.ctx.CloseSession(s.handle)
144 }
145
146 func (s *sessionImpl) Login(pin string) error {
147 return s.LoginAs(pkcs11.CKU_USER, pin)
148 }
149
150 func (s *sessionImpl) LoginSecurityOfficer(pin string) error {
151 return s.LoginAs(pkcs11.CKU_SO, pin)
152 }
153
154 func (s *sessionImpl) LoginAs(userType uint, pin string) error {
155 s.Lock()
156 defer s.Unlock()
157 return s.ctx.Login(s.handle, userType, pin)
158 }
159
160 func (s *sessionImpl) Logout() error {
161 s.Lock()
162 defer s.Unlock()
163 return s.ctx.Logout(s.handle)
164 }
165
166 func (s *sessionImpl) GenerateRandom(length int) ([]byte, error) {
167 s.Lock()
168 defer s.Unlock()
169 return s.ctx.GenerateRandom(s.handle, length)
170 }
171
172 func (s *sessionImpl) CreateObject(template []*pkcs11.Attribute) (Object, error) {
173 s.Lock()
174 defer s.Unlock()
175 oh, err := s.ctx.CreateObject(s.handle, template)
176 if err != nil {
177 return Object{}, err
178 }
179 return Object{
180 session: s,
181 objectHandle: oh,
182 }, nil
183 }
184
185 func (s *sessionImpl) InitPIN(pin string) error {
186 s.Lock()
187 defer s.Unlock()
188 return s.ctx.InitPIN(s.handle, pin)
189 }
190
191 func (s *sessionImpl) SetPIN(old, new string) error {
192 s.Lock()
193 defer s.Unlock()
194 return s.ctx.SetPIN(s.handle, old, new)
195 }
196
197
198
199
200 type KeyPair struct {
201 Public PublicKey
202 Private PrivateKey
203 }
204
205
206 type GenerateKeyPairRequest struct {
207 Mechanism pkcs11.Mechanism
208 PublicKeyAttributes []*pkcs11.Attribute
209 PrivateKeyAttributes []*pkcs11.Attribute
210 }
211
212 func (s *sessionImpl) GenerateKeyPair(request GenerateKeyPairRequest) (*KeyPair, error) {
213 s.Lock()
214 defer s.Unlock()
215 pubHandle, privHandle, err := s.ctx.GenerateKeyPair(s.handle,
216 []*pkcs11.Mechanism{&request.Mechanism},
217 request.PublicKeyAttributes,
218 request.PrivateKeyAttributes)
219 if err != nil {
220 return nil, err
221 }
222 return &KeyPair{
223 Public: PublicKey(Object{
224 session: s,
225 objectHandle: pubHandle,
226 }),
227 Private: PrivateKey(Object{
228 session: s,
229 objectHandle: privHandle,
230 }),
231 }, nil
232 }
233
View as plain text