Added software accelerator.
--- /dev/null
+#
+# Makefile.ad
+#
+# Author: Pekka Riikonen <priikone@silcnet.org>
+#
+# Copyright (C) 2007 Pekka Riikonen
+#
+# This program 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; version 2 of the License.
+#
+# This program 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.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LTLIBRARIES = libsilcacc.la
+
+libsilcacc_la_SOURCES = silcacc.c silcacc_pkcs.c softacc.c
+
+#ifdef SILC_DIST_TOOLKIT
+include_HEADERS = silcacc.h
+#endif SILC_DIST_TOOLKIT
+
+EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
+
+include $(top_srcdir)/Makefile.defines.in
--- /dev/null
+/*
+
+ silcacc.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2007 Pekka Riikonen
+
+ This program 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; version 2 of the License.
+
+ This program 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.
+
+*/
+
+#include "silc.h"
+#include "softacc.h"
+
+/************************** Types and definitions ***************************/
+
+#ifndef SILC_SYMBIAN
+/* Dynamically registered list of accelerators. */
+SilcDList silc_acc_list = NULL;
+#endif /* SILC_SYMBIAN */
+
+/* Static list of accelerators */
+const SilcAcceleratorStruct *silc_default_accs[] =
+{
+#ifndef SILC_SYMBIAN
+ /* Software accelerator */
+ &softacc,
+#endif /* SILC_SYMBIAN */
+ NULL
+};
+
+/*************************** SILC Accelerator API ***************************/
+
+/* Register accelerator */
+
+SilcBool silc_acc_register(const SilcAccelerator acc)
+{
+ if (!acc)
+ return FALSE;
+
+ if (!silc_acc_list) {
+ silc_acc_list = silc_dlist_init();
+ if (!silc_acc_list)
+ return FALSE;
+ }
+
+ SILC_LOG_DEBUG(("Register accelerator %p, name %s", acc, acc->name));
+ silc_dlist_add(silc_acc_list, acc);
+
+ return TRUE;
+}
+
+/* Unregister accelerator */
+
+void silc_acc_unregister(SilcAccelerator acc)
+{
+ if (!acc)
+ return;
+
+ if (!silc_acc_list)
+ return;
+
+ SILC_LOG_DEBUG(("Unregister accelerator %p, name %s", acc, acc->name));
+ silc_dlist_del(silc_acc_list, acc);
+
+ if (!silc_dlist_count(silc_acc_list)) {
+ silc_dlist_uninit(silc_acc_list);
+ silc_acc_list = NULL;
+ }
+}
+
+/* Initialize accelerator */
+
+SilcBool silc_acc_init(SilcAccelerator acc, SilcSchedule schedule, ...)
+{
+ va_list va;
+ SilcBool ret;
+
+ if (!acc || !schedule)
+ return FALSE;
+
+ SILC_LOG_DEBUG(("Initialize accelerator %p, name %s", acc, acc->name));
+
+ va_start(va, schedule);
+ ret = acc->init(schedule, va);
+ va_end(va);
+
+ return ret;
+}
+
+/* Uninitialize accelerator */
+
+SilcBool silc_acc_uninit(SilcAccelerator acc)
+{
+ if (!acc)
+ return FALSE;
+
+ SILC_LOG_DEBUG(("Uninitialize accelerator %p, name %s", acc, acc->name));
+ return acc->uninit();
+}
+
+/* Get list of registered accelerator */
+
+SilcDList silc_acc_get_supported(void)
+{
+ SilcDList list;
+ SilcAccelerator acc;
+ int i;
+
+ list = silc_dlist_init();
+ if (!list)
+ return NULL;
+
+ if (silc_acc_list) {
+ silc_dlist_start(silc_acc_list);
+ while ((acc = silc_dlist_get(silc_acc_list)))
+ silc_dlist_add(list, acc);
+ }
+
+ for (i = 0; silc_default_accs[i]->name; i++)
+ silc_dlist_add(list, (void *)silc_default_accs[i]);
+
+ return list;
+}
+
+/* Get accelerator */
+
+SilcAccelerator silc_acc_find(const char *name)
+{
+ SilcAccelerator acc;
+ int i;
+
+ if (!name)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Find accelerator %s", name));
+
+ if (silc_acc_list) {
+ silc_dlist_start(silc_acc_list);
+ while ((acc = silc_dlist_get(silc_acc_list))) {
+ if (!strcmp(acc->name, name)) {
+ SILC_LOG_DEBUG(("Found accelerator %p", acc));
+ return acc;
+ }
+ }
+ }
+
+ for (i = 0; silc_default_accs[i]->name; i++) {
+ if (!strcmp(silc_default_accs[i]->name, name)) {
+ SILC_LOG_DEBUG(("Found accelerator %p", silc_default_accs[i]));
+ return (SilcAccelerator)silc_default_accs[i];
+ }
+ }
+
+ SILC_LOG_DEBUG(("Accelerator %s does not exist", name));
+ return NULL;
+}
+
+/* Get accelerator name */
+
+const char *silc_acc_get_name(SilcAccelerator acc)
+{
+ if (!acc)
+ return NULL;
+ return acc->name;
+}
--- /dev/null
+/*
+
+ silcacc.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2007 Pekka Riikonen
+
+ This program 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; version 2 of the License.
+
+ This program 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.
+
+*/
+
+/****h* silcskr/SILC Accelerator Interface
+ *
+ * DESCRIPTION
+ *
+ ***/
+
+#ifndef SILCACC_H
+#define SILCACC_H
+
+/****s* silcacc/SilcAccAPI/SilcAccelerator
+ *
+ * NAME
+ *
+ * typedef struct SilcAcceleratorObject { ... }
+ * *SilcAccelerator, SilcAcceleratorStruct;
+ *
+ * DESCRIPTION
+ *
+ * The accelerator context. This is given as argument to silc_acc_register
+ * when registering new accelerator, and it is given as argument to all
+ * other silc_acc_* functions. Registered accelerator context can be
+ * retrieved by calling silc_acc_find.
+ *
+ ***/
+typedef struct SilcAcceleratorObject {
+ const char *name; /* Accelerator's name */
+ SilcBool (*init)(SilcSchedule schedule,
+ va_list va); /* Initialize accelerator */
+ SilcBool (*uninit)(void); /* Uninitialize accelerator */
+ const SilcPKCSAlgorithm *pkcs; /* Accelerated PKCS algorithms */
+#if 0
+ const SilcDHObject *dh; /* Accelerated Diffie-Hellmans */
+ const SilcCipherObject *cipher; /* Accelerated ciphers */
+ const SilcHashObject *hash; /* Accelerated hashes */
+ const SilcHmacObject *hmac; /* Accelerated HMACs */
+ const SilcRngObject *rng; /* Accelerated RNG's */
+#endif /* 0 */
+} *SilcAccelerator, SilcAcceleratorStruct;
+
+/****f* silcacc/SilcAccAPI/silc_acc_register
+ *
+ * SYNOPSIS
+ *
+ * SilcBool silc_acc_register(const SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ * Register new accelerator to the accelerator library. The `acc'
+ * is the accelerator context to be registered.
+ *
+ * NOTES
+ *
+ * This needs to be called only when adding new accelerator to the
+ * library. The accelerator library has some pre-registered accelerators
+ * that need not be registered with this call.
+ *
+ ***/
+SilcBool silc_acc_register(const SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_unregister
+ *
+ * SYNOPSIS
+ *
+ * void silc_acc_unregister(SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ * Unregister the accelerator `acc' from the accelerator library. The
+ * accelerator cannot be used anymore after this call has returned.
+ *
+ ***/
+void silc_acc_unregister(SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_init
+ *
+ * SYNOPSIS
+ *
+ * SilcBool silc_acc_init(SilcAccelerator acc, SilcSchedule schedule, ...);
+ *
+ * DESCRIPTION
+ *
+ * Initialize accelerator `acc'. Usually accelerator may be initialized
+ * only once and should be done after registering it. The `schedule'
+ * must be given as argument, in case the accelerator needs to do operations
+ * through the scheduler. The variable argument list is optional
+ * accelerator specific initialization arguments. The argument list must
+ * be ended with NULL. Returns FALSE if initialization failed.
+ *
+ * EXAMPLE
+ *
+ * silc_acc_init(softacc, "min_threads", 2, "max_threads", 16, NULL);
+ *
+ ***/
+SilcBool silc_acc_init(SilcAccelerator acc, SilcSchedule schedule, ...);
+
+/****f* silcacc/SilcAccAPI/silc_acc_uninit
+ *
+ * SYNOPSIS
+ *
+ * SilcBool silc_acc_uninit(SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ * Uninitialize the accelerator `acc'. The accelerator may not be used
+ * after this call has returned. Some accelerators may be re-initialized
+ * by calling silc_acc_init again. Returns FALSE if error occurred
+ * during uninitializing.
+ *
+ ***/
+SilcBool silc_acc_uninit(SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_supported
+ *
+ * SYNOPSIS
+ *
+ * SilcDList silc_acc_get_supported(void);
+ *
+ * DESCRIPTION
+ *
+ * Returns list of registered accelerators. The caller must free the
+ * returned list by calling silc_dlist_uninit.
+ *
+ ***/
+SilcDList silc_acc_get_supported(void);
+
+/****f* silcacc/SilcAccAPI/silc_acc_find
+ *
+ * SYNOPSIS
+ *
+ * SilcAccelerator silc_acc_find(const char *name);
+ *
+ * DESCRIPTION
+ *
+ * Find accelerator by its name indicated by `name'. Returns the
+ * accelerator context or NULL if such accelerator is not registered.
+ *
+ ***/
+SilcAccelerator silc_acc_find(const char *name);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_name
+ *
+ * SYNOPSIS
+ *
+ * const char *silc_acc_get_name(SilcAccelerator acc);
+ *
+ * DESCRIPTION
+ *
+ * Returns the name of the accelerator `acc'.
+ *
+ ***/
+const char *silc_acc_get_name(SilcAccelerator acc);
+
+/****f* silcacc/SilcAccAPI/silc_acc_public_key
+ *
+ * SYNOPSIS
+ *
+ * SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
+ * SilcPublicKey public_key);
+ *
+ * DESCRIPTION
+ *
+ * Accelerate the public key indicated by `public_key'. Returns new
+ * accelerated SilcPublicKey context. It can be used just as normal
+ * public key and must be freed by calling silc_pkcs_public_key_free.
+ * The associated `public_key' is not freed when the accelerated public
+ * key is freed. The `public_key' must not be freed as long as it is
+ * accelerated.
+ *
+ * The associated `public_key' can be retrieved from the returned
+ * public key by calling silc_acc_get_public_key.
+ *
+ ***/
+SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
+ SilcPublicKey public_key);
+
+/****f* silcacc/SilcAccAPI/silc_acc_private_key
+ *
+ * SYNOPSIS
+ *
+ * SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
+ * SilcPrivateKey private_key);
+ *
+ * DESCRIPTION
+ *
+ * Accelerate the private key indicated by `private_key'. Returns new
+ * accelerated SilcPrivateKey context. It can be used just as normal
+ * private key and must be freed by calling silc_pkcs_private_key_free.
+ * The associated `private_key' is not freed when the accelerated private
+ * key is freed. The `private_key' must not be freed as long as it is
+ * accelerated.
+ *
+ * The associated `private_key' can be retrieved from the returned
+ * private key by calling silc_acc_get_private_key.
+ *
+ ***/
+SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
+ SilcPrivateKey private_key);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_public_key
+ *
+ * SYNOPSIS
+ *
+ * SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
+ * SilcPublicKey public_key);
+ *
+ * DESCRIPTION
+ *
+ * Returns the underlaying public key from the accelerated public key
+ * indicated by `public_key'. Returns NULL if `public_key' is not
+ * accelerated public key.
+ *
+ ***/
+SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
+ SilcPublicKey public_key);
+
+/****f* silcacc/SilcAccAPI/silc_acc_get_private_key
+ *
+ * SYNOPSIS
+ *
+ * SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
+ * SilcPrivateKey private_key);
+ *
+ * DESCRIPTION
+ *
+ * Returns the underlaying private key from the accelerated private key
+ * indicated by `private_key'. Returns NULL if `private_key' is not
+ * accelerated private key.
+ *
+ ***/
+SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
+ SilcPrivateKey private_key);
+
+#endif /* SILCACC_H */
--- /dev/null
+/*
+
+ silcacc_pkcs.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2007 Pekka Riikonen
+
+ This program 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; version 2 of the License.
+
+ This program 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.
+
+*/
+
+#include "silc.h"
+
+/************************** Types and definitions ***************************/
+
+SILC_PKCS_GET_ALGORITHM(silc_acc_pkcs_get_algorithm);
+SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_import_public_key_file);
+SILC_PKCS_IMPORT_PUBLIC_KEY(silc_acc_pkcs_import_public_key);
+SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_export_public_key_file);
+SILC_PKCS_EXPORT_PUBLIC_KEY(silc_acc_pkcs_export_public_key);
+SILC_PKCS_PUBLIC_KEY_BITLEN(silc_acc_pkcs_public_key_bitlen);
+SILC_PKCS_PUBLIC_KEY_COPY(silc_acc_pkcs_public_key_copy);
+SILC_PKCS_PUBLIC_KEY_COMPARE(silc_acc_pkcs_public_key_compare);
+SILC_PKCS_PUBLIC_KEY_FREE(silc_acc_pkcs_public_key_free);
+SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_import_private_key_file);
+SILC_PKCS_IMPORT_PRIVATE_KEY(silc_acc_pkcs_import_private_key);
+SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_export_private_key_file);
+SILC_PKCS_EXPORT_PRIVATE_KEY(silc_acc_pkcs_export_private_key);
+SILC_PKCS_PRIVATE_KEY_BITLEN(silc_acc_pkcs_private_key_bitlen);
+SILC_PKCS_PRIVATE_KEY_FREE(silc_acc_pkcs_private_key_free);
+SILC_PKCS_ENCRYPT(silc_acc_pkcs_encrypt);
+SILC_PKCS_DECRYPT(silc_acc_pkcs_decrypt);
+SILC_PKCS_SIGN(silc_acc_pkcs_sign);
+SILC_PKCS_VERIFY(silc_acc_pkcs_verify);
+
+/* Accelerator public key */
+typedef struct {
+ int pkcs_index; /* Accelerator PKCS index */
+ SilcAccelerator acc; /* The accelerator */
+ void *context; /* Accelerator context */
+ SilcPublicKey accelerated; /* Associated public key */
+} *SilcAcceleratorPublicKey;
+
+/* Accelerator private key */
+typedef struct {
+ int pkcs_index; /* Accelerator PKCS index */
+ SilcAccelerator acc; /* The accelerator */
+ void *context; /* Accelerator context */
+ SilcPrivateKey accelerated; /* Associated private key */
+} *SilcAcceleratorPrivateKey;
+
+/*************************** Accelerator PKCS API ***************************/
+
+/* The PKCS API for the accelerated public key and private key is simply
+ a wrapper for the underlaying key. Encrypt, decrypt, sign and verify
+ operations are accelerated by calling the accelerator operations. */
+
+const SilcPKCSObject silc_acc_pkcs =
+{
+ SILC_PKCS_SILC,
+
+ /* Wrappers */
+ silc_acc_pkcs_get_algorithm,
+ silc_acc_pkcs_import_public_key_file,
+ silc_acc_pkcs_import_public_key,
+ silc_acc_pkcs_export_public_key_file,
+ silc_acc_pkcs_export_public_key,
+ silc_acc_pkcs_public_key_bitlen,
+ silc_acc_pkcs_public_key_copy,
+ silc_acc_pkcs_public_key_compare,
+ silc_acc_pkcs_public_key_free,
+ silc_acc_pkcs_import_private_key_file,
+ silc_acc_pkcs_import_private_key,
+ silc_acc_pkcs_export_private_key_file,
+ silc_acc_pkcs_export_private_key,
+ silc_acc_pkcs_private_key_bitlen,
+ silc_acc_pkcs_private_key_free,
+
+ /* Accelerated */
+ silc_acc_pkcs_encrypt,
+ silc_acc_pkcs_decrypt,
+ silc_acc_pkcs_sign,
+ silc_acc_pkcs_verify
+};
+
+SILC_PKCS_GET_ALGORITHM(silc_acc_pkcs_get_algorithm)
+{
+ SilcAcceleratorPublicKey pub = public_key;
+ return pub->accelerated->pkcs->get_algorithm(pub->accelerated->pkcs,
+ pub->accelerated->public_key);
+}
+
+SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_import_public_key_file)
+{
+ /* Not implemented */
+ return FALSE;
+}
+
+SILC_PKCS_IMPORT_PUBLIC_KEY(silc_acc_pkcs_import_public_key)
+{
+ /* Not implemented */
+ return FALSE;
+}
+
+SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_acc_pkcs_export_public_key_file)
+{
+ SilcAcceleratorPublicKey pub = public_key;
+ return pub->accelerated->pkcs->
+ export_public_key_file(pub->accelerated->pkcs, NULL,
+ pub->accelerated->public_key,
+ encoding, ret_len);
+}
+
+SILC_PKCS_EXPORT_PUBLIC_KEY(silc_acc_pkcs_export_public_key)
+{
+ SilcAcceleratorPublicKey pub = public_key;
+ return pub->accelerated->pkcs->export_public_key(pub->accelerated->pkcs,
+ NULL,
+ pub->accelerated->public_key,
+ ret_len);
+}
+
+SILC_PKCS_PUBLIC_KEY_BITLEN(silc_acc_pkcs_public_key_bitlen)
+{
+ SilcAcceleratorPublicKey pub = public_key;
+ return pub->accelerated->pkcs->
+ public_key_bitlen(pub->accelerated->pkcs,
+ pub->accelerated->public_key);
+}
+
+SILC_PKCS_PUBLIC_KEY_COPY(silc_acc_pkcs_public_key_copy)
+{
+ SilcAcceleratorPublicKey pub = public_key;
+ return pub->accelerated->pkcs->public_key_copy(pub->accelerated->pkcs,
+ pub->accelerated->public_key);
+}
+
+SILC_PKCS_PUBLIC_KEY_COMPARE(silc_acc_pkcs_public_key_compare)
+{
+ /* XXX */
+ return FALSE;
+}
+
+SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_import_private_key_file)
+{
+ return 0;
+}
+
+SILC_PKCS_IMPORT_PRIVATE_KEY(silc_acc_pkcs_import_private_key)
+{
+ return 0;
+}
+
+SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_acc_pkcs_export_private_key_file)
+{
+ return 0;
+}
+
+SILC_PKCS_EXPORT_PRIVATE_KEY(silc_acc_pkcs_export_private_key)
+{
+ return 0;
+}
+
+SILC_PKCS_PRIVATE_KEY_BITLEN(silc_acc_pkcs_private_key_bitlen)
+{
+ return 0;
+}
+
+SILC_PKCS_PUBLIC_KEY_FREE(silc_acc_pkcs_public_key_free)
+{
+
+}
+
+SILC_PKCS_PRIVATE_KEY_FREE(silc_acc_pkcs_private_key_free)
+{
+
+}
+
+SILC_PKCS_ENCRYPT(silc_acc_pkcs_encrypt)
+{
+ SilcAcceleratorPublicKey pub = public_key;
+
+ /* Accelerate */
+ return pub->acc->pkcs[pub->pkcs_index].encrypt(
+ &pub->acc->pkcs[pub->pkcs_index], pub->context, src,
+ src_len, rng, encrypt_cb, context);
+}
+
+SILC_PKCS_DECRYPT(silc_acc_pkcs_decrypt)
+{
+ SilcAcceleratorPrivateKey prv = private_key;
+
+ /* Accelerate */
+ return prv->acc->pkcs[prv->pkcs_index].decrypt(
+ &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
+ src_len, decrypt_cb, context);
+}
+
+SILC_PKCS_SIGN(silc_acc_pkcs_sign)
+{
+ SilcAcceleratorPrivateKey prv = private_key;
+
+ /* Accelerate */
+ return prv->acc->pkcs[prv->pkcs_index].sign(
+ &prv->acc->pkcs[prv->pkcs_index], prv->context, src,
+ src_len, compute_hash, hash, sign_cb, context);
+}
+
+SILC_PKCS_VERIFY(silc_acc_pkcs_verify)
+{
+ SilcAcceleratorPublicKey pub = public_key;
+
+ /* Accelerate */
+ return pub->acc->pkcs[pub->pkcs_index].verify(
+ &pub->acc->pkcs[pub->pkcs_index], pub->context,
+ signature, signature_len, data, data_len, hash,
+ verify_cb, context);
+}
+
+/*************************** SILC Accelerator API ***************************/
+
+/* Accelerate public key */
+
+SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
+ SilcPublicKey public_key)
+{
+ SilcPublicKey pubkey;
+ SilcAcceleratorPublicKey acc_pubkey;
+ const SilcPKCSAlgorithm *alg;
+ int i;
+
+ if (!acc || !public_key)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Accelerate public key %p with accelerator %s",
+ public_key, acc->name));
+
+ if (!acc->pkcs) {
+ SILC_LOG_ERROR(("Accelerator '%s' does not support public key "
+ "acceleration", acc->name));
+ return NULL;
+ }
+
+ /* Check that accelerator supports this public key algorithm */
+ alg = silc_pkcs_get_algorithm(public_key);
+ if (!alg)
+ return NULL;
+ for (i = 0; acc->pkcs[i].name; i++) {
+ if ((!strcmp(acc->pkcs[i].name, alg->name) &&
+ !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
+ !strcmp(acc->pkcs[i].name, "any")) {
+ alg = NULL;
+ break;
+ }
+ }
+ if (alg) {
+ SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
+ alg->name, alg->scheme));
+ return NULL;
+ }
+
+ pubkey = silc_calloc(1, sizeof(*pubkey));
+ if (!pubkey)
+ return NULL;
+
+ /* Allocate PKCS operations */
+ pubkey->pkcs = silc_calloc(1, sizeof(*pubkey->pkcs));
+ if (!pubkey->pkcs) {
+ silc_free(pubkey);
+ return NULL;
+ }
+ *pubkey->pkcs = silc_acc_pkcs;
+ pubkey->pkcs->type = silc_pkcs_get_type(public_key);
+
+ /* Allocate accelerator public key */
+ acc_pubkey = silc_calloc(1, sizeof(*acc_pubkey));
+ if (!acc_pubkey) {
+ silc_free(pubkey->pkcs);
+ silc_free(pubkey);
+ return NULL;
+ }
+ acc_pubkey->accelerated = public_key;
+ acc_pubkey->acc = acc;
+ acc_pubkey->pkcs_index = i;
+
+ /* Accelerate the public key. Returns accelerator context. */
+ if (!acc->pkcs->import_public_key(&acc->pkcs[i], public_key, 0,
+ &acc_pubkey->context)) {
+ SILC_LOG_ERROR(("Error accelerating public key with accelerator '%s'",
+ acc->name));
+ silc_free(acc_pubkey);
+ silc_free(pubkey->pkcs);
+ silc_free(pubkey);
+ return NULL;
+ }
+ pubkey->public_key = acc_pubkey;
+
+ SILC_LOG_DEBUG(("New accelerated public key %p", pubkey));
+
+ return pubkey;
+}
+
+/* Accelerate private key */
+
+SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
+ SilcPrivateKey private_key)
+{
+ SilcPrivateKey privkey;
+ SilcAcceleratorPrivateKey acc_privkey;
+ const SilcPKCSAlgorithm *alg;
+ int i;
+
+ if (!acc || !private_key)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Accelerate private key %p with accelerator %s",
+ private_key, acc->name));
+
+ if (!acc->pkcs) {
+ SILC_LOG_ERROR(("Accelerator '%s' does not support private key "
+ "acceleration", acc->name));
+ return NULL;
+ }
+
+ /* Check that accelerator supports this private key algorithm */
+ alg = silc_pkcs_get_algorithm(private_key);
+ if (!alg)
+ return NULL;
+ for (i = 0; acc->pkcs[i].name; i++) {
+ if ((!strcmp(acc->pkcs[i].name, alg->name) &&
+ !strcmp(acc->pkcs[i].scheme, alg->scheme)) ||
+ !strcmp(acc->pkcs[i].name, "any")) {
+ alg = NULL;
+ break;
+ }
+ }
+ if (alg) {
+ SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration",
+ alg->name, alg->scheme));
+ return NULL;
+ }
+
+ privkey = silc_calloc(1, sizeof(*privkey));
+ if (!privkey)
+ return NULL;
+
+ /* Allocate PKCS operations */
+ privkey->pkcs = silc_calloc(1, sizeof(*privkey->pkcs));
+ if (!privkey->pkcs) {
+ silc_free(privkey);
+ return NULL;
+ }
+ *privkey->pkcs = silc_acc_pkcs;
+ privkey->pkcs->type = silc_pkcs_get_type(private_key);
+
+ /* Allocate accelerator public key */
+ acc_privkey = silc_calloc(1, sizeof(*acc_privkey));
+ if (!acc_privkey) {
+ silc_free(privkey->pkcs);
+ silc_free(privkey);
+ return NULL;
+ }
+ acc_privkey->accelerated = private_key;
+ acc_privkey->acc = acc;
+ acc_privkey->pkcs_index = i;
+
+ /* Accelerate the public key. Returns accelerator context. */
+ if (!acc->pkcs->import_private_key(&acc->pkcs[i], private_key, 0,
+ &acc_privkey->context)) {
+ SILC_LOG_ERROR(("Error accelerating private key with accelerator '%s'",
+ acc->name));
+ silc_free(acc_privkey);
+ silc_free(privkey->pkcs);
+ silc_free(privkey);
+ return NULL;
+ }
+ privkey->private_key = acc_privkey;
+
+ SILC_LOG_DEBUG(("New accelerated private key %p", privkey));
+
+ return privkey;
+}
+
+/* Get associated public key */
+
+SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
+ SilcPublicKey public_key)
+{
+ SilcAcceleratorPublicKey pubkey;
+
+ if (!public_key)
+ return NULL;
+
+ if (public_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
+ return NULL;
+
+ pubkey = public_key->public_key;
+
+ return pubkey->accelerated;
+}
+
+/* Get associated private key */
+
+SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
+ SilcPrivateKey private_key)
+{
+ SilcAcceleratorPrivateKey privkey;
+
+ if (!private_key)
+ return NULL;
+
+ if (private_key->pkcs->get_algorithm != silc_acc_pkcs_get_algorithm)
+ return NULL;
+
+ privkey = private_key->private_key;
+
+ return privkey->accelerated;
+}
--- /dev/null
+/*
+
+ softacc.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2007 Pekka Riikonen
+
+ This program 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; version 2 of the License.
+
+ This program 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.
+
+*/
+
+#include "silc.h"
+#include "softacc.h"
+
+/* Software accelerator is a thread-pool system where public key and private
+ key operations are executed in threads for the purpose of off-loading and
+ balancing the computations across multiple processors. */
+
+#define SILC_SOFTACC_MIN_THREADS 0
+#define SILC_SOFTACC_MAX_THREADS 4
+
+/************************** Types and definitions ***************************/
+
+/* Software accelerator PKCS algorithm operations */
+const SilcPKCSAlgorithm softacc_pkcs[] =
+{
+ {
+ "any", "any", NULL, NULL,
+ silc_softacc_acc_public_key,
+ NULL, NULL, NULL, NULL,
+ silc_softacc_free_public_key,
+ silc_softacc_acc_private_key,
+ NULL, NULL,
+ silc_softacc_free_private_key,
+ silc_softacc_encrypt,
+ silc_softacc_decrypt,
+ silc_softacc_sign,
+ silc_softacc_verify,
+ },
+
+ {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL
+ }
+};
+
+/* Software accelerator operations */
+const SilcAcceleratorStruct softacc =
+{
+ "softacc", silc_softacc_init, silc_softacc_uninit, softacc_pkcs
+};
+
+/* Software accelerator public key */
+typedef struct {
+ SilcPublicKey key; /* Accelerated public key */
+} *SilcSoftaccPublicKey;
+
+/* Software accelerator private key */
+typedef struct {
+ SilcPrivateKey key; /* Accelerated private key */
+} *SilcSoftaccPrivateKey;
+
+/* Execution types */
+typedef enum {
+ SILC_SOFTACC_ENCRYPT,
+ SILC_SOFTACC_DECRYPT,
+ SILC_SOFTACC_SIGN,
+ SILC_SOFTACC_VERIFY,
+} SilcSoftaccType;
+
+/* Executor context */
+typedef struct {
+ SilcStack stack; /* Executor stack */
+ void *context; /* Callback context */
+ SilcSoftaccType type; /* Execution type */
+ SilcAsyncOperationStruct op; /* Operation for aborting */
+
+ unsigned char *src; /* Source data */
+ unsigned char *data; /* More source data */
+ SilcUInt32 src_len;
+ SilcUInt32 data_len;
+ SilcHash hash; /* Hash function to use */
+ SilcRng rng; /* RNG, may be NULL */
+
+ union {
+ SilcPublicKey public_key;
+ SilcPrivateKey private_key;
+ } key;
+
+ union {
+ SilcPKCSEncryptCb encrypt_cb;
+ SilcPKCSDecryptCb decrypt_cb;
+ SilcPKCSSignCb sign_cb;
+ SilcPKCSVerifyCb verify_cb;
+ } cb;
+
+ unsigned char *result_data;
+ SilcUInt32 result_len;
+
+ unsigned int result : 1;
+ unsigned int compute_hash : 1;
+ unsigned int aborted : 1;
+} *SilcSoftaccExec;
+
+/* Software accelerator context */
+typedef struct {
+ SilcSchedule schedule; /* Scheduler */
+ SilcThreadPool tp; /* The thread pool */
+} *SilcSoftacc;
+
+SilcSoftacc sa = NULL; /* The accelerator */
+
+/***************************** Accelerator API ******************************/
+
+/* Initialize software accelerator. Optional initialization parameters:
+
+ min_threads number Minimum number of threads (default 0)
+ max_thread number Maximum number of threads (default 4)
+
+ Eg. silc_acc_init(softacc, "min_threads", 2, "max_threads", 8, NULL);
+
+*/
+
+SilcBool silc_softacc_init(SilcSchedule schedule, va_list va)
+{
+ SilcUInt32 min_threads = SILC_SOFTACC_MIN_THREADS;
+ SilcUInt32 max_threads = SILC_SOFTACC_MAX_THREADS;
+ char *opt;
+
+ if (!schedule)
+ return FALSE;
+
+ /* If already initialized, uninitialize first. */
+ if (sa)
+ silc_softacc_uninit();
+
+ /* Get options */
+ while ((opt = va_arg(va, char *))) {
+ if (!strcmp(opt, "min_threads"))
+ min_threads = va_arg(va, SilcUInt32);
+ else if (!strcmp(opt, "max_threads"))
+ max_threads = va_arg(va, SilcUInt32);
+ }
+
+ SILC_LOG_DEBUG(("Initialize software accelerator, min_threads %d, "
+ "max_threads %d", min_threads, max_threads));
+
+ sa = silc_calloc(1, sizeof(*sa));
+ if (!sa)
+ return FALSE;
+
+ sa->schedule = schedule;
+
+ /* Start the thread pool */
+ sa->tp = silc_thread_pool_alloc(NULL, min_threads, max_threads, TRUE);
+ if (!sa->tp) {
+ silc_free(sa);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Uninitialize */
+
+SilcBool silc_softacc_uninit(void)
+{
+ if (!sa)
+ return FALSE;
+
+ SILC_LOG_DEBUG(("Uninitialize software accelerator"));
+
+ silc_thread_pool_free(sa->tp, TRUE);
+ silc_free(sa);
+ sa = NULL;
+
+ return TRUE;
+}
+
+/****************************** PKCS ALG API ********************************/
+
+/* Abort operation */
+
+void silc_softacc_abort(SilcAsyncOperation op, void *context)
+{
+ SilcSoftaccExec e = context;
+ e->aborted = TRUE;
+}
+
+/* Accelerator completion, executed in main thread. */
+
+SILC_TASK_CALLBACK(silc_softacc_completion)
+{
+ SilcSoftaccExec e = context;
+ SilcStack stack = e->stack;
+
+ /* At the latest, abort is catched here in the main thread. Don't
+ deliver callback if we were aborted */
+ if (e->aborted)
+ goto out;
+
+ SILC_LOG_DEBUG(("Call completion, result=%s", e->result ? "Ok" : "failed"));
+
+ /* Call completion callback */
+ switch (e->type) {
+ case SILC_SOFTACC_ENCRYPT:
+ e->cb.encrypt_cb(e->result, e->result_data, e->result_len, e->context);
+ break;
+
+ case SILC_SOFTACC_DECRYPT:
+ e->cb.decrypt_cb(e->result, e->result_data, e->result_len, e->context);
+ break;
+
+ case SILC_SOFTACC_SIGN:
+ e->cb.sign_cb(e->result, e->result_data, e->result_len, e->context);
+ break;
+
+ case SILC_SOFTACC_VERIFY:
+ e->cb.verify_cb(e->result, e->context);
+ break;
+ }
+
+ out:
+ silc_sfree(stack, e->src);
+ silc_sfree(stack, e->data);
+ silc_sfree(stack, e);
+ silc_stack_free(stack);
+}
+
+/* Callback for encrypt, decrypt and signature */
+
+void silc_softacc_data_cb(SilcBool success, const unsigned char *data,
+ SilcUInt32 data_len, void *context)
+{
+ SilcSoftaccExec e = context;
+ SilcStack stack = e->stack;
+
+ /* Pop e->src and e->data from memory */
+ silc_stack_pop(stack);
+
+ if (success)
+ e->result_data = silc_smemdup(stack, data, data_len);
+ e->result_len = data_len;
+ e->result = success;
+}
+
+/* Verification callback */
+
+void silc_softacc_verify_cb(SilcBool success, void *context)
+{
+ SilcSoftaccExec e = context;
+ SilcStack stack = e->stack;
+
+ silc_stack_pop(stack);
+ e->result = success;
+}
+
+/* Accelerator thread */
+
+void silc_softacc_thread(SilcSchedule schedule, void *context)
+{
+ SilcSoftaccExec e = context;
+
+ if (e->aborted)
+ return;
+
+ SILC_LOG_DEBUG(("Execute type %d", e->type));
+
+ /* Call the operation */
+ switch (e->type) {
+ case SILC_SOFTACC_ENCRYPT:
+ silc_pkcs_encrypt(e->key.public_key, e->src, e->src_len, e->rng,
+ silc_softacc_data_cb, e);
+ break;
+
+ case SILC_SOFTACC_DECRYPT:
+ silc_pkcs_decrypt(e->key.private_key, e->src, e->src_len,
+ silc_softacc_data_cb, e);
+ break;
+
+ case SILC_SOFTACC_SIGN:
+ silc_pkcs_sign(e->key.private_key, e->src, e->src_len, e->compute_hash,
+ e->hash, silc_softacc_data_cb, e);
+ break;
+
+ case SILC_SOFTACC_VERIFY:
+ silc_pkcs_verify(e->key.public_key, e->src, e->src_len, e->data,
+ e->data_len, e->hash, silc_softacc_verify_cb, e);
+ break;
+ }
+}
+
+/* Accelerate public key */
+
+SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key)
+{
+ SilcSoftaccPublicKey pubkey;
+
+ if (!sa) {
+ SILC_LOG_ERROR(("Software accelerator not initialized"));
+ return FALSE;
+ }
+
+ pubkey = silc_calloc(1, sizeof(*pubkey));
+ if (!pubkey)
+ return FALSE;
+ pubkey->key = key;
+
+ *ret_public_key = pubkey;
+
+ return TRUE;
+}
+
+/* Accelerate private key */
+
+SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key)
+{
+ SilcSoftaccPrivateKey privkey;
+
+ if (!sa) {
+ SILC_LOG_ERROR(("Software accelerator not initialized"));
+ return FALSE;
+ }
+
+ privkey = silc_calloc(1, sizeof(*privkey));
+ if (!privkey)
+ return FALSE;
+ privkey->key = key;
+
+ *ret_private_key = privkey;
+
+ return TRUE;
+}
+
+/* Free public key */
+
+SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key)
+{
+ silc_free(public_key);
+}
+
+/* Free private key */
+
+SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key)
+{
+ silc_free(private_key);
+}
+
+/* Accelerated encrypt */
+
+SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt)
+{
+ SilcSoftaccPublicKey pubkey = public_key;
+ SilcStack stack;
+ SilcSoftaccExec e;
+
+ SILC_LOG_DEBUG(("Encrypt"));
+
+ if (!sa) {
+ SILC_LOG_ERROR(("Software accelerator not initialized"));
+ encrypt_cb(FALSE, NULL, 0, context);
+ return NULL;
+ }
+
+ stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+ e = silc_scalloc(stack, 1, sizeof(*e));
+ if (!e) {
+ silc_stack_free(stack);
+ encrypt_cb(FALSE, NULL, 0, context);
+ return NULL;
+ }
+
+ silc_stack_push(stack, NULL);
+
+ e->stack = stack;
+ e->type = SILC_SOFTACC_ENCRYPT;
+ e->src = silc_smemdup(stack, src, src_len);
+ e->src_len = src_len;
+ e->rng = rng;
+ e->key.public_key = pubkey->key;
+ e->cb.encrypt_cb = encrypt_cb;
+ e->context = context;
+ silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+ /* Run */
+ silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+ silc_softacc_completion, e);
+
+ return &e->op;
+}
+
+/* Acceleted decrypt */
+
+SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt)
+{
+ SilcSoftaccPrivateKey privkey = private_key;
+ SilcStack stack;
+ SilcSoftaccExec e;
+
+ SILC_LOG_DEBUG(("Decrypt"));
+
+ if (!sa) {
+ SILC_LOG_ERROR(("Software accelerator not initialized"));
+ decrypt_cb(FALSE, NULL, 0, context);
+ return NULL;
+ }
+
+ stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+ e = silc_scalloc(stack, 1, sizeof(*e));
+ if (!e) {
+ silc_stack_free(stack);
+ decrypt_cb(FALSE, NULL, 0, context);
+ return NULL;
+ }
+
+ silc_stack_push(stack, NULL);
+
+ e->stack = stack;
+ e->type = SILC_SOFTACC_DECRYPT;
+ e->src = silc_smemdup(stack, src, src_len);
+ e->src_len = src_len;
+ e->key.private_key = privkey->key;
+ e->cb.decrypt_cb = decrypt_cb;
+ e->context = context;
+ silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+ /* Run */
+ silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+ silc_softacc_completion, e);
+
+ return &e->op;
+}
+
+/* Accelerated signature */
+
+SILC_PKCS_ALG_SIGN(silc_softacc_sign)
+{
+ SilcSoftaccPrivateKey privkey = private_key;
+ SilcStack stack;
+ SilcSoftaccExec e;
+
+ SILC_LOG_DEBUG(("Sign"));
+
+ if (!sa) {
+ SILC_LOG_ERROR(("Software accelerator not initialized"));
+ sign_cb(FALSE, NULL, 0, context);
+ return NULL;
+ }
+
+ stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+ e = silc_scalloc(stack, 1, sizeof(*e));
+ if (!e) {
+ silc_stack_free(stack);
+ sign_cb(FALSE, NULL, 0, context);
+ return NULL;
+ }
+
+ silc_stack_push(stack, NULL);
+
+ e->stack = stack;
+ e->type = SILC_SOFTACC_SIGN;
+ e->src = silc_smemdup(stack, src, src_len);
+ e->src_len = src_len;
+ e->compute_hash = compute_hash;
+ e->hash = hash;
+ e->key.private_key = privkey->key;
+ e->cb.sign_cb = sign_cb;
+ e->context = context;
+ silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+ /* Run */
+ silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+ silc_softacc_completion, e);
+
+ return &e->op;
+}
+
+/* Accelerated verification */
+
+SILC_PKCS_ALG_VERIFY(silc_softacc_verify)
+{
+ SilcSoftaccPublicKey pubkey = public_key;
+ SilcStack stack;
+ SilcSoftaccExec e;
+
+ SILC_LOG_DEBUG(("Verify"));
+
+ if (!sa) {
+ SILC_LOG_ERROR(("Software accelerator not initialized"));
+ verify_cb(FALSE, context);
+ return NULL;
+ }
+
+ stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+ e = silc_scalloc(stack, 1, sizeof(*e));
+ if (!e) {
+ silc_stack_free(stack);
+ verify_cb(FALSE, context);
+ return NULL;
+ }
+
+ silc_stack_push(stack, NULL);
+
+ e->stack = stack;
+ e->type = SILC_SOFTACC_VERIFY;
+ e->src = silc_smemdup(stack, signature, signature_len);
+ e->src_len = signature_len;
+ e->data = silc_smemdup(stack, data, data_len);
+ e->data_len = data_len;
+ e->hash = hash;
+ e->key.public_key = pubkey->key;
+ e->cb.verify_cb = verify_cb;
+ e->context = context;
+ silc_async_init(&e->op, silc_softacc_abort, NULL, e);
+
+ /* Run */
+ silc_thread_pool_run(sa->tp, TRUE, sa->schedule, silc_softacc_thread, e,
+ silc_softacc_completion, e);
+
+ return &e->op;
+}
--- /dev/null
+/*
+
+ softacc.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2007 Pekka Riikonen
+
+ This program 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; version 2 of the License.
+
+ This program 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.
+
+*/
+
+#ifndef SOFTACC_H
+#define SOFTACC_H
+
+/* The software accelerator */
+extern DLLAPI const SilcAcceleratorStruct softacc;
+
+SilcBool silc_softacc_init(SilcSchedule schedule, va_list va);
+SilcBool silc_softacc_uninit(void);
+SILC_PKCS_ALG_IMPORT_PUBLIC_KEY(silc_softacc_acc_public_key);
+SILC_PKCS_ALG_PUBLIC_KEY_FREE(silc_softacc_free_public_key);
+SILC_PKCS_ALG_IMPORT_PRIVATE_KEY(silc_softacc_acc_private_key);
+SILC_PKCS_ALG_PRIVATE_KEY_FREE(silc_softacc_free_private_key);
+SILC_PKCS_ALG_ENCRYPT(silc_softacc_encrypt);
+SILC_PKCS_ALG_DECRYPT(silc_softacc_decrypt);
+SILC_PKCS_ALG_SIGN(silc_softacc_sign);
+SILC_PKCS_ALG_VERIFY(silc_softacc_verify);
+
+#endif /* SOFTACC_H */
--- /dev/null
+#
+# Makefile.am
+#
+# Author: Pekka Riikonen <priikone@silcnet.org>
+#
+# Copyright (C) 2007 Pekka Riikonen
+#
+# This program 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; version 2 of the License.
+#
+# This program 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.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS = test_softacc
+
+test_softacc_SOURCES = test_softacc.c
+
+LIBS = $(SILC_COMMON_LIBS)
+LDADD = -L.. -L../.. -lsilc -lsilcacc
+
+include $(top_srcdir)/Makefile.defines.in
--- /dev/null
+/* Software accelerator tests */
+
+#include "silc.h"
+
+SilcSchedule schedule;
+SilcPublicKey public_key, accpub;
+SilcPrivateKey private_key, accprv;
+SilcHash hash;
+unsigned char data[] = "Single block msg";
+int data_len = 16;
+int s = 100;
+
+void sign_compl(SilcBool success, const unsigned char *signature,
+ SilcUInt32 signature_len, void *context)
+{
+ SILC_LOG_DEBUG(("Sign compl %s", success ? "Ok" : "failed"));
+}
+
+SILC_TASK_CALLBACK(quit)
+{
+ silc_schedule_stop(schedule);
+}
+
+SILC_TASK_CALLBACK(sign)
+{
+ silc_pkcs_sign(accprv, data, data_len, TRUE, hash, sign_compl, NULL);
+ if (--s > 0)
+ silc_schedule_task_add_timeout(schedule, sign, NULL, 0, 70000);
+}
+
+int main(int argc, char **argv)
+{
+ SilcBool success = FALSE;
+ SilcAccelerator softacc;
+
+ if (argc > 1 && !strcmp(argv[1], "-d")) {
+ silc_log_debug(TRUE);
+ silc_log_quick(TRUE);
+ silc_log_debug_hexdump(TRUE);
+ silc_log_set_debug_string("*acc*");
+ }
+
+ silc_crypto_init(NULL);
+ if (!silc_hash_alloc("sha1", &hash))
+ goto err;
+
+ if (!silc_create_key_pair("rsa", 2048, "pubkey.pub", "privkey.prv", NULL,
+ "", &public_key, &private_key, FALSE))
+ goto err;
+
+ schedule = silc_schedule_init(0, NULL, NULL);
+
+ softacc = silc_acc_find("softacc");
+ if (!softacc)
+ goto err;
+
+ if (!silc_acc_init(softacc, schedule, "min_threads", 2, "max_threads",
+ 8, NULL))
+ goto err;
+
+ accpub = silc_acc_public_key(softacc, public_key);
+ if (!accpub)
+ goto err;
+ accprv = silc_acc_private_key(softacc, private_key);
+ if (!accprv)
+ goto err;
+
+ if (silc_acc_get_public_key(softacc, accpub) != public_key)
+ goto err;
+ if (silc_acc_get_private_key(softacc, accprv) != private_key)
+ goto err;
+
+ silc_schedule_task_add_timeout(schedule, sign, NULL, 0, 1);
+ silc_schedule_task_add_timeout(schedule, quit, NULL, 15, 0);
+ silc_schedule(schedule);
+
+ silc_acc_uninit(softacc);
+ silc_schedule_uninit(schedule);
+ silc_crypto_uninit();
+
+ success = TRUE;
+
+ err:
+ SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+ fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+ return success;
+}