| // 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 LDFLAGS: -lltdl |
| #define CK_PTR * |
| #ifndef NULL_PTR |
| #define NULL_PTR 0 |
| #endif |
| #define CK_DEFINE_FUNCTION(returnType, name) returnType name |
| #define CK_DECLARE_FUNCTION(returnType, name) returnType name |
| #define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name) |
| #define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name) |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <ltdl.h> |
| #include <unistd.h> |
| #include "pkcs11.h" |
| |
| struct ctx { |
| lt_dlhandle handle; |
| CK_FUNCTION_LIST_PTR sym; |
| }; |
| |
| // New initializes a ctx and fills the symbol table. |
| struct ctx *New(const char *module) |
| { |
| if (lt_dlinit() != 0) { |
| return NULL; |
| } |
| CK_C_GetFunctionList list; |
| struct ctx *c = calloc(1, sizeof(struct ctx)); |
| c->handle = lt_dlopen(module); |
| if (c->handle == NULL) { |
| free(c); |
| return NULL; |
| } |
| list = (CK_C_GetFunctionList) lt_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 (lt_dlclose(c->handle) < 0) { |
| return; |
| } |
| lt_dlexit(); |
| free(c); |
| } |
| |
| CK_RV Initialize(struct ctx * c, CK_VOID_PTR initArgs) |
| { |
| return c->sym->C_Initialize(initArgs); |
| } |
| |
| CK_RV Finalize(struct ctx * c) |
| { |
| return c->sym->C_Finalize(NULL); |
| } |
| |
| CK_RV GetInfo(struct ctx * c, CK_INFO_PTR info) |
| { |
| return c->sym->C_GetInfo(info); |
| } |
| |
| 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); |
| if (e != CKR_OK) { |
| 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) |
| { |
| CK_RV e = c->sym->C_CreateObject(session, temp, tempCount, obj); |
| return e; |
| } |
| |
| 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) |
| { |
| CK_RV e = c->sym->C_CopyObject(session, o, temp, tempCount, obj); |
| return e; |
| } |
| |
| 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)); |
| } |
| e = c->sym->C_GetAttributeValue(session, object, temp, templen); |
| return e; |
| } |
| |
| CK_RV SetAttributeValue(struct ctx * c, CK_SESSION_HANDLE session, |
| CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR temp, |
| CK_ULONG templen) |
| { |
| CK_RV e = c->sym->C_SetAttributeValue(session, object, temp, templen); |
| return e; |
| } |
| |
| CK_RV FindObjectsInit(struct ctx * c, CK_SESSION_HANDLE session, |
| CK_ATTRIBUTE_PTR temp, CK_ULONG tempCount) |
| { |
| CK_RV e = c->sym->C_FindObjectsInit(session, temp, tempCount); |
| return e; |
| } |
| |
| 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) |
| { |
| CK_RV e = c->sym->C_EncryptInit(session, mechanism, key); |
| return e; |
| } |
| |
| 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) |
| { |
| CK_RV e = c->sym->C_DecryptInit(session, mechanism, key); |
| return e; |
| } |
| |
| CK_RV Decrypt(struct ctx * c, CK_SESSION_HANDLE session, CK_BYTE_PTR cypher, |
| CK_ULONG clen, CK_BYTE_PTR * plain, CK_ULONG_PTR plainlen) |
| { |
| CK_RV e = c->sym->C_Decrypt(session, cypher, 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, cypher, 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) |
| { |
| CK_RV e = c->sym->C_DigestInit(session, mechanism); |
| return e; |
| } |
| |
| 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) |
| { |
| CK_RV e = c->sym->C_SignInit(session, mechanism, key); |
| return e; |
| } |
| |
| 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 mech, CK_OBJECT_HANDLE key) |
| { |
| CK_RV rv = c->sym->C_SignRecoverInit(session, mech, key); |
| return rv; |
| } |
| |
| 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 mech, CK_OBJECT_HANDLE key) |
| { |
| CK_RV rv = c->sym->C_VerifyInit(session, mech, key); |
| return rv; |
| } |
| |
| 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 mech, CK_OBJECT_HANDLE key) |
| { |
| CK_RV rv = c->sym->C_VerifyRecoverInit(session, mech, key); |
| return rv; |
| } |
| |
| 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) |
| { |
| CK_RV e = |
| c->sym->C_GenerateKey(session, mechanism, temp, tempCount, key); |
| return e; |
| } |
| |
| 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) |
| { |
| CK_RV e = |
| c->sym->C_GenerateKeyPair(session, mechanism, pub, pubCount, priv, |
| privCount, |
| pubkey, privkey); |
| return e; |
| } |
| |
| 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 mech, CK_OBJECT_HANDLE basekey, |
| CK_ATTRIBUTE_PTR a, CK_ULONG alen, CK_OBJECT_HANDLE_PTR key) |
| { |
| CK_RV e = c->sym->C_DeriveKey(session, mech, basekey, a, alen, key); |
| return e; |
| } |
| |
| CK_RV UnwrapKey(struct ctx * c, CK_SESSION_HANDLE session, |
| CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE unwrappingkey, |
| CK_BYTE_PTR wrappedkey, CK_ULONG wrappedkeylen, |
| CK_ATTRIBUTE_PTR a, CK_ULONG alen, CK_OBJECT_HANDLE_PTR key) |
| { |
| CK_RV e = c->sym->C_UnwrapKey(session, mech, unwrappingkey, wrappedkey, |
| wrappedkeylen, a, alen, key); |
| return e; |
| } |
| |
| 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; |
| } |
| */ |
| 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 { |
| args := &C.CK_C_INITIALIZE_ARGS{nil, nil, nil, nil, C.CKF_OS_LOCKING_OK, nil} |
| e := C.Initialize(c.ctx, C.CK_VOID_PTR(args)) |
| 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.CK_INFO |
| e := C.GetInfo(c.ctx, C.CK_INFO_PTR(&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) |
| if toError(e) != nil { |
| return nil, toError(e) |
| } |
| b := C.GoBytes(unsafe.Pointer(state), C.int(statelen)) |
| C.free(unsafe.Pointer(state)) |
| 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), C.CK_ATTRIBUTE_PTR(&pa[0]), C.CK_ULONG(len(a))) |
| if toError(e) != nil { |
| return nil, toError(e) |
| } |
| a1 := make([]*Attribute, len(a)) |
| for i, c := range pa { |
| x := new(Attribute) |
| x.Type = uint(c._type) |
| if int(c.ulValueLen) != -1 { |
| x.Value = C.GoBytes(unsafe.Pointer(c.pValue), C.int(c.ulValueLen)) |
| C.free(unsafe.Pointer(c.pValue)) |
| } |
| 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. The returned boolean indicates if the list would |
| // have been larger than max. |
| 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, _ := cMechanismList(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), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&plain[0])), 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, _ := cMechanismList(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, cypher []byte) ([]byte, error) { |
| var ( |
| plain C.CK_BYTE_PTR |
| plainlen C.CK_ULONG |
| ) |
| e := C.Decrypt(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&cypher[0])), C.CK_ULONG(len(cypher)), &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), C.CK_BYTE_PTR(unsafe.Pointer(&cipher[0])), 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, _ := cMechanismList(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), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), 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, _ := cMechanismList(m) // Only the first is used, but still use a list. |
| 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), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), 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, _ := cMechanismList(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), C.CK_BYTE_PTR(unsafe.Pointer(&data[0])), 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, _ := cMechanismList(m) // only use one here |
| 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), C.CK_BYTE_PTR(unsafe.Pointer(&data[0])), C.CK_ULONG(len(data)), C.CK_BYTE_PTR(unsafe.Pointer(&signature[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&part[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&signature[0])), 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, _ := cMechanismList(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), C.CK_BYTE_PTR(unsafe.Pointer(&signature[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&part[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&cipher[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&part[0])), 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), C.CK_BYTE_PTR(unsafe.Pointer(&cipher[0])), 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, _ := cMechanismList(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, _ := cMechanismList(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, _ := cMechanismList(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, _ := cMechanismList(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, _ := cMechanismList(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 ...? |
| } |