1// Copyright 2013 Miek Gieben. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package pkcs11 6 7/* 8#include <stdlib.h> 9#include <string.h> 10#include "pkcs11go.h" 11 12CK_ULONG Index(CK_ULONG_PTR array, CK_ULONG i) 13{ 14 return array[i]; 15} 16 17static inline void putAttributePval(CK_ATTRIBUTE_PTR a, CK_VOID_PTR pValue) 18{ 19 a->pValue = pValue; 20} 21 22static inline void putMechanismParam(CK_MECHANISM_PTR m, CK_VOID_PTR pParameter) 23{ 24 m->pParameter = pParameter; 25} 26*/ 27import "C" 28 29import ( 30 "fmt" 31 "time" 32 "unsafe" 33) 34 35type arena []unsafe.Pointer 36 37func (a *arena) Allocate(obj []byte) (C.CK_VOID_PTR, C.CK_ULONG) { 38 cobj := C.calloc(C.size_t(len(obj)), 1) 39 *a = append(*a, cobj) 40 C.memmove(cobj, unsafe.Pointer(&obj[0]), C.size_t(len(obj))) 41 return C.CK_VOID_PTR(cobj), C.CK_ULONG(len(obj)) 42} 43 44func (a arena) Free() { 45 for _, p := range a { 46 C.free(p) 47 } 48} 49 50// toList converts from a C style array to a []uint. 51func toList(clist C.CK_ULONG_PTR, size C.CK_ULONG) []uint { 52 l := make([]uint, int(size)) 53 for i := 0; i < len(l); i++ { 54 l[i] = uint(C.Index(clist, C.CK_ULONG(i))) 55 } 56 defer C.free(unsafe.Pointer(clist)) 57 return l 58} 59 60// cBBool converts a bool to a CK_BBOOL. 61func cBBool(x bool) C.CK_BBOOL { 62 if x { 63 return C.CK_BBOOL(C.CK_TRUE) 64 } 65 return C.CK_BBOOL(C.CK_FALSE) 66} 67 68func uintToBytes(x uint64) []byte { 69 ul := C.CK_ULONG(x) 70 return C.GoBytes(unsafe.Pointer(&ul), C.int(unsafe.Sizeof(ul))) 71} 72 73// Error represents an PKCS#11 error. 74type Error uint 75 76func (e Error) Error() string { 77 return fmt.Sprintf("pkcs11: 0x%X: %s", uint(e), strerror[uint(e)]) 78} 79 80func toError(e C.CK_RV) error { 81 if e == C.CKR_OK { 82 return nil 83 } 84 return Error(e) 85} 86 87// SessionHandle is a Cryptoki-assigned value that identifies a session. 88type SessionHandle uint 89 90// ObjectHandle is a token-specific identifier for an object. 91type ObjectHandle uint 92 93// Version represents any version information from the library. 94type Version struct { 95 Major byte 96 Minor byte 97} 98 99func toVersion(version C.CK_VERSION) Version { 100 return Version{byte(version.major), byte(version.minor)} 101} 102 103// SlotEvent holds the SlotID which for which an slot event (token insertion, 104// removal, etc.) occurred. 105type SlotEvent struct { 106 SlotID uint 107} 108 109// Info provides information about the library and hardware used. 110type Info struct { 111 CryptokiVersion Version 112 ManufacturerID string 113 Flags uint 114 LibraryDescription string 115 LibraryVersion Version 116} 117 118// SlotInfo provides information about a slot. 119type SlotInfo struct { 120 SlotDescription string // 64 bytes. 121 ManufacturerID string // 32 bytes. 122 Flags uint 123 HardwareVersion Version 124 FirmwareVersion Version 125} 126 127// TokenInfo provides information about a token. 128type TokenInfo struct { 129 Label string 130 ManufacturerID string 131 Model string 132 SerialNumber string 133 Flags uint 134 MaxSessionCount uint 135 SessionCount uint 136 MaxRwSessionCount uint 137 RwSessionCount uint 138 MaxPinLen uint 139 MinPinLen uint 140 TotalPublicMemory uint 141 FreePublicMemory uint 142 TotalPrivateMemory uint 143 FreePrivateMemory uint 144 HardwareVersion Version 145 FirmwareVersion Version 146 UTCTime string 147} 148 149// SessionInfo provides information about a session. 150type SessionInfo struct { 151 SlotID uint 152 State uint 153 Flags uint 154 DeviceError uint 155} 156 157// Attribute holds an attribute type/value combination. 158type Attribute struct { 159 Type uint 160 Value []byte 161} 162 163// NewAttribute allocates a Attribute and returns a pointer to it. 164// Note that this is merely a convenience function, as values returned 165// from the HSM are not converted back to Go values, those are just raw 166// byte slices. 167func NewAttribute(typ uint, x interface{}) *Attribute { 168 // This function nicely transforms *to* an attribute, but there is 169 // no corresponding function that transform back *from* an attribute, 170 // which in PKCS#11 is just an byte array. 171 a := new(Attribute) 172 a.Type = typ 173 if x == nil { 174 return a 175 } 176 switch v := x.(type) { 177 case bool: 178 if v { 179 a.Value = []byte{1} 180 } else { 181 a.Value = []byte{0} 182 } 183 case int: 184 a.Value = uintToBytes(uint64(v)) 185 case uint: 186 a.Value = uintToBytes(uint64(v)) 187 case string: 188 a.Value = []byte(v) 189 case []byte: 190 a.Value = v 191 case time.Time: // for CKA_DATE 192 a.Value = cDate(v) 193 default: 194 panic("pkcs11: unhandled attribute type") 195 } 196 return a 197} 198 199// cAttribute returns the start address and the length of an attribute list. 200func cAttributeList(a []*Attribute) (arena, C.CK_ATTRIBUTE_PTR, C.CK_ULONG) { 201 var arena arena 202 if len(a) == 0 { 203 return nil, nil, 0 204 } 205 pa := make([]C.CK_ATTRIBUTE, len(a)) 206 for i, attr := range a { 207 pa[i]._type = C.CK_ATTRIBUTE_TYPE(attr.Type) 208 if len(attr.Value) != 0 { 209 buf, len := arena.Allocate(attr.Value) 210 // field is unaligned on windows so this has to call into C 211 C.putAttributePval(&pa[i], buf) 212 pa[i].ulValueLen = len 213 } 214 } 215 return arena, &pa[0], C.CK_ULONG(len(a)) 216} 217 218func cDate(t time.Time) []byte { 219 b := make([]byte, 8) 220 year, month, day := t.Date() 221 y := fmt.Sprintf("%4d", year) 222 m := fmt.Sprintf("%02d", month) 223 d1 := fmt.Sprintf("%02d", day) 224 b[0], b[1], b[2], b[3] = y[0], y[1], y[2], y[3] 225 b[4], b[5] = m[0], m[1] 226 b[6], b[7] = d1[0], d1[1] 227 return b 228} 229 230// Mechanism holds an mechanism type/value combination. 231type Mechanism struct { 232 Mechanism uint 233 Parameter []byte 234 generator interface{} 235} 236 237// NewMechanism returns a pointer to an initialized Mechanism. 238func NewMechanism(mech uint, x interface{}) *Mechanism { 239 m := new(Mechanism) 240 m.Mechanism = mech 241 if x == nil { 242 return m 243 } 244 245 switch p := x.(type) { 246 case *GCMParams, *OAEPParams, *ECDH1DeriveParams: 247 // contains pointers; defer serialization until cMechanism 248 m.generator = p 249 case []byte: 250 m.Parameter = p 251 default: 252 panic("parameter must be one of type: []byte, *GCMParams, *OAEPParams, *ECDH1DeriveParams") 253 } 254 255 return m 256} 257 258func cMechanism(mechList []*Mechanism) (arena, *C.CK_MECHANISM) { 259 if len(mechList) != 1 { 260 panic("expected exactly one mechanism") 261 } 262 mech := mechList[0] 263 cmech := &C.CK_MECHANISM{mechanism: C.CK_MECHANISM_TYPE(mech.Mechanism)} 264 // params that contain pointers are allocated here 265 param := mech.Parameter 266 var arena arena 267 switch p := mech.generator.(type) { 268 case *GCMParams: 269 // uses its own arena because it has to outlive this function call (yuck) 270 param = cGCMParams(p) 271 case *OAEPParams: 272 param, arena = cOAEPParams(p, arena) 273 case *ECDH1DeriveParams: 274 param, arena = cECDH1DeriveParams(p, arena) 275 } 276 if len(param) != 0 { 277 buf, len := arena.Allocate(param) 278 // field is unaligned on windows so this has to call into C 279 C.putMechanismParam(cmech, buf) 280 cmech.ulParameterLen = len 281 } 282 return arena, cmech 283} 284 285// MechanismInfo provides information about a particular mechanism. 286type MechanismInfo struct { 287 MinKeySize uint 288 MaxKeySize uint 289 Flags uint 290} 291 292// stubData is a persistent nonempty byte array used by cMessage. 293var stubData = []byte{0} 294 295// cMessage returns the pointer/length pair corresponding to data. 296func cMessage(data []byte) (dataPtr C.CK_BYTE_PTR) { 297 l := len(data) 298 if l == 0 { 299 // &data[0] is forbidden in this case, so use a nontrivial array instead. 300 data = stubData 301 } 302 return C.CK_BYTE_PTR(unsafe.Pointer(&data[0])) 303} 304