-
Notifications
You must be signed in to change notification settings - Fork 1
/
token.go
268 lines (237 loc) · 7.41 KB
/
token.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
package main
/*
#include <stdlib.h>
#include <string.h>
#include "pkcs11go.h"
*/
import "C"
import (
"fmt"
"strings"
"sync"
"time"
"unsafe"
)
// Security level constant
type SecurityLevel int
const (
Error SecurityLevel = iota
SecurityOfficer
User
Public
)
// A token of the PKCS11 device.
type Token struct {
sync.Mutex
Label string
Pin string
SoPin string
Objects CryptoObjects
tokenFlags uint64
securityLevel SecurityLevel
loggedIn bool
slot *Slot
}
// Creates a new token, but doesn't store it.
func NewToken(label, userPin, soPin string) (*Token, error) {
if len(label) > 32 {
return nil, NewError("objects.NewToken", "Label with more than 32 chars", C.CKR_ARGUMENTS_BAD)
}
newToken := &Token{
Label: label,
Pin: userPin,
SoPin: soPin,
tokenFlags: C.CKF_RNG |
C.CKF_WRITE_PROTECTED |
C.CKF_LOGIN_REQUIRED |
C.CKF_USER_PIN_INITIALIZED |
C.CKF_TOKEN_INITIALIZED,
Objects: make(CryptoObjects, 0),
}
return newToken, nil
}
// Equals returns true if the token objects are equal.
func (token *Token) Equals(token2 *Token) bool {
return token.Label == token2.Label &&
token.Pin == token2.Pin &&
token.SoPin == token2.SoPin &&
token.Objects.Equals(token2.Objects)
}
func (token *Token) GetInfo(pInfo C.CK_TOKEN_INFO_PTR) error {
if pInfo == nil {
return NewError("token.GetInfo", "got NULL pointer", C.CKR_ARGUMENTS_BAD)
}
info := (*C.CK_TOKEN_INFO)(unsafe.Pointer(pInfo))
C.memset(unsafe.Pointer(&info.label[0]), ' ', 32)
cLabel := C.CBytes([]byte(token.Label))
defer C.free(unsafe.Pointer(cLabel))
C.memcpy(unsafe.Pointer(&info.label[0]), cLabel, C.CK_ULONG(len(token.Label)))
if token.slot == nil {
return NewError("token.GetInfo", "cannot get info: token is not bound to a slot", C.CKR_ARGUMENTS_BAD)
}
manufacturerID := token.slot.Application.Config.Criptoki.ManufacturerID
if len(manufacturerID) > 32 {
manufacturerID = manufacturerID[:32]
}
manufacturerID += strings.Repeat(" ", 32-len(manufacturerID))
cManufacturerID := C.CBytes([]byte(manufacturerID))
defer C.free(unsafe.Pointer(cManufacturerID))
C.memcpy(unsafe.Pointer(&info.manufacturerID[0]), cManufacturerID, 32)
model := token.slot.Application.Config.Criptoki.Model
if len(model) > 16 {
model = model[:16]
}
model += strings.Repeat(" ", 16-len(model))
cModel := C.CBytes([]byte(model))
defer C.free(unsafe.Pointer(cModel))
C.memcpy(unsafe.Pointer(&info.model[0]), cModel, 16)
serialNumber := token.slot.Application.Config.Criptoki.SerialNumber
if len(serialNumber) > 16 {
serialNumber = serialNumber[:16]
}
serialNumber += strings.Repeat(" ", 16-len(serialNumber))
cSerial := C.CBytes([]byte(serialNumber))
defer C.free(unsafe.Pointer(cSerial))
C.memcpy(unsafe.Pointer(&info.serialNumber[0]), cSerial, 16)
info.flags = C.CK_ULONG(token.tokenFlags)
info.ulMaxSessionCount = C.CK_ULONG(token.slot.Application.Config.Criptoki.MaxSessionCount)
info.ulSessionCount = C.CK_UNAVAILABLE_INFORMATION
info.ulMaxRwSessionCount = C.CK_ULONG(token.slot.Application.Config.Criptoki.MaxSessionCount)
info.ulRwSessionCount = C.CK_UNAVAILABLE_INFORMATION
info.ulMaxPinLen = C.CK_ULONG(token.slot.Application.Config.Criptoki.MaxPinLength)
info.ulMinPinLen = C.CK_ULONG(token.slot.Application.Config.Criptoki.MinPinLength)
info.ulTotalPublicMemory = C.CK_UNAVAILABLE_INFORMATION
info.ulFreePublicMemory = C.CK_UNAVAILABLE_INFORMATION
info.ulTotalPrivateMemory = C.CK_UNAVAILABLE_INFORMATION
info.ulFreePrivateMemory = C.CK_UNAVAILABLE_INFORMATION
info.hardwareVersion.major = 2
info.hardwareVersion.minor = 40
info.firmwareVersion.major = 2
info.firmwareVersion.minor = 40
now := time.Now()
cTimeStr := C.CString(now.Format("20060102150405") + "00")
defer C.free(unsafe.Pointer(cTimeStr))
C.memcpy(unsafe.Pointer(&info.utcTime[0]), unsafe.Pointer(cTimeStr), 16)
return nil
}
// Sets the user pin to a new pin.
func (token *Token) SetUserPin(pin string) {
token.Pin = pin
}
// It always returns true
func (token *Token) IsInited() bool {
return true
}
// Gets security level set for the token at Login
func (token *Token) GetSecurityLevel() SecurityLevel {
return token.securityLevel
}
// Checks if the pin provided is the user pin
func (token *Token) CheckUserPin(pin string) (SecurityLevel, error) {
if token.Pin == pin {
return User, nil
} else {
return Error, NewError("token.GetUserPin", "incorrect pin", C.CKR_PIN_INCORRECT)
}
}
// Checks if the pin provided is the SO pin.
func (token *Token) CheckSecurityOfficerPin(pin string) (SecurityLevel, error) {
if token.SoPin == pin {
return User, nil
} else {
return Error, NewError("token.GetUserPin", "incorrect pin", C.CKR_PIN_INCORRECT)
}
}
// Logs into the token, or returns an error if something goes wrong.
func (token *Token) Login(userType C.CK_USER_TYPE, pin string) error {
if token.loggedIn &&
(userType == C.CKU_USER && token.securityLevel == SecurityOfficer) ||
(userType == C.CKU_SO && token.securityLevel == User) {
return NewError("token.Login", "another user already logged in", C.CKR_USER_ALREADY_LOGGED_IN)
}
switch userType {
case C.CKU_SO:
securityLevel, err := token.CheckSecurityOfficerPin(pin)
if err != nil {
return err
}
token.securityLevel = securityLevel
case C.CKU_USER:
securityLevel, err := token.CheckUserPin(pin)
if err != nil {
return err
}
token.securityLevel = securityLevel
case C.CKU_CONTEXT_SPECIFIC:
switch token.securityLevel {
case Public:
return NewError("token.Login", "Bad userType", C.CKR_OPERATION_NOT_INITIALIZED)
case User:
securityLevel, err := token.CheckUserPin(pin)
if err != nil {
return err
}
token.securityLevel = securityLevel
case SecurityOfficer:
securityLevel, err := token.CheckSecurityOfficerPin(pin)
if err != nil {
return err
}
token.securityLevel = securityLevel
}
default:
return NewError("token.Login", "Bad userType", C.CKR_USER_TYPE_INVALID)
}
token.loggedIn = true
return nil
}
// Logs out from the token.
func (token *Token) Logout() {
token.securityLevel = Public
token.loggedIn = false
}
// Adds a cryptoObject to the token
func (token *Token) AddObject(object *CryptoObject) {
token.Lock()
defer token.Unlock()
token.Objects = append(token.Objects, object)
}
// Returns the label of the token (should remove. Label is a public property!
func (token *Token) GetLabel() string {
return token.Label
}
// Returns an object that uses the handle provided.
func (token *Token) GetObject(handle C.CK_OBJECT_HANDLE) (*CryptoObject, error) {
token.Lock()
defer token.Unlock()
for _, object := range token.Objects {
if object.Handle == handle {
return object, nil
}
}
return nil, NewError("Token.GetObject", fmt.Sprintf("object not found with id %v", handle), C.CKR_OBJECT_HANDLE_INVALID)
}
// Deletes an object from its list, but doesn't save it.
func (token *Token) DeleteObject(handle C.CK_OBJECT_HANDLE) error {
token.Lock()
defer token.Unlock()
objPos := -1
for i, object := range token.Objects {
if object.Handle == handle {
objPos = i
break
}
}
if objPos == -1 {
return NewError("Token.DeleteObject", fmt.Sprintf("object not found with id %v", handle), C.CKR_OBJECT_HANDLE_INVALID)
}
token.Objects = append(token.Objects[:objPos], token.Objects[objPos+1:]...)
return nil
}
// Copies the state of a token
func (token *Token) CopyState(token2 *Token) {
token.Pin = token2.Pin
token.securityLevel = token2.securityLevel
token.loggedIn = token2.loggedIn
token.SoPin = token2.SoPin
}