Added SILC Accelerator Library.
[crypto.git] / lib / silcacc / silcacc_pkcs.c
diff --git a/lib/silcacc/silcacc_pkcs.c b/lib/silcacc/silcacc_pkcs.c
new file mode 100644 (file)
index 0000000..ee2c5a2
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+
+  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;
+}