diff --git a/examples/add_cert_file.c b/examples/add_cert_file.c new file mode 100644 index 0000000..fea92b4 --- /dev/null +++ b/examples/add_cert_file.c @@ -0,0 +1,401 @@ +/* add_cert.c + * + * Copyright (C) 2006-2024 wolfSSL Inc. + * + * This file is part of wolfPKCS11. + * + * wolfPKCS11 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPKCS11 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifdef HAVE_CONFIG_H + #include +#endif + +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include +#include + +#ifndef WOLFPKCS11_USER_SETTINGS + #include +#endif +#include + +#ifndef HAVE_PKCS11_STATIC +#include +#endif + +#ifndef WOLFPKCS11_NO_STORE + +#ifdef DEBUG_WOLFPKCS11 + #define CHECK_CKR(rv, op) \ + fprintf(stderr, "%s: %ld\n", op, rv) +#else + #define CHECK_CKR(rv, op) \ + if (ret != CKR_OK) \ + fprintf(stderr, "%s: %ld\n", op, rv) +#endif + + +/* DLL Location and slot */ +#ifndef WOLFPKCS11_DLL_FILENAME + #ifdef __MACH__ + #define WOLFPKCS11_DLL_FILENAME "./src/.libs/libwolfpkcs11.dylib" + #else + #define WOLFPKCS11_DLL_FILENAME "./src/.libs/libwolfpkcs11.so" + #endif +#endif +#ifndef WOLFPKCS11_DLL_SLOT + #define WOLFPKCS11_DLL_SLOT 1 +#endif + + +#ifndef HAVE_PKCS11_STATIC +static void* dlib; +#endif +static CK_FUNCTION_LIST* funcList; +static CK_SLOT_ID slot = WOLFPKCS11_DLL_SLOT; + +static byte* userPin = (byte*)"wolfpkcs11-test"; +static CK_ULONG userPinLen; + +static CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; +static CK_BBOOL ckTrue = CK_TRUE; +CK_CERTIFICATE_TYPE certType = CKC_X_509; + + +static CK_RV pkcs11_init(const char* library, CK_SESSION_HANDLE* session) +{ + CK_RV ret = CKR_OK; +#ifndef HAVE_PKCS11_STATIC + void* func; + + dlib = dlopen(library, RTLD_NOW | RTLD_LOCAL); + if (dlib == NULL) { + fprintf(stderr, "dlopen error: %s\n", dlerror()); + ret = -1; + } + + if (ret == CKR_OK) { + func = (void*)(CK_C_GetFunctionList)dlsym(dlib, "C_GetFunctionList"); + if (func == NULL) { + fprintf(stderr, "Failed to get function list function\n"); + ret = -1; + } + } + + if (ret == CKR_OK) { + ret = ((CK_C_GetFunctionList)func)(&funcList); + CHECK_CKR(ret, "Get Function List call"); + } + + if (ret != CKR_OK && dlib != NULL) + dlclose(dlib); + +#else + ret = C_GetFunctionList(&funcList); + (void)library; +#endif + + if (ret == CKR_OK) { + ret = funcList->C_Initialize(NULL); + CHECK_CKR(ret, "Initialize"); + } + + if (ret == CKR_OK) { + CK_FLAGS sessFlags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + + ret = funcList->C_OpenSession(slot, sessFlags, NULL, NULL, session); + CHECK_CKR(ret, "Open Session"); + if (ret == CKR_OK && userPinLen != 0) { + ret = funcList->C_Login(*session, CKU_USER, userPin, userPinLen); + CHECK_CKR(ret, "Login"); + } + } + + return ret; +} + + +static void pkcs11_final(CK_SESSION_HANDLE session) +{ + if (userPinLen != 0) + funcList->C_Logout(session); + funcList->C_CloseSession(session); + + funcList->C_Finalize(NULL); +#ifndef HAVE_PKCS11_STATIC + dlclose(dlib); +#endif +} + + +static CK_RV load_cert(char* filename, unsigned char **certData, + CK_ULONG *certDataLen) +{ + int ret = 0; + unsigned char *buffer; + int len; + XFILE file; + + file = XFOPEN(filename, "r"); + if (file == XBADFILE) { + fprintf(stderr, "Unable to open file: %s\n", filename); + ret = 1; + } + if (ret == 0) { + XFSEEK(file, 0, XSEEK_END); + len = (int)XFTELL(file); + if (len == 0) { + fprintf(stderr, "File: %s is empty\n", filename); + ret = 1; + } + } + if (ret == 0) { + if (XFSEEK(file, 0, XSEEK_SET) != 0) { + fprintf(stderr, "Error seeking file: %s\n", filename); + ret = 1; + } + } + if (ret == 0) { + buffer = (unsigned char *)XMALLOC(len + 1, NULL, DYNAMIC_TYPE_FILE); + if (buffer == NULL) { + fprintf(stderr, "Malloc error on %d bytes\n", len); + ret = 1; + } + } + if (ret == 0) { + len = (int)XFREAD(buffer, 1, len, file); + if (len <= 0) { + fprintf(stderr, ": %s\n", filename); + ret = 1; + } + + *certData = buffer; + *certDataLen = (CK_ULONG)len; + buffer = NULL; + } + + if (file != XBADFILE) { + XFCLOSE(file); + } + if (buffer != NULL) { + XFREE(buffer, NULL, DYNAMIC_TYPE_FILE); + } + + return ret; +} + +static CK_RV pkcs11_add_cert(CK_SESSION_HANDLE session, + unsigned char* privId, CK_ULONG privIdLen, char *label, + unsigned char *certData, CK_ULONG certDataLen) +{ + CK_RV ret; + CK_ATTRIBUTE certTmpl[6] = { + { CKA_CLASS, &certClass, sizeof(certClass) }, + { CKA_CERTIFICATE_TYPE, &certType, sizeof(certType) }, + { CKA_VALUE, certData, certDataLen }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG cnt = 4; + CK_OBJECT_HANDLE obj; + + if (privId != NULL && privIdLen > 0) { + certTmpl[cnt].type = CKA_ID; + certTmpl[cnt].pValue = privId; + certTmpl[cnt].ulValueLen = privIdLen; + cnt++; + } + + if (label != NULL) { + certTmpl[cnt].type = CKA_LABEL; + certTmpl[cnt].pValue = label; + certTmpl[cnt].ulValueLen = (CK_ULONG)(XSTRLEN(label)); + cnt++; + } + + ret = funcList->C_CreateObject(session, certTmpl, cnt, &obj); + CHECK_CKR(ret, "CreateObject Certificate"); + + return ret; +} + + +/* Match the command line argument with the string. + * + * arg Command line argument. + * str String to check for. + * return 1 if the command line argument matches the string, 0 otherwise. + */ +static int string_matches(const char* arg, const char* str) +{ + int len = (int)XSTRLEN(str) + 1; + return XSTRNCMP(arg, str, len) == 0; +} + + +/* Display the usage options of the benchmark program. */ +static void Usage(void) +{ + printf("add_cert\n"); + printf("-? Help, print this usage\n"); + printf("-lib PKCS#11 library to test\n"); + printf("-slot Slot number to use\n"); + printf("-userPin User PIN\n"); + printf("-privId Certificate identifier\n"); + printf("-label Certificate label\n"); + printf("-cert Certificate file in DER format\n"); +} + + +#ifndef NO_MAIN_DRIVER +int main(int argc, char* argv[]) +#else +int add_cert(int argc, char* argv[]) +#endif +{ + int ret; + CK_RV rv; + const char* libName = WOLFPKCS11_DLL_FILENAME; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + unsigned char* privId = NULL; + CK_ULONG privIdLen = 0; + char *label = NULL; + unsigned char *certData = NULL; + CK_ULONG certDataLen = 0; + char *filename = NULL; + +#ifndef WOLFPKCS11_NO_ENV + if (!XGETENV("WOLFPKCS11_TOKEN_PATH")) { + XSETENV("WOLFPKCS11_TOKEN_PATH", "./store", 1); + } +#endif + + argc--; + argv++; + while (argc > 0) { + if (string_matches(*argv, "-?")) { + Usage(); + return 0; + } + else if (string_matches(*argv, "-lib")) { + argc--; + argv++; + if (argc == 0) { + fprintf(stderr, "Library name not supplied\n"); + return 1; + } + libName = *argv; + } + else if (string_matches(*argv, "-slot")) { + argc--; + argv++; + if (argc == 0) { + fprintf(stderr, "Slot number not supplied\n"); + return 1; + } + slot = atoi(*argv); + } + else if (string_matches(*argv, "-userPin")) { + argc--; + argv++; + if (argc == 0) { + fprintf(stderr, "User PIN not supplied\n"); + return 1; + } + userPin = (byte*)*argv; + } + else if (string_matches(*argv, "-privId")) { + argc--; + argv++; + if (argc == 0) { + fprintf(stderr, "Certificate identifier not supplied\n"); + return 1; + } + privId = (unsigned char*)*argv; + privIdLen = (int)strlen(*argv); + } + else if (string_matches(*argv, "-label")) { + argc--; + argv++; + if (argc == 0) { + fprintf(stderr, "Label not supplied\n"); + return 1; + } + label = (char*)*argv; + } + else if (string_matches(*argv, "-cert")) { + argc--; + argv++; + if (argc == 0) { + fprintf(stderr, "Certificate filename not supplied\n"); + return 1; + } + filename = (char*)*argv; + } + else { + fprintf(stderr, "Unrecognized command line argument\n %s\n", + argv[0]); + return 1; + } + + argc--; + argv++; + } + + if (filename == NULL) { + fprintf(stderr, "Must specify certificate filename!\n"); + return 1; + } + + userPinLen = (int)XSTRLEN((const char*)userPin); + + rv = load_cert(filename, &certData, &certDataLen); + if (rv != 0) { + return 1; + } + + rv = pkcs11_init(libName, &session); + if (rv == CKR_OK) { + rv = pkcs11_add_cert(session, privId, privIdLen, label, + certData, certDataLen); + } + pkcs11_final(session); + + if (rv == CKR_OK) + ret = 0; + else + ret = 1; + return ret; +} + +#else + +#ifndef NO_MAIN_DRIVER +int main(int argc, char* argv[]) +#else +int add_cert(int argc, char* argv[]) +#endif +{ + (void)argc; + (void)argv; + fprintf(stderr, "Store disabled\n"); + return 0; +} + +#endif + diff --git a/examples/include.am b/examples/include.am index 362580a..865a735 100644 --- a/examples/include.am +++ b/examples/include.am @@ -21,6 +21,10 @@ noinst_PROGRAMS += examples/add_cert examples_add_cert_SOURCES = examples/add_cert.c examples_add_cert_LDADD = +noinst_PROGRAMS += examples/add_cert_file +examples_add_cert_file_SOURCES = examples/add_cert_file.c +examples_add_cert_file_LDADD = + noinst_PROGRAMS += examples/init_token examples_init_token_SOURCES = examples/init_token.c examples_init_token_LDADD = diff --git a/examples/obj_list.c b/examples/obj_list.c index ca60087..1846aaa 100644 --- a/examples/obj_list.c +++ b/examples/obj_list.c @@ -363,6 +363,48 @@ static CK_RV pkcs11_rsa_attr(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj) return ret; } +static CK_RV pkcs11_cert_attr(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj) +{ + CK_RV ret = CKR_OK; + CK_ATTRIBUTE getTmpl[] = { + { CKA_VALUE, NULL, 0 }, + }; + CK_ULONG getTmplCnt = sizeof(getTmpl) / sizeof(*getTmpl); + CK_ULONG i; + + printf("Get cert attr\n"); + + ret = funcList->C_GetAttributeValue(session, obj, getTmpl, getTmplCnt); + CHECK_CKR(ret, "Get Attribute Value sizes"); + + for (i = 0; i < getTmplCnt; i++) { + if (getTmpl[i].ulValueLen > 0) { + printf("cert attr, templ[%d].len = %d\n", (int)i, (int)getTmpl[i].ulValueLen); + getTmpl[i].pValue = malloc(getTmpl[i].ulValueLen * sizeof(byte)); + if (getTmpl[i].pValue == NULL) + ret = CKR_DEVICE_MEMORY; + CHECK_CKR(ret, "Allocate get attribute memory"); + } + } + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, getTmpl, getTmplCnt); + CHECK_CKR(ret, "Get Attribute Values"); + } + + if (ret == CKR_OK) { + i = 0; + pkcs11_print_data("Value", getTmpl[i].pValue, getTmpl[i].ulValueLen); + i++; + } + + for (i = 0; i < getTmplCnt; i++) { + free(getTmpl[i].pValue); + } + + return ret; +} + /* Retrieve the object attributes and display as text. * * return CKR_OK on success, other value on failure. @@ -429,6 +471,9 @@ static CK_RV pkcs11_obj_attr(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj) else if (objClass == CKO_SECRET_KEY) { ret = pkcs11_key_attr(session, obj, &keyType); } + else if (objClass == CKO_CERTIFICATE) { + ret = pkcs11_cert_attr(session, obj); + } } fprintf(stderr, "\n"); diff --git a/src/internal.c b/src/internal.c index 3fb5de4..f318fb6 100644 --- a/src/internal.c +++ b/src/internal.c @@ -141,7 +141,7 @@ typedef struct WP11_Data { /* Certificate */ typedef struct WP11_Cert { - byte data[WP11_MAX_CERT_SZ]; /* Certificate data */ + byte *data; /* Certificate data */ word32 len; /* Length of certificate data in bytes */ CK_CERTIFICATE_TYPE type; } WP11_Cert; @@ -1619,6 +1619,21 @@ static int wp11_Object_Store_Cert(WP11_Object* object, int tokenId, int objId) return ret; } +/** + * "Decode" the certificate. + * + * Certificates are not encrypted. + * + * @param [in, out] object Certificate object. + */ +static void wp11_Object_Decode_Cert(WP11_Object* object) +{ + object->data.cert.data = object->keyData; + object->data.cert.len = object->keyDataLen; + object->keyData = NULL; + object->encoded = 0; +} + #ifndef NO_RSA /** * Decode the RSA key. @@ -2808,7 +2823,7 @@ static int wp11_Object_Decode(WP11_Object* object) int ret; if (object->objClass == CKO_CERTIFICATE) { - object->encoded = 0; + wp11_Object_Decode_Cert(object); ret = 0; } else { @@ -4947,7 +4962,7 @@ void WP11_Object_Free(WP11_Object* object) if (object->keyId != NULL) XFREE(object->keyId, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (object->objClass == CKO_CERTIFICATE) { - XMEMSET(object->data.cert.data, 0, object->data.cert.len); + XFREE(object->data.cert.data, NULL, DYNAMIC_TYPE_CERT); } else { #ifndef NO_RSA @@ -4964,12 +4979,13 @@ void WP11_Object_Free(WP11_Object* object) #endif if (object->type == CKK_AES || object->type == CKK_GENERIC_SECRET) XMEMSET(object->data.symmKey.data, 0, object->data.symmKey.len); - #ifndef WOLFPKCS11_NO_STORE - if (object->keyData != NULL) - XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif } +#ifndef WOLFPKCS11_NO_STORE + if (object->keyData != NULL) + XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + /* Dispose of object. */ XFREE(object, NULL, DYNAMIC_TYPE_TMP_BUFFER); } @@ -5390,7 +5406,6 @@ int WP11_Object_SetCert(WP11_Object* object, unsigned char** data, cert = &object->data.cert; cert->len = 0; - XMEMSET(cert->data, 0, sizeof(cert->data)); /* First item is certificate type */ if (ret == 0 && data[0] != NULL && len[0] != (int)sizeof(CK_ULONG)) @@ -5400,13 +5415,20 @@ int WP11_Object_SetCert(WP11_Object* object, unsigned char** data, /* Second item is certificate data (CKA_VALUE) */ if (ret == 0 && data[1] != NULL) { - if ((word32)len[1] > sizeof(cert->data)) - ret = BUFFER_E; - else - cert->len = (word32)len[1]; + cert->len = (word32)len[1]; } - if (ret == 0 && data[1] != NULL) + if (ret == 0 && data[1] != NULL) { + if (cert->data != NULL) { + XFREE(cert->data, NULL, DYNAMIC_TYPE_CERT); + } + cert->data = (byte *)XMALLOC(cert->len, NULL, DYNAMIC_TYPE_CERT); + if (cert->data == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0 && data[1] != NULL) { XMEMCPY(cert->data, data[1], cert->len); + } if (object->onToken) WP11_Lock_UnlockRW(object->lock);