// Copyright 2013 Miek Gieben. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package pkcs11 is a wrapper around the PKCS#11 cryptographic library. package pkcs11 // It is *assumed*, that: // // * Go's uint size == PKCS11's CK_ULONG size // * CK_ULONG never overflows an Go int /* #cgo windows CFLAGS: -DPACKED_STRUCTURES #cgo linux LDFLAGS: -ldl #cgo darwin LDFLAGS: -ldl #cgo openbsd LDFLAGS: -ldl #cgo freebsd LDFLAGS: -ldl #include #include #include #include #include "pkcs11go.h" #ifdef _WIN32 #include struct ctx { HMODULE handle; CK_FUNCTION_LIST_PTR sym; }; // New initializes a ctx and fills the symbol table. struct ctx *New(const char *module) { CK_C_GetFunctionList list; struct ctx *c = calloc(1, sizeof(struct ctx)); c->handle = LoadLibrary(module); if (c->handle == NULL) { free(c); return NULL; } list = (CK_C_GetFunctionList) GetProcAddress(c->handle, "C_GetFunctionList"); if (list == NULL) { free(c); return NULL; } list(&c->sym); return c; } // Destroy cleans up a ctx. void Destroy(struct ctx *c) { if (!c) { return; } free(c); } #else #include struct ctx { void *handle; CK_FUNCTION_LIST_PTR sym; }; // New initializes a ctx and fills the symbol table. struct ctx *New(const char *module) { CK_C_GetFunctionList list; struct ctx *c = calloc(1, sizeof(struct ctx)); c->handle = dlopen(module, RTLD_LAZY); if (c->handle == NULL) { free(c); return NULL; } list = (CK_C_GetFunctionList) dlsym(c->handle, "C_GetFunctionList"); if (list == NULL) { free(c); return NULL; } list(&c->sym); return c; } // Destroy cleans up a ctx. void Destroy(struct ctx *c) { if (!c) { return; } if (c->handle == NULL) { return; } if (dlclose(c->handle) < 0) { return; } free(c); } #endif CK_RV Initialize(struct ctx * c) { CK_C_INITIALIZE_ARGS args; memset(&args, 0, sizeof(args)); args.flags = CKF_OS_LOCKING_OK; return c->sym->C_Initialize(&args); } CK_RV Finalize(struct ctx * c) { return c->sym->C_Finalize(NULL); } CK_RV GetInfo(struct ctx * c, ckInfoPtr info) { CK_INFO p; CK_RV e = c->sym->C_GetInfo(&p); if (e != CKR_OK) { return e; } info->cryptokiVersion = p.cryptokiVersion; memcpy(info->manufacturerID, p.manufacturerID, sizeof(p.manufacturerID)); info->flags = p.flags; memcpy(info->libraryDescription, p.libraryDescription, sizeof(p.libraryDescription)); info->libraryVersion = p.libraryVersion; return e; } CK_RV GetSlotList(struct ctx * c, CK_BBOOL tokenPresent, CK_ULONG_PTR * slotList, CK_ULONG_PTR ulCount) { CK_RV e = c->sym->C_GetSlotList(tokenPresent, NULL, ulCount); if (e != CKR_OK) { return e; } *slotList = calloc(*ulCount, sizeof(CK_SLOT_ID)); e = c->sym->C_GetSlotList(tokenPresent, *slotList, ulCount); return e; } CK_RV GetSlotInfo(struct ctx * c, CK_ULONG slotID, CK_SLOT_INFO_PTR info) { CK_RV e = c->sym->C_GetSlotInfo((CK_SLOT_ID) slotID, info); return e; } CK_RV GetTokenInfo(struct ctx * c, CK_ULONG slotID, CK_TOKEN_INFO_PTR info) { CK_RV e = c->sym->C_GetTokenInfo((CK_SLOT_ID) slotID, info); return e; } CK_RV GetMechanismList(struct ctx * c, CK_ULONG slotID, CK_ULONG_PTR * mech, CK_ULONG_PTR mechlen) { CK_RV e = c->sym->C_GetMechanismList((CK_SLOT_ID) slotID, NULL, mechlen); // Gemaltos PKCS11 implementation returns CKR_BUFFER_TOO_SMALL on a NULL ptr instad of CKR_OK as the spec states. if (e != CKR_OK && e != CKR_BUFFER_TOO_SMALL) { return e; } *mech = calloc(*mechlen, sizeof(CK_MECHANISM_TYPE)); e = c->sym->C_GetMechanismList((CK_SLOT_ID) slotID, (CK_MECHANISM_TYPE_PTR) * mech, mechlen); return e; } CK_RV GetMechanismInfo(struct ctx * c, CK_ULONG slotID, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR info) { CK_RV e = c->sym->C_GetMechanismInfo((CK_SLOT_ID) slotID, mech, info); return e; } CK_RV InitToken(struct ctx * c, CK_ULONG slotID, char *pin, CK_ULONG pinlen, char *label) { CK_RV e = c->sym->C_InitToken((CK_SLOT_ID) slotID, (CK_UTF8CHAR_PTR) pin, pinlen, (CK_UTF8CHAR_PTR) label); return e; } CK_RV InitPIN(struct ctx * c, CK_SESSION_HANDLE sh, char *pin, CK_ULONG pinlen) { CK_RV e = c->sym->C_InitPIN(sh, (CK_UTF8CHAR_PTR) pin, pinlen); return e; } CK_RV SetPIN(struct ctx * c, CK_SESSION_HANDLE sh, char *oldpin, CK_ULONG oldpinlen, char *newpin, CK_ULONG newpinlen) { CK_RV e = c->sym->C_SetPIN(sh, (CK_UTF8CHAR_PTR) oldpin, oldpinlen, (CK_UTF8CHAR_PTR) newpin, newpinlen); return e; } CK_RV OpenSession(struct ctx * c, CK_ULONG slotID, CK_ULONG flags, CK_SESSION_HANDLE_PTR session) { CK_RV e = c->sym->C_OpenSession((CK_SLOT_ID) slotID, (CK_FLAGS) flags, NULL, NULL, session); return e; } CK_RV CloseSession(struct ctx * c, CK_SESSION_HANDLE session) { CK_RV e = c->sym->C_CloseSession(session); return e; } CK_RV CloseAllSessions(struct ctx * c, CK_ULONG slotID) { CK_RV e = c->sym->C_CloseAllSessions(slotID); return e; } CK_RV GetSessionInfo(struct ctx * c, CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info) { CK_RV e = c->sym->C_GetSessionInfo(session, info); return e; } CK_RV GetOperationState(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR * state, CK_ULONG_PTR statelen) { CK_RV rv = c->sym->C_GetOperationState(session, NULL, statelen); if (rv != CKR_OK) { return rv; } *state = calloc(*statelen, sizeof(CK_BYTE)); if (*state == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_GetOperationState(session, *state, statelen); return rv; } CK_RV SetOperationState(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR state, CK_ULONG statelen, CK_OBJECT_HANDLE encryptkey, CK_OBJECT_HANDLE authkey) { return c->sym->C_SetOperationState(session, state, statelen, encryptkey, authkey); } CK_RV Login(struct ctx *c, CK_SESSION_HANDLE session, CK_USER_TYPE userType, char *pin, CK_ULONG pinLen) { if (pinLen == 0) { pin = NULL; } CK_RV e = c->sym->C_Login(session, userType, (CK_UTF8CHAR_PTR) pin, pinLen); return e; } CK_RV Logout(struct ctx * c, CK_SESSION_HANDLE session) { CK_RV e = c->sym->C_Logout(session); return e; } CK_RV CreateObject(struct ctx * c, CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR temp, CK_ULONG tempCount, CK_OBJECT_HANDLE_PTR obj) { return c->sym->C_CreateObject(session, temp, tempCount, obj); } CK_RV CopyObject(struct ctx * c, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE o, CK_ATTRIBUTE_PTR temp, CK_ULONG tempCount, CK_OBJECT_HANDLE_PTR obj) { return c->sym->C_CopyObject(session, o, temp, tempCount, obj); } CK_RV DestroyObject(struct ctx * c, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) { CK_RV e = c->sym->C_DestroyObject(session, object); return e; } CK_RV GetObjectSize(struct ctx * c, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ULONG_PTR size) { CK_RV e = c->sym->C_GetObjectSize(session, object, size); return e; } CK_RV GetAttributeValue(struct ctx * c, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR temp, CK_ULONG templen) { // Call for the first time, check the returned ulValue in the attributes, then // allocate enough space and try again. CK_RV e = c->sym->C_GetAttributeValue(session, object, temp, templen); if (e != CKR_OK) { return e; } CK_ULONG i; for (i = 0; i < templen; i++) { if ((CK_LONG) temp[i].ulValueLen == -1) { // either access denied or no such object continue; } temp[i].pValue = calloc(temp[i].ulValueLen, sizeof(CK_BYTE)); } return c->sym->C_GetAttributeValue(session, object, temp, templen); } CK_RV SetAttributeValue(struct ctx * c, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR temp, CK_ULONG templen) { return c->sym->C_SetAttributeValue(session, object, temp, templen); } CK_RV FindObjectsInit(struct ctx * c, CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR temp, CK_ULONG tempCount) { return c->sym->C_FindObjectsInit(session, temp, tempCount); } CK_RV FindObjects(struct ctx * c, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR * obj, CK_ULONG max, CK_ULONG_PTR objCount) { *obj = calloc(max, sizeof(CK_OBJECT_HANDLE)); CK_RV e = c->sym->C_FindObjects(session, *obj, max, objCount); return e; } CK_RV FindObjectsFinal(struct ctx * c, CK_SESSION_HANDLE session) { CK_RV e = c->sym->C_FindObjectsFinal(session); return e; } CK_RV EncryptInit(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return c->sym->C_EncryptInit(session, mechanism, key); } CK_RV Encrypt(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR message, CK_ULONG mlen, CK_BYTE_PTR * enc, CK_ULONG_PTR enclen) { CK_RV rv = c->sym->C_Encrypt(session, message, mlen, NULL, enclen); if (rv != CKR_OK) { return rv; } *enc = calloc(*enclen, sizeof(CK_BYTE)); if (*enc == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_Encrypt(session, message, mlen, *enc, enclen); return rv; } CK_RV EncryptUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR plain, CK_ULONG plainlen, CK_BYTE_PTR * cipher, CK_ULONG_PTR cipherlen) { CK_RV rv = c->sym->C_EncryptUpdate(session, plain, plainlen, NULL, cipherlen); if (rv != CKR_OK) { return rv; } *cipher = calloc(*cipherlen, sizeof(CK_BYTE)); if (*cipher == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_EncryptUpdate(session, plain, plainlen, *cipher, cipherlen); return rv; } CK_RV EncryptFinal(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR * cipher, CK_ULONG_PTR cipherlen) { CK_RV rv = c->sym->C_EncryptFinal(session, NULL, cipherlen); if (rv != CKR_OK) { return rv; } *cipher = calloc(*cipherlen, sizeof(CK_BYTE)); if (*cipher == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_EncryptFinal(session, *cipher, cipherlen); return rv; } CK_RV DecryptInit(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return c->sym->C_DecryptInit(session, mechanism, key); } CK_RV Decrypt(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR cipher, CK_ULONG clen, CK_BYTE_PTR * plain, CK_ULONG_PTR plainlen) { CK_RV e = c->sym->C_Decrypt(session, cipher, clen, NULL, plainlen); if (e != CKR_OK) { return e; } *plain = calloc(*plainlen, sizeof(CK_BYTE)); if (*plain == NULL) { return CKR_HOST_MEMORY; } e = c->sym->C_Decrypt(session, cipher, clen, *plain, plainlen); return e; } CK_RV DecryptUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR cipher, CK_ULONG cipherlen, CK_BYTE_PTR * part, CK_ULONG_PTR partlen) { CK_RV rv = c->sym->C_DecryptUpdate(session, cipher, cipherlen, NULL, partlen); if (rv != CKR_OK) { return rv; } *part = calloc(*partlen, sizeof(CK_BYTE)); if (*part == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_DecryptUpdate(session, cipher, cipherlen, *part, partlen); return rv; } CK_RV DecryptFinal(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR * plain, CK_ULONG_PTR plainlen) { CK_RV rv = c->sym->C_DecryptFinal(session, NULL, plainlen); if (rv != CKR_OK) { return rv; } *plain = calloc(*plainlen, sizeof(CK_BYTE)); if (*plain == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_DecryptFinal(session, *plain, plainlen); return rv; } CK_RV DigestInit(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism) { return c->sym->C_DigestInit(session, mechanism); } CK_RV Digest(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR message, CK_ULONG mlen, CK_BYTE_PTR * hash, CK_ULONG_PTR hashlen) { CK_RV rv = c->sym->C_Digest(session, message, mlen, NULL, hashlen); if (rv != CKR_OK) { return rv; } *hash = calloc(*hashlen, sizeof(CK_BYTE)); if (*hash == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_Digest(session, message, mlen, *hash, hashlen); return rv; } CK_RV DigestUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR message, CK_ULONG mlen) { CK_RV rv = c->sym->C_DigestUpdate(session, message, mlen); return rv; } CK_RV DigestKey(struct ctx * c, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) { CK_RV rv = c->sym->C_DigestKey(session, key); return rv; } CK_RV DigestFinal(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR * hash, CK_ULONG_PTR hashlen) { CK_RV rv = c->sym->C_DigestFinal(session, NULL, hashlen); if (rv != CKR_OK) { return rv; } *hash = calloc(*hashlen, sizeof(CK_BYTE)); if (*hash == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_DigestFinal(session, *hash, hashlen); return rv; } CK_RV SignInit(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return c->sym->C_SignInit(session, mechanism, key); } CK_RV Sign(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR message, CK_ULONG mlen, CK_BYTE_PTR * sig, CK_ULONG_PTR siglen) { CK_RV rv = c->sym->C_Sign(session, message, mlen, NULL, siglen); if (rv != CKR_OK) { return rv; } *sig = calloc(*siglen, sizeof(CK_BYTE)); if (*sig == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_Sign(session, message, mlen, *sig, siglen); return rv; } CK_RV SignUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR message, CK_ULONG mlen) { CK_RV rv = c->sym->C_SignUpdate(session, message, mlen); return rv; } CK_RV SignFinal(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR * sig, CK_ULONG_PTR siglen) { CK_RV rv = c->sym->C_SignFinal(session, NULL, siglen); if (rv != CKR_OK) { return rv; } *sig = calloc(*siglen, sizeof(CK_BYTE)); if (*sig == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_SignFinal(session, *sig, siglen); return rv; } CK_RV SignRecoverInit(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return c->sym->C_SignRecoverInit(session, mechanism, key); } CK_RV SignRecover(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG datalen, CK_BYTE_PTR * sig, CK_ULONG_PTR siglen) { CK_RV rv = c->sym->C_SignRecover(session, data, datalen, NULL, siglen); if (rv != CKR_OK) { return rv; } *sig = calloc(*siglen, sizeof(CK_BYTE)); if (*sig == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_SignRecover(session, data, datalen, *sig, siglen); return rv; } CK_RV VerifyInit(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return c->sym->C_VerifyInit(session, mechanism, key); } CK_RV Verify(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR message, CK_ULONG mesglen, CK_BYTE_PTR sig, CK_ULONG siglen) { CK_RV rv = c->sym->C_Verify(session, message, mesglen, sig, siglen); return rv; } CK_RV VerifyUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG partlen) { CK_RV rv = c->sym->C_VerifyUpdate(session, part, partlen); return rv; } CK_RV VerifyFinal(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR sig, CK_ULONG siglen) { CK_RV rv = c->sym->C_VerifyFinal(session, sig, siglen); return rv; } CK_RV VerifyRecoverInit(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return c->sym->C_VerifyRecoverInit(session, mechanism, key); } CK_RV VerifyRecover(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR sig, CK_ULONG siglen, CK_BYTE_PTR * data, CK_ULONG_PTR datalen) { CK_RV rv = c->sym->C_VerifyRecover(session, sig, siglen, NULL, datalen); if (rv != CKR_OK) { return rv; } *data = calloc(*datalen, sizeof(CK_BYTE)); if (*data == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_VerifyRecover(session, sig, siglen, *data, datalen); return rv; } CK_RV DigestEncryptUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG partlen, CK_BYTE_PTR * enc, CK_ULONG_PTR enclen) { CK_RV rv = c->sym->C_DigestEncryptUpdate(session, part, partlen, NULL, enclen); if (rv != CKR_OK) { return rv; } *enc = calloc(*enclen, sizeof(CK_BYTE)); if (*enc == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_DigestEncryptUpdate(session, part, partlen, *enc, enclen); return rv; } CK_RV DecryptDigestUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR cipher, CK_ULONG cipherlen, CK_BYTE_PTR * part, CK_ULONG_PTR partlen) { CK_RV rv = c->sym->C_DecryptDigestUpdate(session, cipher, cipherlen, NULL, partlen); if (rv != CKR_OK) { return rv; } *part = calloc(*partlen, sizeof(CK_BYTE)); if (*part == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_DecryptDigestUpdate(session, cipher, cipherlen, *part, partlen); return rv; } CK_RV SignEncryptUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG partlen, CK_BYTE_PTR * enc, CK_ULONG_PTR enclen) { CK_RV rv = c->sym->C_SignEncryptUpdate(session, part, partlen, NULL, enclen); if (rv != CKR_OK) { return rv; } *enc = calloc(*enclen, sizeof(CK_BYTE)); if (*enc == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_SignEncryptUpdate(session, part, partlen, *enc, enclen); return rv; } CK_RV DecryptVerifyUpdate(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR cipher, CK_ULONG cipherlen, CK_BYTE_PTR * part, CK_ULONG_PTR partlen) { CK_RV rv = c->sym->C_DecryptVerifyUpdate(session, cipher, cipherlen, NULL, partlen); if (rv != CKR_OK) { return rv; } *part = calloc(*partlen, sizeof(CK_BYTE)); if (*part == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_DecryptVerifyUpdate(session, cipher, cipherlen, *part, partlen); return rv; } CK_RV GenerateKey(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_ATTRIBUTE_PTR temp, CK_ULONG tempCount, CK_OBJECT_HANDLE_PTR key) { return c->sym->C_GenerateKey(session, mechanism, temp, tempCount, key); } CK_RV GenerateKeyPair(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_ATTRIBUTE_PTR pub, CK_ULONG pubCount, CK_ATTRIBUTE_PTR priv, CK_ULONG privCount, CK_OBJECT_HANDLE_PTR pubkey, CK_OBJECT_HANDLE_PTR privkey) { return c->sym->C_GenerateKeyPair(session, mechanism, pub, pubCount, priv, privCount, pubkey, privkey); } CK_RV WrapKey(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE wrappingkey, CK_OBJECT_HANDLE key, CK_BYTE_PTR * wrapped, CK_ULONG_PTR wrappedlen) { CK_RV rv = c->sym->C_WrapKey(session, mechanism, wrappingkey, key, NULL, wrappedlen); if (rv != CKR_OK) { return rv; } *wrapped = calloc(*wrappedlen, sizeof(CK_BYTE)); if (*wrapped == NULL) { return CKR_HOST_MEMORY; } rv = c->sym->C_WrapKey(session, mechanism, wrappingkey, key, *wrapped, wrappedlen); return rv; } CK_RV DeriveKey(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE basekey, CK_ATTRIBUTE_PTR a, CK_ULONG alen, CK_OBJECT_HANDLE_PTR key) { return c->sym->C_DeriveKey(session, mechanism, basekey, a, alen, key); } CK_RV UnwrapKey(struct ctx * c, CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE unwrappingkey, CK_BYTE_PTR wrappedkey, CK_ULONG wrappedkeylen, CK_ATTRIBUTE_PTR a, CK_ULONG alen, CK_OBJECT_HANDLE_PTR key) { return c->sym->C_UnwrapKey(session, mechanism, unwrappingkey, wrappedkey, wrappedkeylen, a, alen, key); } CK_RV SeedRandom(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR seed, CK_ULONG seedlen) { CK_RV e = c->sym->C_SeedRandom(session, seed, seedlen); return e; } CK_RV GenerateRandom(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR * rand, CK_ULONG length) { *rand = calloc(length, sizeof(CK_BYTE)); if (*rand == NULL) { return CKR_HOST_MEMORY; } CK_RV e = c->sym->C_GenerateRandom(session, *rand, length); return e; } CK_RV WaitForSlotEvent(struct ctx * c, CK_FLAGS flags, CK_ULONG_PTR slot) { CK_RV e = c->sym->C_WaitForSlotEvent(flags, (CK_SLOT_ID_PTR) slot, NULL); return e; } static inline CK_VOID_PTR getAttributePval(CK_ATTRIBUTE_PTR a) { return a->pValue; } */ import "C" import "strings" import "unsafe" // Ctx contains the current pkcs11 context. type Ctx struct { ctx *C.struct_ctx } // New creates a new context and initializes the module/library for use. func New(module string) *Ctx { c := new(Ctx) mod := C.CString(module) defer C.free(unsafe.Pointer(mod)) c.ctx = C.New(mod) if c.ctx == nil { return nil } return c } // Destroy unloads the module/library and frees any remaining memory. func (c *Ctx) Destroy() { if c == nil || c.ctx == nil { return } C.Destroy(c.ctx) c.ctx = nil } // Initialize initializes the Cryptoki library. func (c *Ctx) Initialize() error { e := C.Initialize(c.ctx) return toError(e) } // Finalize indicates that an application is done with the Cryptoki library. func (c *Ctx) Finalize() error { if c.ctx == nil { return toError(CKR_CRYPTOKI_NOT_INITIALIZED) } e := C.Finalize(c.ctx) return toError(e) } // GetInfo returns general information about Cryptoki. func (c *Ctx) GetInfo() (Info, error) { var p C.ckInfo e := C.GetInfo(c.ctx, &p) i := Info{ CryptokiVersion: toVersion(p.cryptokiVersion), ManufacturerID: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&p.manufacturerID[0]), 32)), " "), Flags: uint(p.flags), LibraryDescription: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&p.libraryDescription[0]), 32)), " "), LibraryVersion: toVersion(p.libraryVersion), } return i, toError(e) } // GetSlotList obtains a list of slots in the system. func (c *Ctx) GetSlotList(tokenPresent bool) ([]uint, error) { var ( slotList C.CK_ULONG_PTR ulCount C.CK_ULONG ) e := C.GetSlotList(c.ctx, cBBool(tokenPresent), &slotList, &ulCount) if toError(e) != nil { return nil, toError(e) } l := toList(slotList, ulCount) return l, nil } // GetSlotInfo obtains information about a particular slot in the system. func (c *Ctx) GetSlotInfo(slotID uint) (SlotInfo, error) { var csi C.CK_SLOT_INFO e := C.GetSlotInfo(c.ctx, C.CK_ULONG(slotID), &csi) s := SlotInfo{ SlotDescription: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&csi.slotDescription[0]), 64)), " "), ManufacturerID: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&csi.manufacturerID[0]), 32)), " "), Flags: uint(csi.flags), HardwareVersion: toVersion(csi.hardwareVersion), FirmwareVersion: toVersion(csi.firmwareVersion), } return s, toError(e) } // GetTokenInfo obtains information about a particular token // in the system. func (c *Ctx) GetTokenInfo(slotID uint) (TokenInfo, error) { var cti C.CK_TOKEN_INFO e := C.GetTokenInfo(c.ctx, C.CK_ULONG(slotID), &cti) s := TokenInfo{ Label: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.label[0]), 32)), " "), ManufacturerID: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.manufacturerID[0]), 32)), " "), Model: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.model[0]), 16)), " "), SerialNumber: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.serialNumber[0]), 16)), " "), Flags: uint(cti.flags), MaxSessionCount: uint(cti.ulMaxSessionCount), SessionCount: uint(cti.ulSessionCount), MaxRwSessionCount: uint(cti.ulMaxRwSessionCount), RwSessionCount: uint(cti.ulRwSessionCount), MaxPinLen: uint(cti.ulMaxPinLen), MinPinLen: uint(cti.ulMinPinLen), TotalPublicMemory: uint(cti.ulTotalPublicMemory), FreePublicMemory: uint(cti.ulFreePublicMemory), TotalPrivateMemory: uint(cti.ulTotalPrivateMemory), FreePrivateMemory: uint(cti.ulFreePrivateMemory), HardwareVersion: toVersion(cti.hardwareVersion), FirmwareVersion: toVersion(cti.firmwareVersion), UTCTime: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.utcTime[0]), 16)), " "), } return s, toError(e) } // GetMechanismList obtains a list of mechanism types supported by a token. func (c *Ctx) GetMechanismList(slotID uint) ([]*Mechanism, error) { var ( mech C.CK_ULONG_PTR // in pkcs#11 we're all CK_ULONGs \o/ mechlen C.CK_ULONG ) e := C.GetMechanismList(c.ctx, C.CK_ULONG(slotID), &mech, &mechlen) if toError(e) != nil { return nil, toError(e) } // Although the function returns only type, cast them back into real // attributes as this is used in other functions. m := make([]*Mechanism, int(mechlen)) for i, typ := range toList(mech, mechlen) { m[i] = NewMechanism(typ, nil) } return m, nil } // GetMechanismInfo obtains information about a particular // mechanism possibly supported by a token. func (c *Ctx) GetMechanismInfo(slotID uint, m []*Mechanism) (MechanismInfo, error) { var cm C.CK_MECHANISM_INFO e := C.GetMechanismInfo(c.ctx, C.CK_ULONG(slotID), C.CK_MECHANISM_TYPE(m[0].Mechanism), C.CK_MECHANISM_INFO_PTR(&cm)) mi := MechanismInfo{ MinKeySize: uint(cm.ulMinKeySize), MaxKeySize: uint(cm.ulMaxKeySize), Flags: uint(cm.flags), } return mi, toError(e) } // InitToken initializes a token. The label must be 32 characters // long, it is blank padded if it is not. If it is longer it is capped // to 32 characters. func (c *Ctx) InitToken(slotID uint, pin string, label string) error { p := C.CString(pin) defer C.free(unsafe.Pointer(p)) ll := len(label) for ll < 32 { label += " " ll++ } l := C.CString(label[:32]) defer C.free(unsafe.Pointer(l)) e := C.InitToken(c.ctx, C.CK_ULONG(slotID), p, C.CK_ULONG(len(pin)), l) return toError(e) } // InitPIN initializes the normal user's PIN. func (c *Ctx) InitPIN(sh SessionHandle, pin string) error { p := C.CString(pin) defer C.free(unsafe.Pointer(p)) e := C.InitPIN(c.ctx, C.CK_SESSION_HANDLE(sh), p, C.CK_ULONG(len(pin))) return toError(e) } // SetPIN modifies the PIN of the user who is logged in. func (c *Ctx) SetPIN(sh SessionHandle, oldpin string, newpin string) error { old := C.CString(oldpin) defer C.free(unsafe.Pointer(old)) new := C.CString(newpin) defer C.free(unsafe.Pointer(new)) e := C.SetPIN(c.ctx, C.CK_SESSION_HANDLE(sh), old, C.CK_ULONG(len(oldpin)), new, C.CK_ULONG(len(newpin))) return toError(e) } // OpenSession opens a session between an application and a token. func (c *Ctx) OpenSession(slotID uint, flags uint) (SessionHandle, error) { var s C.CK_SESSION_HANDLE e := C.OpenSession(c.ctx, C.CK_ULONG(slotID), C.CK_ULONG(flags), C.CK_SESSION_HANDLE_PTR(&s)) return SessionHandle(s), toError(e) } // CloseSession closes a session between an application and a token. func (c *Ctx) CloseSession(sh SessionHandle) error { if c.ctx == nil { return toError(CKR_CRYPTOKI_NOT_INITIALIZED) } e := C.CloseSession(c.ctx, C.CK_SESSION_HANDLE(sh)) return toError(e) } // CloseAllSessions closes all sessions with a token. func (c *Ctx) CloseAllSessions(slotID uint) error { if c.ctx == nil { return toError(CKR_CRYPTOKI_NOT_INITIALIZED) } e := C.CloseAllSessions(c.ctx, C.CK_ULONG(slotID)) return toError(e) } // GetSessionInfo obtains information about the session. func (c *Ctx) GetSessionInfo(sh SessionHandle) (SessionInfo, error) { var csi C.CK_SESSION_INFO e := C.GetSessionInfo(c.ctx, C.CK_SESSION_HANDLE(sh), &csi) s := SessionInfo{SlotID: uint(csi.slotID), State: uint(csi.state), Flags: uint(csi.flags), DeviceError: uint(csi.ulDeviceError), } return s, toError(e) } // GetOperationState obtains the state of the cryptographic operation in a session. func (c *Ctx) GetOperationState(sh SessionHandle) ([]byte, error) { var ( state C.CK_BYTE_PTR statelen C.CK_ULONG ) e := C.GetOperationState(c.ctx, C.CK_SESSION_HANDLE(sh), &state, &statelen) defer C.free(unsafe.Pointer(state)) if toError(e) != nil { return nil, toError(e) } b := C.GoBytes(unsafe.Pointer(state), C.int(statelen)) return b, nil } // SetOperationState restores the state of the cryptographic operation in a session. func (c *Ctx) SetOperationState(sh SessionHandle, state []byte, encryptKey, authKey ObjectHandle) error { e := C.SetOperationState(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&state[0])), C.CK_ULONG(len(state)), C.CK_OBJECT_HANDLE(encryptKey), C.CK_OBJECT_HANDLE(authKey)) return toError(e) } // Login logs a user into a token. func (c *Ctx) Login(sh SessionHandle, userType uint, pin string) error { p := C.CString(pin) defer C.free(unsafe.Pointer(p)) e := C.Login(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_USER_TYPE(userType), p, C.CK_ULONG(len(pin))) return toError(e) } // Logout logs a user out from a token. func (c *Ctx) Logout(sh SessionHandle) error { if c.ctx == nil { return toError(CKR_CRYPTOKI_NOT_INITIALIZED) } e := C.Logout(c.ctx, C.CK_SESSION_HANDLE(sh)) return toError(e) } // CreateObject creates a new object. func (c *Ctx) CreateObject(sh SessionHandle, temp []*Attribute) (ObjectHandle, error) { var obj C.CK_OBJECT_HANDLE arena, t, tcount := cAttributeList(temp) defer arena.Free() e := C.CreateObject(c.ctx, C.CK_SESSION_HANDLE(sh), t, tcount, C.CK_OBJECT_HANDLE_PTR(&obj)) e1 := toError(e) if e1 == nil { return ObjectHandle(obj), nil } return 0, e1 } // CopyObject copies an object, creating a new object for the copy. func (c *Ctx) CopyObject(sh SessionHandle, o ObjectHandle, temp []*Attribute) (ObjectHandle, error) { var obj C.CK_OBJECT_HANDLE arena, t, tcount := cAttributeList(temp) defer arena.Free() e := C.CopyObject(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(o), t, tcount, C.CK_OBJECT_HANDLE_PTR(&obj)) e1 := toError(e) if e1 == nil { return ObjectHandle(obj), nil } return 0, e1 } // DestroyObject destroys an object. func (c *Ctx) DestroyObject(sh SessionHandle, oh ObjectHandle) error { e := C.DestroyObject(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(oh)) return toError(e) } // GetObjectSize gets the size of an object in bytes. func (c *Ctx) GetObjectSize(sh SessionHandle, oh ObjectHandle) (uint, error) { var size C.CK_ULONG e := C.GetObjectSize(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(oh), &size) return uint(size), toError(e) } // GetAttributeValue obtains the value of one or more object attributes. func (c *Ctx) GetAttributeValue(sh SessionHandle, o ObjectHandle, a []*Attribute) ([]*Attribute, error) { // copy the attribute list and make all the values nil, so that // the C function can (allocate) fill them in pa := make([]C.CK_ATTRIBUTE, len(a)) for i := 0; i < len(a); i++ { pa[i]._type = C.CK_ATTRIBUTE_TYPE(a[i].Type) } e := C.GetAttributeValue(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(o), &pa[0], C.CK_ULONG(len(a))) if err := toError(e); err != nil { return nil, err } a1 := make([]*Attribute, len(a)) for i, c := range pa { x := new(Attribute) x.Type = uint(c._type) if int(c.ulValueLen) != -1 { buf := unsafe.Pointer(C.getAttributePval(&c)) x.Value = C.GoBytes(buf, C.int(c.ulValueLen)) C.free(buf) } a1[i] = x } return a1, nil } // SetAttributeValue modifies the value of one or more object attributes func (c *Ctx) SetAttributeValue(sh SessionHandle, o ObjectHandle, a []*Attribute) error { arena, pa, palen := cAttributeList(a) defer arena.Free() e := C.SetAttributeValue(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(o), pa, palen) return toError(e) } // FindObjectsInit initializes a search for token and session // objects that match a template. func (c *Ctx) FindObjectsInit(sh SessionHandle, temp []*Attribute) error { arena, t, tcount := cAttributeList(temp) defer arena.Free() e := C.FindObjectsInit(c.ctx, C.CK_SESSION_HANDLE(sh), t, tcount) return toError(e) } // FindObjects continues a search for token and session // objects that match a template, obtaining additional object // handles. Calling the function repeatedly may yield additional results until // an empty slice is returned. // // The returned boolean value is deprecated and should be ignored. func (c *Ctx) FindObjects(sh SessionHandle, max int) ([]ObjectHandle, bool, error) { var ( objectList C.CK_OBJECT_HANDLE_PTR ulCount C.CK_ULONG ) e := C.FindObjects(c.ctx, C.CK_SESSION_HANDLE(sh), &objectList, C.CK_ULONG(max), &ulCount) if toError(e) != nil { return nil, false, toError(e) } l := toList(C.CK_ULONG_PTR(unsafe.Pointer(objectList)), ulCount) // Make again a new list of the correct type. // This is copying data, but this is not an often used function. o := make([]ObjectHandle, len(l)) for i, v := range l { o[i] = ObjectHandle(v) } return o, ulCount > C.CK_ULONG(max), nil } // FindObjectsFinal finishes a search for token and session objects. func (c *Ctx) FindObjectsFinal(sh SessionHandle) error { e := C.FindObjectsFinal(c.ctx, C.CK_SESSION_HANDLE(sh)) return toError(e) } // EncryptInit initializes an encryption operation. func (c *Ctx) EncryptInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error { arena, mech := cMechanism(m) defer arena.Free() e := C.EncryptInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o)) return toError(e) } // Encrypt encrypts single-part data. func (c *Ctx) Encrypt(sh SessionHandle, message []byte) ([]byte, error) { var ( enc C.CK_BYTE_PTR enclen C.CK_ULONG ) e := C.Encrypt(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(message), C.CK_ULONG(len(message)), &enc, &enclen) if toError(e) != nil { return nil, toError(e) } s := C.GoBytes(unsafe.Pointer(enc), C.int(enclen)) C.free(unsafe.Pointer(enc)) return s, nil } // EncryptUpdate continues a multiple-part encryption operation. func (c *Ctx) EncryptUpdate(sh SessionHandle, plain []byte) ([]byte, error) { var ( part C.CK_BYTE_PTR partlen C.CK_ULONG ) e := C.EncryptUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(plain), C.CK_ULONG(len(plain)), &part, &partlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(part), C.int(partlen)) C.free(unsafe.Pointer(part)) return h, nil } // EncryptFinal finishes a multiple-part encryption operation. func (c *Ctx) EncryptFinal(sh SessionHandle) ([]byte, error) { var ( enc C.CK_BYTE_PTR enclen C.CK_ULONG ) e := C.EncryptFinal(c.ctx, C.CK_SESSION_HANDLE(sh), &enc, &enclen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(enc), C.int(enclen)) C.free(unsafe.Pointer(enc)) return h, nil } // DecryptInit initializes a decryption operation. func (c *Ctx) DecryptInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error { arena, mech := cMechanism(m) defer arena.Free() e := C.DecryptInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o)) return toError(e) } // Decrypt decrypts encrypted data in a single part. func (c *Ctx) Decrypt(sh SessionHandle, cipher []byte) ([]byte, error) { var ( plain C.CK_BYTE_PTR plainlen C.CK_ULONG ) e := C.Decrypt(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(cipher), C.CK_ULONG(len(cipher)), &plain, &plainlen) if toError(e) != nil { return nil, toError(e) } s := C.GoBytes(unsafe.Pointer(plain), C.int(plainlen)) C.free(unsafe.Pointer(plain)) return s, nil } // DecryptUpdate continues a multiple-part decryption operation. func (c *Ctx) DecryptUpdate(sh SessionHandle, cipher []byte) ([]byte, error) { var ( part C.CK_BYTE_PTR partlen C.CK_ULONG ) e := C.DecryptUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(cipher), C.CK_ULONG(len(cipher)), &part, &partlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(part), C.int(partlen)) C.free(unsafe.Pointer(part)) return h, nil } // DecryptFinal finishes a multiple-part decryption operation. func (c *Ctx) DecryptFinal(sh SessionHandle) ([]byte, error) { var ( plain C.CK_BYTE_PTR plainlen C.CK_ULONG ) e := C.DecryptFinal(c.ctx, C.CK_SESSION_HANDLE(sh), &plain, &plainlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(plain), C.int(plainlen)) C.free(unsafe.Pointer(plain)) return h, nil } // DigestInit initializes a message-digesting operation. func (c *Ctx) DigestInit(sh SessionHandle, m []*Mechanism) error { arena, mech := cMechanism(m) defer arena.Free() e := C.DigestInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech) return toError(e) } // Digest digests message in a single part. func (c *Ctx) Digest(sh SessionHandle, message []byte) ([]byte, error) { var ( hash C.CK_BYTE_PTR hashlen C.CK_ULONG ) e := C.Digest(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(message), C.CK_ULONG(len(message)), &hash, &hashlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(hash), C.int(hashlen)) C.free(unsafe.Pointer(hash)) return h, nil } // DigestUpdate continues a multiple-part message-digesting operation. func (c *Ctx) DigestUpdate(sh SessionHandle, message []byte) error { e := C.DigestUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(message), C.CK_ULONG(len(message))) if toError(e) != nil { return toError(e) } return nil } // DigestKey continues a multi-part message-digesting // operation, by digesting the value of a secret key as part of // the data already digested. func (c *Ctx) DigestKey(sh SessionHandle, key ObjectHandle) error { e := C.DigestKey(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(key)) if toError(e) != nil { return toError(e) } return nil } // DigestFinal finishes a multiple-part message-digesting operation. func (c *Ctx) DigestFinal(sh SessionHandle) ([]byte, error) { var ( hash C.CK_BYTE_PTR hashlen C.CK_ULONG ) e := C.DigestFinal(c.ctx, C.CK_SESSION_HANDLE(sh), &hash, &hashlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(hash), C.int(hashlen)) C.free(unsafe.Pointer(hash)) return h, nil } // SignInit initializes a signature (private key encryption) // operation, where the signature is (will be) an appendix to // the data, and plaintext cannot be recovered from the signature. func (c *Ctx) SignInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error { arena, mech := cMechanism(m) defer arena.Free() e := C.SignInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o)) return toError(e) } // Sign signs (encrypts with private key) data in a single part, where the signature // is (will be) an appendix to the data, and plaintext cannot be recovered from the signature. func (c *Ctx) Sign(sh SessionHandle, message []byte) ([]byte, error) { var ( sig C.CK_BYTE_PTR siglen C.CK_ULONG ) e := C.Sign(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(message), C.CK_ULONG(len(message)), &sig, &siglen) if toError(e) != nil { return nil, toError(e) } s := C.GoBytes(unsafe.Pointer(sig), C.int(siglen)) C.free(unsafe.Pointer(sig)) return s, nil } // SignUpdate continues a multiple-part signature operation, // where the signature is (will be) an appendix to the data, // and plaintext cannot be recovered from the signature. func (c *Ctx) SignUpdate(sh SessionHandle, message []byte) error { e := C.SignUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(message), C.CK_ULONG(len(message))) return toError(e) } // SignFinal finishes a multiple-part signature operation returning the signature. func (c *Ctx) SignFinal(sh SessionHandle) ([]byte, error) { var ( sig C.CK_BYTE_PTR siglen C.CK_ULONG ) e := C.SignFinal(c.ctx, C.CK_SESSION_HANDLE(sh), &sig, &siglen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(sig), C.int(siglen)) C.free(unsafe.Pointer(sig)) return h, nil } // SignRecoverInit initializes a signature operation, where the data can be recovered from the signature. func (c *Ctx) SignRecoverInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error { arena, mech := cMechanism(m) defer arena.Free() e := C.SignRecoverInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key)) return toError(e) } // SignRecover signs data in a single operation, where the data can be recovered from the signature. func (c *Ctx) SignRecover(sh SessionHandle, data []byte) ([]byte, error) { var ( sig C.CK_BYTE_PTR siglen C.CK_ULONG ) e := C.SignRecover(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(data), C.CK_ULONG(len(data)), &sig, &siglen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(sig), C.int(siglen)) C.free(unsafe.Pointer(sig)) return h, nil } // VerifyInit initializes a verification operation, where the // signature is an appendix to the data, and plaintext cannot // be recovered from the signature (e.g. DSA). func (c *Ctx) VerifyInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error { arena, mech := cMechanism(m) defer arena.Free() e := C.VerifyInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key)) return toError(e) } // Verify verifies a signature in a single-part operation, // where the signature is an appendix to the data, and plaintext // cannot be recovered from the signature. func (c *Ctx) Verify(sh SessionHandle, data []byte, signature []byte) error { e := C.Verify(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(data), C.CK_ULONG(len(data)), cMessage(signature), C.CK_ULONG(len(signature))) return toError(e) } // VerifyUpdate continues a multiple-part verification // operation, where the signature is an appendix to the data, // and plaintext cannot be recovered from the signature. func (c *Ctx) VerifyUpdate(sh SessionHandle, part []byte) error { e := C.VerifyUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(part), C.CK_ULONG(len(part))) return toError(e) } // VerifyFinal finishes a multiple-part verification // operation, checking the signature. func (c *Ctx) VerifyFinal(sh SessionHandle, signature []byte) error { e := C.VerifyFinal(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(signature), C.CK_ULONG(len(signature))) return toError(e) } // VerifyRecoverInit initializes a signature verification // operation, where the data is recovered from the signature. func (c *Ctx) VerifyRecoverInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error { arena, mech := cMechanism(m) defer arena.Free() e := C.VerifyRecoverInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key)) return toError(e) } // VerifyRecover verifies a signature in a single-part // operation, where the data is recovered from the signature. func (c *Ctx) VerifyRecover(sh SessionHandle, signature []byte) ([]byte, error) { var ( data C.CK_BYTE_PTR datalen C.CK_ULONG ) e := C.DecryptVerifyUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(signature), C.CK_ULONG(len(signature)), &data, &datalen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(data), C.int(datalen)) C.free(unsafe.Pointer(data)) return h, nil } // DigestEncryptUpdate continues a multiple-part digesting and encryption operation. func (c *Ctx) DigestEncryptUpdate(sh SessionHandle, part []byte) ([]byte, error) { var ( enc C.CK_BYTE_PTR enclen C.CK_ULONG ) e := C.DigestEncryptUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(part), C.CK_ULONG(len(part)), &enc, &enclen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(enc), C.int(enclen)) C.free(unsafe.Pointer(enc)) return h, nil } // DecryptDigestUpdate continues a multiple-part decryption and digesting operation. func (c *Ctx) DecryptDigestUpdate(sh SessionHandle, cipher []byte) ([]byte, error) { var ( part C.CK_BYTE_PTR partlen C.CK_ULONG ) e := C.DecryptDigestUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(cipher), C.CK_ULONG(len(cipher)), &part, &partlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(part), C.int(partlen)) C.free(unsafe.Pointer(part)) return h, nil } // SignEncryptUpdate continues a multiple-part signing and encryption operation. func (c *Ctx) SignEncryptUpdate(sh SessionHandle, part []byte) ([]byte, error) { var ( enc C.CK_BYTE_PTR enclen C.CK_ULONG ) e := C.SignEncryptUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(part), C.CK_ULONG(len(part)), &enc, &enclen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(enc), C.int(enclen)) C.free(unsafe.Pointer(enc)) return h, nil } // DecryptVerifyUpdate continues a multiple-part decryption and verify operation. func (c *Ctx) DecryptVerifyUpdate(sh SessionHandle, cipher []byte) ([]byte, error) { var ( part C.CK_BYTE_PTR partlen C.CK_ULONG ) e := C.DecryptVerifyUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), cMessage(cipher), C.CK_ULONG(len(cipher)), &part, &partlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(part), C.int(partlen)) C.free(unsafe.Pointer(part)) return h, nil } // GenerateKey generates a secret key, creating a new key object. func (c *Ctx) GenerateKey(sh SessionHandle, m []*Mechanism, temp []*Attribute) (ObjectHandle, error) { var key C.CK_OBJECT_HANDLE attrarena, t, tcount := cAttributeList(temp) defer attrarena.Free() mecharena, mech := cMechanism(m) defer mecharena.Free() e := C.GenerateKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, t, tcount, C.CK_OBJECT_HANDLE_PTR(&key)) e1 := toError(e) if e1 == nil { return ObjectHandle(key), nil } return 0, e1 } // GenerateKeyPair generates a public-key/private-key pair creating new key objects. func (c *Ctx) GenerateKeyPair(sh SessionHandle, m []*Mechanism, public, private []*Attribute) (ObjectHandle, ObjectHandle, error) { var ( pubkey C.CK_OBJECT_HANDLE privkey C.CK_OBJECT_HANDLE ) pubarena, pub, pubcount := cAttributeList(public) defer pubarena.Free() privarena, priv, privcount := cAttributeList(private) defer privarena.Free() mecharena, mech := cMechanism(m) defer mecharena.Free() e := C.GenerateKeyPair(c.ctx, C.CK_SESSION_HANDLE(sh), mech, pub, pubcount, priv, privcount, C.CK_OBJECT_HANDLE_PTR(&pubkey), C.CK_OBJECT_HANDLE_PTR(&privkey)) e1 := toError(e) if e1 == nil { return ObjectHandle(pubkey), ObjectHandle(privkey), nil } return 0, 0, e1 } // WrapKey wraps (i.e., encrypts) a key. func (c *Ctx) WrapKey(sh SessionHandle, m []*Mechanism, wrappingkey, key ObjectHandle) ([]byte, error) { var ( wrappedkey C.CK_BYTE_PTR wrappedkeylen C.CK_ULONG ) arena, mech := cMechanism(m) defer arena.Free() e := C.WrapKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(wrappingkey), C.CK_OBJECT_HANDLE(key), &wrappedkey, &wrappedkeylen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(wrappedkey), C.int(wrappedkeylen)) C.free(unsafe.Pointer(wrappedkey)) return h, nil } // UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. func (c *Ctx) UnwrapKey(sh SessionHandle, m []*Mechanism, unwrappingkey ObjectHandle, wrappedkey []byte, a []*Attribute) (ObjectHandle, error) { var key C.CK_OBJECT_HANDLE attrarena, ac, aclen := cAttributeList(a) defer attrarena.Free() mecharena, mech := cMechanism(m) defer mecharena.Free() e := C.UnwrapKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(unwrappingkey), C.CK_BYTE_PTR(unsafe.Pointer(&wrappedkey[0])), C.CK_ULONG(len(wrappedkey)), ac, aclen, &key) return ObjectHandle(key), toError(e) } // DeriveKey derives a key from a base key, creating a new key object. func (c *Ctx) DeriveKey(sh SessionHandle, m []*Mechanism, basekey ObjectHandle, a []*Attribute) (ObjectHandle, error) { var key C.CK_OBJECT_HANDLE attrarena, ac, aclen := cAttributeList(a) defer attrarena.Free() mecharena, mech := cMechanism(m) defer mecharena.Free() e := C.DeriveKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(basekey), ac, aclen, &key) return ObjectHandle(key), toError(e) } // SeedRandom mixes additional seed material into the token's // random number generator. func (c *Ctx) SeedRandom(sh SessionHandle, seed []byte) error { e := C.SeedRandom(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&seed[0])), C.CK_ULONG(len(seed))) return toError(e) } // GenerateRandom generates random data. func (c *Ctx) GenerateRandom(sh SessionHandle, length int) ([]byte, error) { var rand C.CK_BYTE_PTR e := C.GenerateRandom(c.ctx, C.CK_SESSION_HANDLE(sh), &rand, C.CK_ULONG(length)) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(rand), C.int(length)) C.free(unsafe.Pointer(rand)) return h, nil } // WaitForSlotEvent returns a channel which returns a slot event // (token insertion, removal, etc.) when it occurs. func (c *Ctx) WaitForSlotEvent(flags uint) chan SlotEvent { sl := make(chan SlotEvent, 1) // hold one element go c.waitForSlotEventHelper(flags, sl) return sl } func (c *Ctx) waitForSlotEventHelper(f uint, sl chan SlotEvent) { var slotID C.CK_ULONG C.WaitForSlotEvent(c.ctx, C.CK_FLAGS(f), &slotID) sl <- SlotEvent{uint(slotID)} close(sl) // TODO(miek): Sending and then closing ...? }