New SILC PKCS API, enabling support for other public keys/certs.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 1 Jan 2006 10:04:25 +0000 (10:04 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 1 Jan 2006 10:04:25 +0000 (10:04 +0000)
Separated SILC Public Key Payload routines into lib/silccore.

45 files changed:
CHANGES
TODO
includes/silc.h.in
lib/silcasn1/silcasn1.c
lib/silcasn1/silcasn1.h
lib/silcasn1/silcasn1_decode.c
lib/silcasn1/silcasn1_encode.c
lib/silcasn1/silcber.c
lib/silcasn1/tests/test_silcasn1.c
lib/silccore/Makefile.ad
lib/silccore/silcauth.c
lib/silccore/silcmessage.c
lib/silccore/silcmessage.h
lib/silccore/silcpacket.h
lib/silccrypt/Makefile.ad
lib/silccrypt/rsa.c
lib/silccrypt/rsa.h
lib/silccrypt/rsa_internal.h [deleted file]
lib/silccrypt/silchash.h
lib/silccrypt/silcpk.c [new file with mode: 0644]
lib/silccrypt/silcpk.h [new file with mode: 0644]
lib/silccrypt/silcpk_i.h [new file with mode: 0644]
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs.h
lib/silccrypt/silcpkcs1.c
lib/silccrypt/silcpkcs1.h
lib/silccrypt/silcpkcs1_i.h [new file with mode: 0644]
lib/silcmath/mpbin.c
lib/silcmath/silcmath.h
lib/silcmath/silcmp.h
lib/silcserver/server.c
lib/silcserver/server_internal.h
lib/silcserver/server_st_accept.c
lib/silcserver/server_st_command.c
lib/silcserver/server_st_command_reply.c
lib/silcserver/server_st_packet.c
lib/silcserver/tests/test_silcserver.c
lib/silcske/silcske.c
lib/silcske/silcske.h
lib/silcskr/silcskr.c
lib/silcskr/silcskr.h
lib/silcutil/silcapputil.c
lib/silcutil/silcapputil.h
lib/silcutil/silcutil.c
lib/silcutil/silcutil.h

diff --git a/CHANGES b/CHANGES
index 3fc948fd13338b45a1ac58302f8afb4d2364ac6b..432bd167f0eb0aa95a9224e8708c9e130a8c31e0 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,11 @@
+Sat Dec 30 22:54:21 EET 2005  Pekka Riikonen <priikone@silcnet.org>
+
+       * New SILC PKCS API enabling support for other public keys
+         and certificates, lib/silccrypt/silcpkcs.[ch], silcpk.[ch].
+
+       * Separated SILC Public Key Payload routines from the PKCS API
+         to lib/silccore/silcpubkey.[ch].
+
 Wed Dec 28 13:55:22 EET 2005  Pekka Riikonen <priikone@silcnet.org>
 
        * Added SILC Key Repository library, lib/silcskr.
diff --git a/TODO b/TODO
index 6e39a0ab897f3472f6ad2dc7489be16d79e90f0b..3f5aa5cfb4644318d7e7d69f18df4efbefd7d7d4 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,7 +1,7 @@
 TODO for 1.1 And Beyond
 =======================
 
-lib/silccrypt
+lib/silccrypt                  ****PARTLY DONE****
 =============
 
  o Implement the defined SilcDH API.  The definition is in
index b85fd024aad5112307b936af7f16cebe7d2e32fd..20be333951b1f5ea4e2038839a3a991648b3beb3 100644 (file)
@@ -252,6 +252,7 @@ extern "C" {
 #include "silchmac.h"
 #include "silcrng.h"
 #include "silcpkcs.h"
+#include "silcpk.h"
 #include "silcpkcs1.h"
 
 /* More SILC util library includes */
@@ -297,6 +298,7 @@ extern "C" {
 #include "silcmode.h"
 #include "silcauth.h"
 #include "silcattrs.h"
+#include "silcpubkey.h"
 
 #ifdef SILC_DIST_SKR
 #include "silcskr.h"
index ccf77c2b8ca85e816e0117ac4edbedf2fefbf83d..007f1990d98fe6baa1680772d5850ba1c11d6e72 100644 (file)
@@ -66,10 +66,6 @@ SilcBool silc_asn1_init(SilcAsn1 asn1)
 
 void silc_asn1_uninit(SilcAsn1 asn1)
 {
-#if 1
-  silc_stack_stats(asn1->stack1);
-  silc_stack_stats(asn1->stack2);
-#endif
   silc_stack_free(asn1->stack1);
   silc_stack_free(asn1->stack2);
 }
index 57c31905b9108e8285452b57a3c9f13a3275e495..26c03f38256cfd34091d34dbdb20949db5be13f0 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2003 - 2005 Pekka Riikonen
+  Copyright (C) 2003 - 2006 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
@@ -35,7 +35,7 @@
  * pre-allocated SilcStack is used as memory.
  *
  * The encoding and decoding interface is simple.  silc_asn1_encode is used
- * encode and silc_asn1_decode to decode.  The actual ASN.1 is defined
+ * to encode and silc_asn1_decode to decode.  The actual ASN.1 is defined
  * as variable argument list to the function.  Various macros can be used
  * to encode and decode different ASN.1 types.  All types may also be used
  * to encode and decode with various options (such as implicit and explicit
@@ -102,6 +102,16 @@ typedef struct SilcAsn1Object SilcAsn1Struct;
  *    with SILC_ASN1_OPTS macro.  Other options can be given with various
  *    SILC_ASN1_*_T macros.
  *
+ * EXAMPLE
+ *
+ *    // Encodes boolean value with explicit tag and private class, and
+ *    // the result is allocated into `dest'.
+ *    silc_asn1_encode(asn1, &dest,
+ *                     SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
+ *                     SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE |
+ *                                         SILC_ASN1_EXPLICIT, 100, boolval),
+ *                     SILC_ASN1_END);
+ *
  * SOURCE
  */
 typedef enum {
@@ -413,7 +423,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
  *
  *    Decoding:
  *    SILC_ASN1_ANY(&buffer)
- *    SILC_ASN1_ANY_T(opts, tag, &buffer)
+ *    SILC_ASN1_ANY_T(opts, tag, buffer)
  *
  * DESCRIPTION
  *
@@ -453,7 +463,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
  *
  *    Decoding:
  *    SILC_ASN1_ANY_PRIMITIVE(tag, &buffer)
- *    SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, &buffer)
+ *    SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, buffer)
  *
  * DESCRIPTION
  *
@@ -671,7 +681,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
  *
  *    Encoding:
  *    SILC_ASN1_INT(integer)
- *    SILC_ASN1_INT_T(opts, tag, integer)
+ *    SILC_ASN1_INT_T(opts, tag, &integer)
  *
  *    Decoding:
  *    SILC_ASN1_INT(&integer)
@@ -694,7 +704,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
  *
  *    Encoding:
  *    SILC_ASN1_ENUM(enum)
- *    SILC_ASN1_ENUM_T(opts, tag, enum)
+ *    SILC_ASN1_ENUM_T(opts, tag, &enum)
  *
  *    Decoding:
  *    SILC_ASN1_ENUM(&enum)
@@ -1110,7 +1120,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
  *
  *    Decoding:
  *    SILC_ASN1_UTC_TIME(&str, &timeval)
- *    SILC_ASN1_UTC_TIME_T(opts, tag, &timeval)
+ *    SILC_ASN1_UTC_TIME_T(opts, tag, timeval)
  *
  * DESCRIPTION
  *
@@ -1133,7 +1143,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
  *
  *    Decoding:
  *    SILC_ASN1_GEN_TIME(&str, &timeval)
- *    SILC_ASN1_GEN_TIME_T(opts, tag, &timeval)
+ *    SILC_ASN1_GEN_TIME_T(opts, tag, timeval)
  *
  * DESCRIPTION
  *
index 34b93ca26ab182020458843602b5556469b3f439..8fdfef24720343da660036fcb69806fb2d3f6e01 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2003 - 2005 Pekka Riikonen
+  Copyright (C) 2003 - 2006 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
@@ -21,7 +21,6 @@
 #include "silcasn1.h"
 #include "silcber.h"
 
-
 /************************** ASN.1 Decoder routines **************************/
 
 /* Internal SEQUENCE OF and SET OF decoder.  This is used only when decoding
@@ -472,7 +471,7 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type,
 
            /* 2s complement and change sign */
            silc_mp_init(&z);
-           silc_mp_set(&z, 0);
+           silc_mp_set_ui(&z, 0);
            silc_mp_add_ui(*intval, *intval, 1);
            silc_mp_sub(*intval, &z, *intval);
            silc_mp_uninit(&z);
index 123539f6fcd93d42b690832db1a0fbd14e430efb..d8706b73a9dbd31643d3a0c99913a63cea5f0ac9 100644 (file)
@@ -199,6 +199,8 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
          len = silc_buffer_len(node);
          dest = silc_buffer_srealloc_size(stack1, dest,
                                           silc_buffer_truelen(dest) + len);
+         if (!dest)
+           goto fail;
          silc_buffer_put(dest, node->data, len);
        }
        break;
@@ -266,11 +268,15 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
             bytes in 1s complement */
        } else {
          /* Positive */
-         len = (silc_mp_sizeinbase(mpint, 2) + 7) / 8;
-         len += len & 7 ? 1: 0;
+         len = silc_mp_sizeinbase(mpint, 2);
+         if (!(len & 7))
+           len = ((len + 7) / 8) + 1;
+         else
+           len = (len + 7) / 8;
          silc_stack_push(stack2, &frame);
          silc_buffer_srealloc_size(stack2, &buf,
                                    silc_buffer_truelen(&buf) + len);
+         buf.data[0] = 0x00;
          silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
        }
 
index 9d83d8b56e43fb08329fe70f1f828aaa20f94a15..e6f2de30a864ba1b55a9f968e4d8ec480e456562 100644 (file)
@@ -75,7 +75,7 @@ SilcBool silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class,
       /* Long form */
 
       /* Calculate the number of octets for the length field */
-      tmp = tag;
+      tmp = data_len;
       c = 0;
       while (tmp) {
        c++;
index 3e2bd3ce72e16560ba873e69a6a7215fe649ee09..fad097b5b3644cd9d9ad931b2003b96254ea6c3f 100644 (file)
@@ -53,6 +53,8 @@ int main(int argc, char **argv)
   unsigned char *str;
   SilcUInt32 str_len;
   char tmp[32];
+  SilcRng rng;
+  SilcMPInt mpint, mpint2;
 
   memset(&node, 0, sizeof(node));
   memset(&node2, 0, sizeof(node2));
@@ -63,6 +65,10 @@ int main(int argc, char **argv)
     silc_log_set_debug_string("*asn1*,*ber*");
   }
 
+  silc_hash_register_default();
+  rng = silc_rng_alloc();
+  silc_rng_init(rng);
+
   SILC_LOG_DEBUG(("Allocating ASN.1 context"));
   asn1 = silc_asn1_alloc();
   if (!asn1)
@@ -583,6 +589,7 @@ int main(int argc, char **argv)
   memset(&node, 0, sizeof(node));
   printf("\n");
 
+
   memset(&node, 0, sizeof(node));
   SILC_LOG_DEBUG(("Encoding ASN.1 tree 9"));
   success =
@@ -641,6 +648,39 @@ int main(int argc, char **argv)
   SILC_LOG_DEBUG(("Ooctet-string %s, len %d", str, str_len));
   printf("\n");
 
+
+  memset(&node, 0, sizeof(node));
+  SILC_LOG_DEBUG(("Encoding ASN.1 tree 10 (INTEGER)"));
+  str = silc_rng_get_rn_data(rng, 256);
+  silc_mp_init(&mpint);
+  silc_mp_init(&mpint2);
+  silc_mp_bin2mp(str, 256, &mpint);
+  success =
+    silc_asn1_encode(asn1, &node,
+                    SILC_ASN1_INT(&mpint),
+                    SILC_ASN1_END);
+  if (!success) {
+    SILC_LOG_DEBUG(("Encoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Encoding success"));
+  SILC_LOG_HEXDUMP(("ASN.1 tree"), node.data, silc_buffer_len(&node));
+  SILC_LOG_DEBUG(("Decoding ASN.1 tree 9"));
+  success =
+    silc_asn1_decode(asn1, &node,
+                    SILC_ASN1_INT(&mpint2),
+                    SILC_ASN1_END);
+  if (silc_mp_cmp(&mpint, &mpint2) != 0) {
+    SILC_LOG_DEBUG(("INTEGER MISMATCH"));
+    goto out;
+  }
+  if (!success) {
+    SILC_LOG_DEBUG(("Decoding failed"));
+    goto out;
+  }
+  SILC_LOG_DEBUG(("Decoding success"));
+  printf("\n");
+
 #endif
   silc_asn1_free(asn1);
 
index b5d6d71b277bed0a82eb8adf351016f4d481173d..7d9507e66f502217d2d8cca3722e042945482552 100644 (file)
@@ -19,18 +19,19 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
 noinst_LTLIBRARIES = libsilccore.la
 
-libsilccore_la_SOURCES = \
-       silcid.c \
-       silcidcache.c \
-       silcmessage.c \
-       silcchannel.c \
-       silccommand.c \
-       silcpacket.c \
-       silcargument.c \
-       silcnotify.c \
-       silcauth.c \
-       silcattrs.c \
-       silcstatus.c
+libsilccore_la_SOURCES =       \
+       silcid.c                \
+       silcidcache.c           \
+       silcmessage.c           \
+       silcchannel.c           \
+       silccommand.c           \
+       silcpacket.c            \
+       silcargument.c          \
+       silcnotify.c            \
+       silcauth.c              \
+       silcattrs.c             \
+       silcstatus.c            \
+       silcpubkey.c
 
 #ifdef SILC_DIST_TOOLKIT
 include_HEADERS =      \
@@ -45,7 +46,8 @@ include_HEADERS =     \
        silcpacket.h    \
        silcargument.h  \
        silcstatus.h    \
-       silcattrs.h
+       silcattrs.h     \
+       silcpubkey.h
 
 SILC_EXTRA_DIST = tests
 #endif SILC_DIST_TOOLKIT
index b98f36e84ae7d7e5aa5d42383ad2483b5dc71308..22ba281ab70e1a8dab9f1a6db5edb87dcd62c2da 100644 (file)
@@ -279,7 +279,6 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   SilcBuffer buf;
-  SilcPKCS pkcs;
 
   SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
 
@@ -289,22 +288,11 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
   if (!tmp)
     return NULL;
 
-  /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(private_key->name, SILC_PKCS_SILC, &pkcs)) {
-    memset(tmp, 0, tmp_len);
-    silc_free(tmp);
-    return NULL;
-  }
-  silc_pkcs_public_key_set(pkcs, public_key);
-  silc_pkcs_private_key_set(pkcs, private_key);
-
   /* Compute the hash and the signature. */
-  if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
-      !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
-                               &auth_len)) {
+  if (!silc_pkcs_sign(private_key, tmp, tmp_len, auth_data,
+                     sizeof(auth_data) - 1, &auth_len, hash)) {
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
-    silc_pkcs_free(pkcs);
     return NULL;
   }
 
@@ -315,7 +303,6 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
   memset(tmp, 0, tmp_len);
   memset(auth_data, 0, sizeof(auth_data));
   silc_free(tmp);
-  silc_pkcs_free(pkcs);
 
   return buf;
 }
@@ -330,7 +317,6 @@ SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
 {
   unsigned char *tmp;
   SilcUInt32 tmp_len;
-  SilcPKCS pkcs;
 
   SILC_LOG_DEBUG(("Verifying authentication data"));
 
@@ -343,28 +329,18 @@ SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
     return FALSE;
   }
 
-  /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(public_key->name, SILC_PKCS_SILC, &pkcs)) {
-    memset(tmp, 0, tmp_len);
-    silc_free(tmp);
-    return FALSE;
-  }
-  silc_pkcs_public_key_set(pkcs, public_key);
-
   /* Verify the authentication data */
-  if (!silc_pkcs_verify_with_hash(pkcs, hash, payload->auth_data,
-                                 payload->auth_len, tmp, tmp_len)) {
+  if (!silc_pkcs_verify(public_key, payload->auth_data,
+                       payload->auth_len, tmp, tmp_len, hash)) {
 
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
-    silc_pkcs_free(pkcs);
     SILC_LOG_DEBUG(("Authentication failed"));
     return FALSE;
   }
 
   memset(tmp, 0, tmp_len);
   silc_free(tmp);
-  silc_pkcs_free(pkcs);
 
   SILC_LOG_DEBUG(("Authentication successful"));
 
index cf4ee1bf674a05783d0bcb7d053a156559552ca3..990050c6d7327c223271322f10f60b88e3789f7c 100644 (file)
@@ -543,7 +543,6 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
                                   SilcHash hash)
 {
   SilcBuffer buffer, sign;
-  SilcPKCS pkcs;
   unsigned char auth_data[2048 + 1];
   SilcUInt32 auth_len;
   unsigned char *pk = NULL;
@@ -553,11 +552,12 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
   if (!message_payload || !message_payload_len || !private_key || !hash)
     return NULL;
 
-  if (public_key)
+  if (public_key) {
     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
-
-  /* Now we support only SILC style public key */
-  pk_type = SILC_SKE_PK_TYPE_SILC;
+    if (!pk)
+      return NULL;
+  }
+  pk_type = silc_pkcs_get_type(public_key);
 
   /* Encode the data to be signed */
   sign = silc_message_signed_encode_data(message_payload,
@@ -570,24 +570,12 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
 
   /* Sign the buffer */
 
-  /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(private_key->name, SILC_PKCS_SILC, &pkcs)) {
-    SILC_LOG_ERROR(("Could not allocated PKCS"));
-    silc_buffer_clear(sign);
-    silc_buffer_free(sign);
-    silc_free(pk);
-    return NULL;
-  }
-  silc_pkcs_private_key_set(pkcs, private_key);
-
   /* Compute the hash and the signature. */
-  if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
-      !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, silc_buffer_len(sign), auth_data,
-                               &auth_len)) {
+  if (!silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
+                     auth_data, sizeof(auth_data) - 1, &auth_len, hash)) {
     SILC_LOG_ERROR(("Could not compute signature"));
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
-    silc_pkcs_free(pkcs);
     silc_free(pk);
     return NULL;
   }
@@ -598,7 +586,6 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
   if (!buffer) {
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
-    silc_pkcs_free(pkcs);
     memset(auth_data, 0, sizeof(auth_data));
     silc_free(pk);
     return NULL;
@@ -627,7 +614,6 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
   SILC_LOG_HEXDUMP(("sig payload"), buffer->data, silc_buffer_len(buffer));
 
   memset(auth_data, 0, sizeof(auth_data));
-  silc_pkcs_free(pkcs);
   silc_buffer_clear(sign);
   silc_buffer_free(sign);
   silc_free(pk);
@@ -654,7 +640,6 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
 {
   int ret = SILC_AUTH_FAILED;
   SilcBuffer sign;
-  SilcPKCS pkcs;
   SilcBuffer tmp;
 
   if (!sig || !remote_public_key || !hash)
@@ -678,22 +663,13 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
   if (!sign)
     return ret;
 
-  /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(remote_public_key->name, SILC_PKCS_SILC, &pkcs)) {
-    silc_buffer_clear(sign);
-    silc_buffer_free(sign);
-    return ret;
-  }
-  silc_pkcs_public_key_set(pkcs, remote_public_key);
-
   /* Verify the authentication data */
-  if (!silc_pkcs_verify_with_hash(pkcs, hash, sig->sign_data,
-                                 sig->sign_len,
-                                 sign->data, silc_buffer_len(sign))) {
+  if (!silc_pkcs_verify(remote_public_key, sig->sign_data,
+                       sig->sign_len,
+                       sign->data, silc_buffer_len(sign), hash)) {
 
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
-    silc_pkcs_free(pkcs);
     SILC_LOG_DEBUG(("Signature verification failed"));
     return ret;
   }
@@ -702,7 +678,6 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
 
   silc_buffer_clear(sign);
   silc_buffer_free(sign);
-  silc_pkcs_free(pkcs);
 
   SILC_LOG_DEBUG(("Signature verification successful"));
 
@@ -713,13 +688,16 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
 
 SilcPublicKey
 silc_message_signed_get_public_key(SilcMessageSignedPayload sig,
-                                  unsigned char **pk_data,
+                                  const unsigned char **pk_data,
                                   SilcUInt32 *pk_data_len)
 {
   SilcPublicKey pk;
 
-  if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data,
-                                                   sig->pk_len, &pk))
+  if (!sig->pk_data)
+    return NULL;
+
+  if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
+                                 sig->pk_len, &pk))
     return NULL;
 
   if (pk_data)
index 7dc136efeca6905d369e058764ff5aadc86c6d46..356a2ad81a742ca5785a9dce2258f2c6d68850f4 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcmessage.h 
+  silcmessage.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2005 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
@@ -26,7 +26,7 @@
  *
  * This interface defines also the SILC_MESSAGE_FLAG_SIGNED Payload,
  * which defines how channel messages and private messages can be digitally
- * signed.  This interface provides the payload parsing, encoding, 
+ * signed.  This interface provides the payload parsing, encoding,
  * signature computing and signature verification routines.
  *
  ***/
@@ -37,7 +37,7 @@
 /****s* silccore/SilcMessageAPI/SilcMessagePayload
  *
  * NAME
- * 
+ *
  *    typedef struct SilcMessagePayloadStruct *SilcMessagePayload;
  *
  *
@@ -54,7 +54,7 @@ typedef struct SilcMessagePayloadStruct *SilcMessagePayload;
 /****s* silccore/SilcMessageAPI/SilcMessageSignedPayload
  *
  * NAME
- * 
+ *
  *    typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
  *
  *
@@ -73,12 +73,12 @@ typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload;
 /****d* silccore/SilcMessageAPI/SilcMessageFlags
  *
  * NAME
- * 
+ *
  *    typedef SilcUInt16 SilcMessageFlags;
  *
  * DESCRIPTION
  *
- *    The message flags type definition and the message flags.  The 
+ *    The message flags type definition and the message flags.  The
  *    message flags are used to indicate some status of the message.
  *
  * SOURCE
@@ -125,7 +125,7 @@ typedef SilcUInt16 SilcMessageFlags;
  *
  *    This is usually used by the Message Payload interface itself but can
  *    be called by the appliation if separate decryption process is required.
- *    For example server might need to call this directly in some 
+ *    For example server might need to call this directly in some
  *    circumstances. The `cipher' is used to decrypt the payload.  If
  *    `check_mac' is FALSE then MAC is not verified.
  *
@@ -142,7 +142,7 @@ SilcBool silc_message_payload_decrypt(unsigned char *data,
  *
  * SYNOPSIS
  *
- *    SilcMessagePayload 
+ *    SilcMessagePayload
  *    silc_message_payload_parse(unsigned char *payload,
  *                               SilcUInt32 payload_len,
  *                               SilcBool private_message,
@@ -167,7 +167,7 @@ SilcBool silc_message_payload_decrypt(unsigned char *data,
  *    (no private message key) and this merely decodes the payload.
  *
  ***/
-SilcMessagePayload 
+SilcMessagePayload
 silc_message_payload_parse(unsigned char *payload,
                           SilcUInt32 payload_len,
                           SilcBool private_message,
@@ -196,7 +196,7 @@ silc_message_payload_parse(unsigned char *payload,
  *
  *    This is usually used by the Message Payload interface itself but can
  *    be called by the appliation if separate encryption process is required.
- *    For example server might need to call this directly in some 
+ *    For example server might need to call this directly in some
  *    circumstances. The `cipher' is used to encrypt the payload and `hmac'
  *    to compute the MAC for the payload.
  *
@@ -318,7 +318,7 @@ unsigned char *silc_message_get_data(SilcMessagePayload payload,
  *
  * DESCRIPTION
  *
- *    Return the MAC of the payload. The caller must already know the 
+ *    Return the MAC of the payload. The caller must already know the
  *    length of the MAC. The caller must not free the MAC.
  *
  ***/
@@ -333,7 +333,7 @@ unsigned char *silc_message_get_mac(SilcMessagePayload payload);
  *
  * DESCRIPTION
  *
- *    Return the IV of the payload. The caller must already know the 
+ *    Return the IV of the payload. The caller must already know the
  *    length of the IV. The caller must not free the IV.
  *
  ***/
@@ -405,7 +405,7 @@ silc_message_signed_payload_parse(const unsigned char *data,
  *    is used to produce the signature.  This function returns the encoded
  *    payload with the signature or NULL on error.  Caller must free the
  *    returned buffer.  The `hash' SHOULD be SHA-1 hash function.
- *    
+ *
  *    Application usually does not need to call this since the function
  *    silc_message_payload_encode calls this automatically if the caller
  *    wants to sign the message.
@@ -458,7 +458,7 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
  *
  *    SilcPublicKey
  *    silc_message_signed_get_public_key(SilcMessageSignedPayload sig,
- *                                       unsigned char **pk_data,
+ *                                       const unsigned char **pk_data,
  *                                       SilcUInt32 *pk_data_len);
  *
  * DESCRIPTION
@@ -472,7 +472,7 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
  ***/
 SilcPublicKey
 silc_message_signed_get_public_key(SilcMessageSignedPayload sig,
-                                  unsigned char **pk_data,
+                                  const unsigned char **pk_data,
                                   SilcUInt32 *pk_data_len);
 
 #endif /* SILCMESSAGE_H */
index eb3c97d762817882210ed453d9ca8565ccc06ef8..f7c6853cdcc6687d76e8e80f678031a799de310e 100644 (file)
@@ -22,9 +22,9 @@
  * DESCRIPTION
  *
  * The SILC secure binary packet protocol interface, provides interface for
- * sending and receiving SILC packets.  The interface provides a packet engine,
- * that can be used to receive packets from packet streams, and routines
- * for sending all kinds of SILC packets.
+ * sending and receiving SILC packets.  The interface provides a packet
+ * engine, that can be used to receive packets from packet streams, and
+ * routines for sending all kinds of SILC packets.
  *
  * The packet engine and packet stream are thread safe.  They can be safely
  * used in multi threaded environment.
index 98c64393ea5c719e9e58278a168d518d59e69297..01edf7c313e3464c672b11a2e4c49344935cc891 100644 (file)
@@ -20,22 +20,23 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 noinst_LTLIBRARIES = libsilccrypt.la
 
 libsilccrypt_la_SOURCES = \
-       none.c \
-       rc5.c \
-       md5.c \
-       aes.c \
-       rsa.c \
-       sha1.c \
-       sha256.c \
-       twofish.c \
-       blowfish.c \
-       cast.c \
-       silccipher.c \
-       silchash.c \
-       silchmac.c \
-       silcrng.c \
-       silcpkcs.c \
-       silcpkcs1.c
+       none.c          \
+       rc5.c           \
+       md5.c           \
+       aes.c           \
+       rsa.c           \
+       sha1.c          \
+       sha256.c        \
+       twofish.c       \
+       blowfish.c      \
+       cast.c          \
+       silccipher.c    \
+       silchash.c      \
+       silchmac.c      \
+       silcrng.c       \
+       silcpkcs.c      \
+       silcpkcs1.c     \
+       silcpk.c
 
 if SILC_LIBTOOLFIX
 # Tell libtool to compile silccrypt as shared since silcsim will need it.
@@ -68,7 +69,8 @@ include_HEADERS =     \
        silcpkcs.h      \
        silcrng.h       \
        silcpkcs1.h     \
-       twofish.h
+       twofish.h       \
+       silcpk.h
 
 SILC_EXTRA_DIST = tests
 #endif SILC_DIST_TOOLKIT
index 18399a5a393a0c49707d0803dad3eb402b27dab8..b09693a591976c56e8d5599833415cc1ea785bc0 100644 (file)
@@ -5,7 +5,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2006 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
      Fixed double free in public key setting.  Use a bit larger e as
      starting point in key generation.
 
+   o Fri Dec 30 13:39:51 EET 2005 Pekka
+
+     Support PKCS #1 format public and private keys.  Support for new
+     PKCS API.
 */
 
 #include "silc.h"
-#include "rsa_internal.h"
 #include "rsa.h"
 
-/*
- * SILC PKCS API for RSA
- */
-
-/* Generates RSA key pair. */
-
-SILC_PKCS_API_INIT(rsa)
-{
-  SilcUInt32 prime_bits = keylen / 2;
-  SilcMPInt p, q;
-  SilcBool found = FALSE;
-
-  if (keylen < 768 || keylen > 16384)
-    return FALSE;
-
-  printf("Generating RSA Public and Private keys, might take a while...\n");
-
-  silc_mp_init(&p);
-  silc_mp_init(&q);
-
-  /* Find p and q */
-  while (!found) {
-    printf("Finding p: ");
-    silc_math_gen_prime(&p, prime_bits, TRUE, rng);
-
-    printf("\nFinding q: ");
-    silc_math_gen_prime(&q, prime_bits, TRUE, rng);
-
-    if ((silc_mp_cmp(&p, &q)) == 0)
-      printf("\nFound equal primes, not good, retrying...\n");
-    else
-      found = TRUE;
-  }
-
-  /* If p is smaller than q, switch them */
-  if ((silc_mp_cmp(&p, &q)) > 0) {
-    SilcMPInt hlp;
-    silc_mp_init(&hlp);
-
-    silc_mp_set(&hlp, &p);
-    silc_mp_set(&p, &q);
-    silc_mp_set(&q, &hlp);
-
-    silc_mp_uninit(&hlp);
-  }
-
-  /* Generate the actual keys */
-  rsa_generate_keys((RsaKey *)context, keylen, &p, &q);
-
-  silc_mp_uninit(&p);
-  silc_mp_uninit(&q);
-
-  printf("\nKeys generated successfully.\n");
-
-  return TRUE;
-}
-
-SILC_PKCS_API_CLEAR_KEYS(rsa)
-{
-  rsa_clear_keys((RsaKey *)context);
-}
-
-/* Returns SILC style encoded RSA public key. */
-
-SILC_PKCS_API_GET_PUBLIC_KEY(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  unsigned char *e, *n, *ret;
-  SilcUInt32 e_len, n_len;
-  unsigned char tmp[4];
-
-  e = silc_mp_mp2bin(&key->e, 0, &e_len);
-  n = silc_mp_mp2bin(&key->n, (key->bits + 7) / 8, &n_len);
-
-  *ret_len = e_len + 4 + n_len + 4;
-  ret = silc_calloc(*ret_len, sizeof(unsigned char));
-
-  /* Put the length of the e. */
-  SILC_PUT32_MSB(e_len, tmp);
-  memcpy(ret, tmp, 4);
-
-  /* Put the e. */
-  memcpy(ret + 4, e, e_len);
-
-  /* Put the length of the n. */
-  SILC_PUT32_MSB(n_len, tmp);
-  memcpy(ret + 4 + e_len, tmp, 4);
-
-  /* Put the n. */
-  memcpy(ret + 4 + e_len + 4, n, n_len);
-
-  memset(e, 0, e_len);
-  memset(n, 0, n_len);
-  silc_free(e);
-  silc_free(n);
-
-  return ret;
-}
-
-/* Returns SILC style encoded RSA private key. Public key is always
-   returned in private key as well. Public keys are often derived
-   directly from private key. */
-
-SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  SilcBuffer buf;
-  unsigned char *e, *n, *d, *ret, *dp = NULL, *dq = NULL;
-  unsigned char *pq = NULL, *qp = NULL, *p = NULL, *q = NULL;
-  SilcUInt32 e_len, n_len, d_len, dp_len, dq_len, pq_len, qp_len, p_len, q_len;
-  SilcUInt32 len = 0;
-
-  e = silc_mp_mp2bin(&key->e, 0, &e_len);
-  n = silc_mp_mp2bin(&key->n, (key->bits + 7) / 8, &n_len);
-  d = silc_mp_mp2bin(&key->d, 0, &d_len);
-  if (key->crt) {
-    dp = silc_mp_mp2bin(&key->dP, 0, &dp_len);
-    dq = silc_mp_mp2bin(&key->dQ, 0, &dq_len);
-    pq = silc_mp_mp2bin(&key->pQ, 0, &pq_len);
-    qp = silc_mp_mp2bin(&key->qP, 0, &qp_len);
-    p = silc_mp_mp2bin(&key->p, 0, &p_len);
-    q = silc_mp_mp2bin(&key->q, 0, &q_len);
-    len = dp_len + 4 + dq_len + 4 + pq_len + 4 + qp_len + 4 + p_len + 4 +
-      q_len + 4;
-  }
-
-  buf = silc_buffer_alloc_size(e_len + 4 + n_len + 4 + d_len + 4 + len);
-  len = silc_buffer_format(buf,
-                          SILC_STR_UI_INT(e_len),
-                          SILC_STR_UI_XNSTRING(e, e_len),
-                          SILC_STR_UI_INT(n_len),
-                          SILC_STR_UI_XNSTRING(n, n_len),
-                          SILC_STR_UI_INT(d_len),
-                          SILC_STR_UI_XNSTRING(d, d_len),
-                          SILC_STR_END);
-
-  if (key->crt) {
-    silc_buffer_pull(buf, len);
-    silc_buffer_format(buf,
-                      SILC_STR_UI_INT(dp_len),
-                      SILC_STR_UI_XNSTRING(dp, dp_len),
-                      SILC_STR_UI_INT(dq_len),
-                      SILC_STR_UI_XNSTRING(dq, dq_len),
-                      SILC_STR_UI_INT(pq_len),
-                      SILC_STR_UI_XNSTRING(pq, pq_len),
-                      SILC_STR_UI_INT(qp_len),
-                      SILC_STR_UI_XNSTRING(qp, qp_len),
-                      SILC_STR_UI_INT(p_len),
-                      SILC_STR_UI_XNSTRING(p, p_len),
-                      SILC_STR_UI_INT(q_len),
-                      SILC_STR_UI_XNSTRING(q, q_len),
-                      SILC_STR_END);
-    silc_buffer_push(buf, len);
-
-    memset(dp, 0, dp_len);
-    memset(dq, 0, dq_len);
-    memset(pq, 0, pq_len);
-    memset(qp, 0, qp_len);
-    memset(p, 0, p_len);
-    memset(q, 0, q_len);
-    silc_free(dp);
-    silc_free(dq);
-    silc_free(pq);
-    silc_free(qp);
-    silc_free(p);
-    silc_free(q);
-  }
-
-  memset(d, 0, d_len);
-  silc_free(e);
-  silc_free(n);
-  silc_free(d);
-
-  ret = silc_buffer_steal(buf, ret_len);
-  silc_buffer_free(buf);
-  return ret;
-}
-
-/* Set public key */
-
-SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  unsigned char tmp[4];
-  SilcUInt32 e_len, n_len;
-
-  if (key->pub_set) {
-    silc_mp_uninit(&key->e);
-    silc_mp_uninit(&key->n);
-    key->pub_set = FALSE;
-  }
-
-  if (key_len < 4)
-    return 0;
-
-  silc_mp_init(&key->e);
-  silc_mp_init(&key->n);
-
-  memcpy(tmp, key_data, 4);
-  SILC_GET32_MSB(e_len, tmp);
-  if (!e_len || e_len + 4 > key_len) {
-    silc_mp_uninit(&key->e);
-    silc_mp_uninit(&key->n);
-    return 0;
-  }
-
-  silc_mp_bin2mp(key_data + 4, e_len, &key->e);
-
-  if (key_len < 4 + e_len + 4) {
-    silc_mp_uninit(&key->e);
-    silc_mp_uninit(&key->n);
-    return 0;
-  }
-
-  memcpy(tmp, key_data + 4 + e_len, 4);
-  SILC_GET32_MSB(n_len, tmp);
-  if (!n_len || e_len + 4 + n_len + 4 > key_len) {
-    silc_mp_uninit(&key->e);
-    silc_mp_uninit(&key->n);
-    return 0;
-  }
-
-  silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &key->n);
-
-  key->bits = silc_mp_sizeinbase(&key->n, 2);
-  key->pub_set = TRUE;
-
-  return key->bits;
-}
-
-/* Set private key. This derives the public key from the private
-   key and sets the public key as well. Public key should not be set
-   already and should not be set after setting private key. */
-
-SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  SilcBufferStruct k;
-  unsigned char *tmp;
-  SilcUInt32 len;
-
-  if (key->prv_set) {
-    silc_mp_uninit(&key->d);
-    key->prv_set = FALSE;
-  }
-
-  if (key->pub_set) {
-    silc_mp_uninit(&key->e);
-    silc_mp_uninit(&key->n);
-    key->pub_set = FALSE;
-  }
-
-  if (key_len < 4)
-    return FALSE;
-
-  silc_buffer_set(&k, key_data, key_len);
-
-  silc_mp_init(&key->e);
-  silc_mp_init(&key->n);
-  silc_mp_init(&key->d);
-  key->prv_set = TRUE;
-  key->pub_set = TRUE;
-
-  /* Get e */
-  if (silc_buffer_unformat(&k,
-                          SILC_STR_UI_INT(&len),
-                          SILC_STR_END) < 0)
-    goto err;
-  silc_buffer_pull(&k, 4);
-  if (silc_buffer_unformat(&k,
-                          SILC_STR_UI_XNSTRING(&tmp, len),
-                          SILC_STR_END) < 0)
-    goto err;
-  silc_mp_bin2mp(tmp, len, &key->e);
-  silc_buffer_pull(&k, len);
-
-  /* Get n */
-  if (silc_buffer_unformat(&k,
-                          SILC_STR_UI_INT(&len),
-                          SILC_STR_END) < 0)
-    goto err;
-  silc_buffer_pull(&k, 4);
-  if (silc_buffer_unformat(&k,
-                          SILC_STR_UI_XNSTRING(&tmp, len),
-                          SILC_STR_END) < 0)
-    goto err;
-  silc_mp_bin2mp(tmp, len, &key->n);
-  silc_buffer_pull(&k, len);
-
-  /* Get d */
-  if (silc_buffer_unformat(&k,
-                          SILC_STR_UI_INT(&len),
-                          SILC_STR_END) < 0)
-    goto err;
-  silc_buffer_pull(&k, 4);
-  if (silc_buffer_unformat(&k,
-                          SILC_STR_UI_XNSTRING(&tmp, len),
-                          SILC_STR_END) < 0)
-    goto err;
-  silc_mp_bin2mp(tmp, len, &key->d);
-  silc_buffer_pull(&k, len);
-
-  /* Get optimized d for CRT, if present. */
-  if (silc_buffer_len(&k) > 4) {
-    key->crt = TRUE;
-    silc_mp_init(&key->dP);
-    silc_mp_init(&key->dQ);
-    silc_mp_init(&key->pQ);
-    silc_mp_init(&key->qP);
-    silc_mp_init(&key->p);
-    silc_mp_init(&key->q);
-
-    /* Get dP */
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_INT(&len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_buffer_pull(&k, 4);
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_mp_bin2mp(tmp, len, &key->dP);
-    silc_buffer_pull(&k, len);
-
-    /* Get dQ */
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_INT(&len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_buffer_pull(&k, 4);
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_mp_bin2mp(tmp, len, &key->dQ);
-    silc_buffer_pull(&k, len);
-
-    /* Get pQ */
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_INT(&len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_buffer_pull(&k, 4);
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_mp_bin2mp(tmp, len, &key->pQ);
-    silc_buffer_pull(&k, len);
-
-    /* Get qP */
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_INT(&len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_buffer_pull(&k, 4);
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_mp_bin2mp(tmp, len, &key->qP);
-    silc_buffer_pull(&k, len);
-
-    /* Get p */
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_INT(&len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_buffer_pull(&k, 4);
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_mp_bin2mp(tmp, len, &key->p);
-    silc_buffer_pull(&k, len);
-
-    /* Get q */
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_INT(&len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_buffer_pull(&k, 4);
-    if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
-                            SILC_STR_END) < 0)
-      goto err;
-    silc_mp_bin2mp(tmp, len, &key->q);
-    silc_buffer_pull(&k, len);
-  }
-
-  key->bits = silc_mp_sizeinbase(&key->n, 2);
-  return key->bits;
-
- err:
-  rsa_clear_keys(key);
-  return FALSE;
-}
-
-SILC_PKCS_API_CONTEXT_LEN(rsa)
-{
-  return sizeof(RsaKey);
-}
-
-/* Raw RSA routines */
-
-SILC_PKCS_API_ENCRYPT(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  int tmplen;
-  SilcMPInt mp_tmp;
-  SilcMPInt mp_dst;
-
-  silc_mp_init(&mp_tmp);
-  silc_mp_init(&mp_dst);
-
-  /* Format the data into MP int */
-  silc_mp_bin2mp(src, src_len, &mp_tmp);
-
-  /* Encrypt */
-  rsa_public_operation(key, &mp_tmp, &mp_dst);
-
-  tmplen = (key->bits + 7) / 8;
-
-  /* Format the MP int back into data */
-  silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen);
-  *dst_len = tmplen;
-
-  silc_mp_uninit(&mp_tmp);
-  silc_mp_uninit(&mp_dst);
-
-  return TRUE;
-}
-
-SILC_PKCS_API_DECRYPT(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  int tmplen;
-  SilcMPInt mp_tmp;
-  SilcMPInt mp_dst;
-
-  silc_mp_init(&mp_tmp);
-  silc_mp_init(&mp_dst);
-
-  /* Format the data into MP int */
-  silc_mp_bin2mp(src, src_len, &mp_tmp);
-
-  /* Decrypt */
-  rsa_private_operation(key, &mp_tmp, &mp_dst);
-
-  tmplen = (key->bits + 7) / 8;
-
-  /* Format the MP int back into data */
-  silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen);
-  *dst_len = tmplen;
-
-  silc_mp_uninit(&mp_tmp);
-  silc_mp_uninit(&mp_dst);
-
-  return TRUE;
-}
-
-SILC_PKCS_API_SIGN(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  int tmplen;
-  SilcMPInt mp_tmp;
-  SilcMPInt mp_dst;
-
-  silc_mp_init(&mp_tmp);
-  silc_mp_init(&mp_dst);
-
-  /* Format the data into MP int */
-  silc_mp_bin2mp(src, src_len, &mp_tmp);
-
-  /* Sign */
-  rsa_private_operation(key, &mp_tmp, &mp_dst);
-
-  tmplen = (key->bits + 7) / 8;
-
-  /* Format the MP int back into data */
-  silc_mp_mp2bin_noalloc(&mp_dst, dst, tmplen);
-  *dst_len = tmplen;
-
-  silc_mp_uninit(&mp_tmp);
-  silc_mp_uninit(&mp_dst);
-
-  return TRUE;
-}
-
-SILC_PKCS_API_VERIFY(rsa)
-{
-  RsaKey *key = (RsaKey *)context;
-  int ret;
-  SilcMPInt mp_tmp, mp_tmp2;
-  SilcMPInt mp_dst;
-
-  silc_mp_init(&mp_tmp);
-  silc_mp_init(&mp_tmp2);
-  silc_mp_init(&mp_dst);
-
-  /* Format the signature into MP int */
-  silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
-
-  /* Verify */
-  rsa_public_operation(key, &mp_tmp2, &mp_dst);
-
-  /* Format the data into MP int */
-  silc_mp_bin2mp(data, data_len, &mp_tmp);
-
-  ret = TRUE;
-
-  /* Compare */
-  if ((silc_mp_cmp(&mp_tmp, &mp_dst)) != 0)
-    ret = FALSE;
-
-  silc_mp_uninit(&mp_tmp);
-  silc_mp_uninit(&mp_tmp2);
-  silc_mp_uninit(&mp_dst);
-
-  return ret;
-}
-
-
-/* PKCS#1 RSA routines */
-
-SILC_PKCS_API_ENCRYPT(pkcs1)
-{
-  RsaKey *key = (RsaKey *)context;
-  SilcMPInt mp_tmp;
-  SilcMPInt mp_dst;
-  unsigned char padded[2048 + 1];
-  SilcUInt32 len = (key->bits + 7) / 8;
-
-  if (sizeof(padded) < len)
-    return FALSE;
-
-  /* Pad data */
-  if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len,
-                        padded, len, NULL))
-    return FALSE;
-
-  silc_mp_init(&mp_tmp);
-  silc_mp_init(&mp_dst);
-
-  /* Data to MP */
-  silc_mp_bin2mp(padded, len, &mp_tmp);
-
-  /* Encrypt */
-  rsa_public_operation(key, &mp_tmp, &mp_dst);
-
-  /* MP to data */
-  silc_mp_mp2bin_noalloc(&mp_dst, dst, len);
-  *dst_len = len;
-
-  memset(padded, 0, sizeof(padded));
-  silc_mp_uninit(&mp_tmp);
-  silc_mp_uninit(&mp_dst);
-
-  return TRUE;
-}
-
-SILC_PKCS_API_DECRYPT(pkcs1)
-{
-  RsaKey *key = (RsaKey *)context;
-  SilcMPInt mp_tmp;
-  SilcMPInt mp_dst;
-  unsigned char *padded, unpadded[2048 + 1];
-  SilcUInt32 padded_len;
-
-  silc_mp_init(&mp_tmp);
-  silc_mp_init(&mp_dst);
-
-  /* Data to MP */
-  silc_mp_bin2mp(src, src_len, &mp_tmp);
-
-  /* Decrypt */
-  rsa_private_operation(key, &mp_tmp, &mp_dst);
-
-  /* MP to data */
-  padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len);
-
-  /* Unpad data */
-  if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len,
-                        unpadded, sizeof(unpadded), dst_len)) {
-    memset(padded, 0, padded_len);
-    silc_free(padded);
-    silc_mp_uninit(&mp_tmp);
-    silc_mp_uninit(&mp_dst);
-    return FALSE;
-  }
-
-  /* Copy to destination */
-  memcpy(dst, unpadded, *dst_len);
-
-  memset(padded, 0, padded_len);
-  memset(unpadded, 0, sizeof(unpadded));
-  silc_free(padded);
-  silc_mp_uninit(&mp_tmp);
-  silc_mp_uninit(&mp_dst);
-
-  return TRUE;
-}
-
-SILC_PKCS_API_SIGN(pkcs1)
-{
-  RsaKey *key = (RsaKey *)context;
-  SilcMPInt mp_tmp;
-  SilcMPInt mp_dst;
-  unsigned char padded[2048 + 1];
-  SilcUInt32 len = (key->bits + 7) / 8;
-
-  if (sizeof(padded) < len)
-    return FALSE;
-
-  /* Pad data */
-  if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len,
-                        padded, len, NULL))
-    return FALSE;
-
-  silc_mp_init(&mp_tmp);
-  silc_mp_init(&mp_dst);
-
-  /* Data to MP */
-  silc_mp_bin2mp(padded, len, &mp_tmp);
-
-  /* Sign */
-  rsa_private_operation(key, &mp_tmp, &mp_dst);
-
-  /* MP to data */
-  silc_mp_mp2bin_noalloc(&mp_dst, dst, len);
-  *dst_len = len;
-
-  memset(padded, 0, sizeof(padded));
-  silc_mp_uninit(&mp_tmp);
-  silc_mp_uninit(&mp_dst);
-
-  return TRUE;
-}
-
-SILC_PKCS_API_VERIFY(pkcs1)
-{
-  RsaKey *key = (RsaKey *)context;
-  int ret = TRUE;
-  SilcMPInt mp_tmp2;
-  SilcMPInt mp_dst;
-  unsigned char *verify, unpadded[2048 + 1];
-  SilcUInt32 verify_len, len = (key->bits + 7) / 8;
-
-  silc_mp_init(&mp_tmp2);
-  silc_mp_init(&mp_dst);
-
-  /* Format the signature into MP int */
-  silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
-
-  /* Verify */
-  rsa_public_operation(key, &mp_tmp2, &mp_dst);
-
-  /* MP to data */
-  verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);
-
-  /* Unpad data */
-  if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
-                        unpadded, sizeof(unpadded), &len)) {
-    memset(verify, 0, verify_len);
-    silc_free(verify);
-    silc_mp_uninit(&mp_tmp2);
-    silc_mp_uninit(&mp_dst);
-    return FALSE;
-  }
-
-  /* Compare */
-  if (memcmp(data, unpadded, len))
-    ret = FALSE;
-
-  memset(verify, 0, verify_len);
-  memset(unpadded, 0, sizeof(unpadded));
-  silc_free(verify);
-  silc_mp_uninit(&mp_tmp2);
-  silc_mp_uninit(&mp_dst);
-
-  return ret;
-}
-
 /* Generates RSA public and private keys. Primes p and q that are used
    to compute the modulus n has to be generated before calling this. They
    are then sent as argument for the function. */
 
-SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits,
-                      SilcMPInt *p, SilcMPInt *q)
+SilcBool rsa_generate_keys(SilcUInt32 bits, SilcMPInt *p, SilcMPInt *q,
+                          void **ret_public_key, void **ret_private_key)
 {
+  RsaPublicKey *pubkey;
+  RsaPrivateKey *privkey;
   SilcMPInt phi, hlp;
   SilcMPInt div, lcm;
   SilcMPInt pm1, qm1;
 
+  *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
+  if (!pubkey)
+    return FALSE;
+
+  *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey));
+  if (!privkey)
+    return FALSE;
+
   /* Initialize variables */
-  silc_mp_init(&key->n);
-  silc_mp_init(&key->e);
-  silc_mp_init(&key->d);
-  silc_mp_init(&key->dP);
-  silc_mp_init(&key->dQ);
-  silc_mp_init(&key->pQ);
-  silc_mp_init(&key->qP);
+  silc_mp_init(&privkey->n);
+  silc_mp_init(&privkey->e);
+  silc_mp_init(&privkey->d);
+  silc_mp_init(&privkey->dP);
+  silc_mp_init(&privkey->dQ);
+  silc_mp_init(&privkey->qP);
   silc_mp_init(&phi);
   silc_mp_init(&hlp);
   silc_mp_init(&div);
@@ -790,10 +118,10 @@ SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits,
   silc_mp_init(&qm1);
 
   /* Set modulus length */
-  key->bits = bits;
+  privkey->bits = bits;
 
   /* Compute modulus, n = p * q */
-  silc_mp_mul(&key->n, p, q);
+  silc_mp_mul(&privkey->n, p, q);
 
   /* phi = (p - 1) * (q - 1) */
   silc_mp_sub_ui(&pm1, p, 1);
@@ -803,33 +131,27 @@ SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits,
   /* Set e, the public exponent. We try to use same public exponent
      for all keys. Also, to make encryption faster we use small
      number. */
-  silc_mp_set_ui(&key->e, 65533);
+  silc_mp_set_ui(&privkey->e, 65533);
  retry_e:
   /* See if e is relatively prime to phi. gcd == greates common divisor,
      if gcd equals 1 they are relatively prime. */
-  silc_mp_gcd(&hlp, &key->e, &phi);
+  silc_mp_gcd(&hlp, &privkey->e, &phi);
   if ((silc_mp_cmp_ui(&hlp, 1)) > 0) {
-    silc_mp_add_ui(&key->e, &key->e, 2);
+    silc_mp_add_ui(&privkey->e, &privkey->e, 2);
     goto retry_e;
   }
 
   /* Find d, the private exponent, e ^ -1 mod lcm(phi). */
   silc_mp_gcd(&div, &pm1, &qm1);
   silc_mp_div(&lcm, &phi, &div);
-  silc_mp_modinv(&key->d, &key->e, &lcm);
-
-  /* Optimize d with CRT.  We precompute as much as possible. */
-  silc_mp_mod(&key->dP, &key->d, &pm1);
-  silc_mp_mod(&key->dQ, &key->d, &qm1);
-  silc_mp_modinv(&key->pQ, p, q);
-  silc_mp_mul(&key->pQ, p, &key->pQ);
-  silc_mp_mod(&key->pQ, &key->pQ, &key->n);
-  silc_mp_modinv(&key->qP, q, p);
-  silc_mp_mul(&key->qP, q, &key->qP);
-  silc_mp_mod(&key->qP, &key->qP, &key->n);
-  silc_mp_set(&key->p, p);
-  silc_mp_set(&key->q, q);
-  key->crt = TRUE;
+  silc_mp_modinv(&privkey->d, &privkey->e, &lcm);
+
+  /* Optimize d with CRT. */
+  silc_mp_mod(&privkey->dP, &privkey->d, &pm1);
+  silc_mp_mod(&privkey->dQ, &privkey->d, &qm1);
+  silc_mp_modinv(&privkey->qP, q, p);
+  silc_mp_set(&privkey->p, p);
+  silc_mp_set(&privkey->q, q);
 
   silc_mp_uninit(&phi);
   silc_mp_uninit(&hlp);
@@ -838,34 +160,20 @@ SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits,
   silc_mp_uninit(&pm1);
   silc_mp_uninit(&qm1);
 
-  return TRUE;
-}
+  /* Set public key */
+  silc_mp_init(&pubkey->n);
+  silc_mp_init(&pubkey->e);
+  pubkey->bits = privkey->bits;
+  silc_mp_set(&pubkey->n, &privkey->n);
+  silc_mp_set(&pubkey->e, &privkey->e);
 
-/* Clears whole key structure. */
-
-SilcBool rsa_clear_keys(RsaKey *key)
-{
-  key->bits = 0;
-  if (key->pub_set) {
-    silc_mp_uninit(&key->n);
-    silc_mp_uninit(&key->e);
-  }
-  if (key->prv_set)
-    silc_mp_uninit(&key->d);
-  if (key->prv_set && key->crt) {
-    silc_mp_uninit(&key->dP);
-    silc_mp_uninit(&key->dQ);
-    silc_mp_uninit(&key->pQ);
-    silc_mp_uninit(&key->qP);
-    silc_mp_uninit(&key->p);
-    silc_mp_uninit(&key->q);
-  }
   return TRUE;
 }
 
 /* RSA public key operation */
 
-SilcBool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst)
+SilcBool rsa_public_operation(RsaPublicKey *key, SilcMPInt *src,
+                             SilcMPInt *dst)
 {
   /* dst = src ^ e mod n */
   silc_mp_pow_mod(dst, src, &key->e, &key->n);
@@ -874,27 +182,29 @@ SilcBool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst)
 
 /* RSA private key operation */
 
-SilcBool rsa_private_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst)
+SilcBool rsa_private_operation(RsaPrivateKey *key, SilcMPInt *src,
+                              SilcMPInt *dst)
 {
-  if (!key->crt) {
-    /* dst = src ^ d mod n */
-    silc_mp_pow_mod(dst, src, &key->d, &key->n);
-  } else {
-    /* CRT */
-    SilcMPInt tmp;
-
-    silc_mp_init(&tmp);
-
-    /* dst = ((src ^ dP mod p) * qP) + ((src ^ dQ mod q) * pQ) mod n */
-    silc_mp_pow_mod(dst, src, &key->dP, &key->p);
-    silc_mp_mul(dst, dst, &key->qP);
-    silc_mp_pow_mod(&tmp, src, &key->dQ, &key->q);
-    silc_mp_mul(&tmp, &tmp, &key->pQ);
-    silc_mp_add(dst, dst, &tmp);
-    silc_mp_mod(dst, dst, &key->n);
-
-    silc_mp_uninit(&tmp);
-  }
+  SilcMPInt tmp;
+
+  silc_mp_init(&tmp);
+
+  /* dst = (src ^ dP mod p) */
+  silc_mp_pow_mod(dst, src, &key->dP, &key->p);
+
+  /* tmp = (src ^ dQ mod q) */
+  silc_mp_pow_mod(&tmp, src, &key->dQ, &key->q);
+
+  /* dst = (dst - tmp) * qP mod p */
+  silc_mp_sub(dst, dst, &tmp);
+  silc_mp_mul(dst, dst, &key->qP);
+  silc_mp_mod(dst, dst, &key->p);
+
+  /* dst = (q * dst) + tmp */
+  silc_mp_mul(dst, dst, &key->q);
+  silc_mp_add(dst, dst, &tmp);
+
+  silc_mp_uninit(&tmp);
 
   return TRUE;
 }
index a697fef493a8c6d51bddfc33d221e5964a6c9d11..0b05728e86a1754e4f9be554b8fb8cd3e3bb50e1 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2003 Pekka Riikonen
+  Copyright (C) 1997 - 2006 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
 #ifndef RSA_H
 #define RSA_H
 
-/*
- * SILC PKCS API for RSA
- */
-
-SILC_PKCS_API_INIT(rsa);
-SILC_PKCS_API_CLEAR_KEYS(rsa);
-SILC_PKCS_API_GET_PUBLIC_KEY(rsa);
-SILC_PKCS_API_GET_PRIVATE_KEY(rsa);
-SILC_PKCS_API_SET_PUBLIC_KEY(rsa);
-SILC_PKCS_API_SET_PRIVATE_KEY(rsa);
-SILC_PKCS_API_CONTEXT_LEN(rsa);
-SILC_PKCS_API_ENCRYPT(rsa);
-SILC_PKCS_API_DECRYPT(rsa);
-SILC_PKCS_API_SIGN(rsa);
-SILC_PKCS_API_VERIFY(rsa);
-
-SILC_PKCS_API_ENCRYPT(pkcs1);
-SILC_PKCS_API_DECRYPT(pkcs1);
-SILC_PKCS_API_SIGN(pkcs1);
-SILC_PKCS_API_VERIFY(pkcs1);
-
-
-#endif
+/* RSA Public Key */
+typedef struct {
+  int bits;                    /* bits in key */
+  SilcMPInt n;                 /* modulus */
+  SilcMPInt e;                 /* public exponent */
+} RsaPublicKey;
+
+/* RSA Private Key */
+typedef struct {
+  int bits;                    /* bits in key */
+  SilcMPInt n;                 /* modulus */
+  SilcMPInt e;                 /* public exponent */
+  SilcMPInt d;                 /* private exponent */
+  SilcMPInt p;                 /* CRT, p */
+  SilcMPInt q;                 /* CRT, q */
+  SilcMPInt dP;                        /* CRT, d mod p - 1 */
+  SilcMPInt dQ;                        /* CRT, d mod q - 1 */
+  SilcMPInt qP;                        /* CRT, q ^ -1 mod p */
+} RsaPrivateKey;
+
+SilcBool rsa_generate_keys(SilcUInt32 bits, SilcMPInt *p, SilcMPInt *q,
+                          void **ret_public_key, void **ret_private_key);
+SilcBool rsa_public_operation(RsaPublicKey *key, SilcMPInt *src,
+                             SilcMPInt *dst);
+SilcBool rsa_private_operation(RsaPrivateKey *key, SilcMPInt *src,
+                              SilcMPInt *dst);
+
+#endif /* RSA_H */
diff --git a/lib/silccrypt/rsa_internal.h b/lib/silccrypt/rsa_internal.h
deleted file mode 100644 (file)
index f3daa12..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-
-  rsa_internal.h
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 1997 - 2003 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 RSA_INTERNAL_H
-#define RSA_INTERNAL_H
-
-/* RSA Keys, includes both Private and Public key */
-typedef struct {
-  int bits;                    /* bits in key */
-  SilcMPInt n;                 /* modulus */
-  SilcMPInt e;                 /* public exponent */
-  SilcMPInt d;                 /* private exponent (no CRT) */
-  SilcMPInt p;                 /* p */
-  SilcMPInt q;                 /* q */
-  SilcMPInt dP;                        /* CRT, d mod p - 1 */
-  SilcMPInt dQ;                        /* CRT, d mod q - 1 */
-  SilcMPInt pQ;                        /* CRT, p * (p ^ -1 mod q) mod n */
-  SilcMPInt qP;                        /* CRT, q * (q ^ -1 mod p) mod n */
-  unsigned int pub_set : 1;    /* TRUE if n and e is set */
-  unsigned int prv_set : 1;    /* TRUE if d is set */
-  unsigned int crt     : 1;    /* TRUE if CRT is used */
-} RsaKey;
-
-SilcBool rsa_generate_keys(RsaKey *key, SilcUInt32 bits,
-                      SilcMPInt *p, SilcMPInt *q);
-SilcBool rsa_clear_keys(RsaKey *key);
-SilcBool rsa_public_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst);
-SilcBool rsa_private_operation(RsaKey *key, SilcMPInt *src, SilcMPInt *dst);
-
-#endif
index d7317f0c0b067013fb66993dff59f48c9913dfc7..698ce15a579cd2b5f6f924116760ed527b86e7e6 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silchash.h 
+  silchash.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2005 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
@@ -34,7 +34,7 @@
 /****s* silccrypt/SilcHashAPI/SilcHash
  *
  * NAME
- * 
+ *
  *    typedef struct SilcHashStruct *SilcHash;
  *
  * DESCRIPTION
@@ -50,7 +50,7 @@ typedef struct SilcHashStruct *SilcHash;
 /****s* silccrypt/SilcHashAPI/SilcHashObject
  *
  * NAME
- * 
+ *
  *    typedef struct { ... } SilcHashObject;
  *
  * DESCRIPTION
@@ -310,7 +310,7 @@ void silc_hash_make(SilcHash hash, const unsigned char *data,
  *    put them into a buffer and compute the digest from the buffer by
  *    calling the silc_hash_make, or you can use the silc_hash_init,
  *    silc_hash_update and silc_hash_final to do the digest.  This function
- *    prepares the allocated hash function context for this kind of digest 
+ *    prepares the allocated hash function context for this kind of digest
  *    computation.  To add the data to be used in the digest computation
  *    call the silc_hash_update function.
  *
diff --git a/lib/silccrypt/silcpk.c b/lib/silccrypt/silcpk.c
new file mode 100644 (file)
index 0000000..0de35d6
--- /dev/null
@@ -0,0 +1,1601 @@
+/*
+
+  silcpk.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2006 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 "silcpk_i.h"
+
+/****************************** Key generation *******************************/
+
+/* Generate new SILC key pair. */
+
+SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
+                                    const char *scheme,
+                                    SilcUInt32 bits_key_len,
+                                    const char *identifier,
+                                    SilcRng rng,
+                                    SilcPublicKey *ret_public_key,
+                                    SilcPrivateKey *ret_private_key)
+{
+  SilcSILCPublicKey pubkey;
+  SilcSILCPrivateKey privkey;
+  const SilcPKCSAlgorithm *alg;
+  const SilcPKCSObject *pkcs;
+
+  SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
+                 algorithm, bits_key_len));
+
+  if (!rng)
+    return FALSE;
+
+  pkcs = silc_pkcs_find_pkcs(SILC_PKCS_SILC);
+  if (!pkcs)
+    return FALSE;
+
+  alg = silc_pkcs_find_algorithm(algorithm, scheme);
+  if (!alg)
+    return FALSE;
+
+  /* Allocate SILC public key */
+  pubkey = silc_calloc(1, sizeof(*pubkey));
+  if (!pubkey)
+    return FALSE;
+  pubkey->pkcs = alg;
+
+  /* Decode identifier */
+  if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier)) {
+    silc_free(pubkey);
+    return FALSE;
+  }
+
+  /* Allocate SILC private key */
+  privkey = silc_calloc(1, sizeof(*privkey));
+  if (!privkey) {
+    silc_free(pubkey);
+    return FALSE;
+  }
+  privkey->pkcs = alg;
+
+  /* Allocate public key */
+  *ret_public_key = silc_calloc(1, sizeof(**ret_public_key));
+  if (!(*ret_public_key)) {
+    silc_free(pubkey);
+    silc_free(privkey);
+    return FALSE;
+  }
+  (*ret_public_key)->pkcs = pkcs;
+  (*ret_public_key)->public_key = pubkey;
+
+  /* Allocate private key */
+  *ret_private_key = silc_calloc(1, sizeof(**ret_private_key));
+  if (!(*ret_private_key)) {
+    silc_free(pubkey);
+    silc_free(privkey);
+    silc_free(*ret_public_key);
+    return FALSE;
+  }
+  (*ret_private_key)->pkcs = pkcs;
+  (*ret_private_key)->private_key = privkey;
+
+  /* Generate the algorithm key pair */
+  if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
+                        &privkey->private_key)) {
+    silc_free(pubkey);
+    silc_free(privkey);
+    silc_free(*ret_public_key);
+    silc_free(*ret_private_key);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/**************************** Utility functions ******************************/
+
+/* Decodes the provided `identifier' */
+
+SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
+                                         SilcPublicKeyIdentifier ident)
+{
+  char *cp, *item;
+  int len;
+
+  /* Protocol says that at least UN and HN must be provided as identifier */
+  if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) {
+    SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
+                   "identifiers"));
+    return FALSE;
+  }
+
+  cp = (char *)identifier;
+  while (cp) {
+    len = strcspn(cp, ",");
+    if (len < 1) {
+      cp = NULL;
+      break;
+    }
+    if (len - 1 >= 0 && cp[len - 1] == '\\') {
+      while (cp) {
+       if (len + 1 > strlen(cp)) {
+         cp = NULL;
+         break;
+       }
+       cp += len + 1;
+       len = strcspn(cp, ",") + len;
+       if (len < 1) {
+         cp = NULL;
+         break;
+       }
+       if (len - 1 >= 0 && cp[len - 1] != '\\')
+         break;
+      }
+    }
+
+    if (!cp)
+      break;
+
+    item = silc_calloc(len + 1, sizeof(char));
+    if (!item)
+      return FALSE;
+    if (len > strlen(cp))
+      break;
+    memcpy(item, cp, len);
+
+    if (strstr(item, "UN="))
+      ident->username = strdup(item + strcspn(cp, "=") + 1);
+    else if (strstr(item, "HN="))
+      ident->host = strdup(item + strcspn(cp, "=") + 1);
+    else if (strstr(item, "RN="))
+      ident->realname = strdup(item + strcspn(cp, "=") + 1);
+    else if (strstr(item, "E="))
+      ident->email = strdup(item + strcspn(cp, "=") + 1);
+    else if (strstr(item, "O="))
+      ident->org = strdup(item + strcspn(cp, "=") + 1);
+    else if (strstr(item, "C="))
+      ident->country = strdup(item + strcspn(cp, "=") + 1);
+
+    cp += len;
+    if (strlen(cp) < 1)
+      cp = NULL;
+    else
+      cp += 1;
+
+    if (item)
+      silc_free(item);
+  }
+
+  return TRUE;
+}
+
+/* Encodes and returns SILC public key identifier.  If some of the
+   arguments is NULL those are not encoded into the identifier string.
+   Protocol says that at least username and host must be provided. */
+
+char *silc_pkcs_silc_encode_identifier(char *username, char *host,
+                                      char *realname, char *email,
+                                      char *org, char *country)
+{
+  SilcBuffer buf;
+  char *identifier;
+  SilcUInt32 len, tlen = 0;
+
+  if (!username || !host)
+    return NULL;
+
+  len = (username ? strlen(username) : 0) +
+       (host     ? strlen(host)     : 0) +
+       (realname ? strlen(realname) : 0) +
+       (email    ? strlen(email)    : 0) +
+       (org      ? strlen(org)      : 0) +
+       (country  ? strlen(country)  : 0);
+
+  if (len < 3)
+    return NULL;
+
+  len += 3 + 5 + 5 + 4 + 4 + 4;
+  buf = silc_buffer_alloc(len);
+  if (!buf)
+    return NULL;
+  silc_buffer_pull_tail(buf, len);
+
+  if (username) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING("UN="),
+                      SILC_STR_UI32_STRING(username),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 3 + strlen(username));
+    tlen = 3 + strlen(username);
+  }
+
+  if (host) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("HN="),
+                      SILC_STR_UI32_STRING(host),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 5 + strlen(host));
+    tlen += 5 + strlen(host);
+  }
+
+  if (realname) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("RN="),
+                      SILC_STR_UI32_STRING(realname),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 5 + strlen(realname));
+    tlen += 5 + strlen(realname);
+  }
+
+  if (email) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("E="),
+                      SILC_STR_UI32_STRING(email),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 4 + strlen(email));
+    tlen += 4 + strlen(email);
+  }
+
+  if (org) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("O="),
+                      SILC_STR_UI32_STRING(org),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 4 + strlen(org));
+    tlen += 4 + strlen(org);
+  }
+
+  if (country) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("C="),
+                      SILC_STR_UI32_STRING(country),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 4 + strlen(country));
+    tlen += 4 + strlen(country);
+  }
+
+  silc_buffer_push(buf, buf->data - buf->head);
+  identifier = silc_calloc(tlen + 1, sizeof(*identifier));
+  if (!identifier)
+    return NULL;
+  memcpy(identifier, buf->data, tlen);
+  silc_buffer_free(buf);
+
+  return identifier;
+}
+
+
+/*************************** Public key routines *****************************/
+
+/* Returns PKCS algorithm context */
+
+const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
+{
+  SilcSILCPublicKey silc_pubkey = public_key;
+  return silc_pubkey->pkcs;
+}
+
+/* Imports SILC protocol style public key from SILC public key file */
+
+SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
+                                              SilcUInt32 filedata_len,
+                                              SilcPKCSFileEncoding encoding,
+                                              void **ret_public_key)
+{
+  SilcUInt32 i, len;
+  unsigned char *data = NULL;
+  SilcBool ret;
+
+  SILC_LOG_DEBUG(("Parsing SILC public key file"));
+
+  if (!ret_public_key)
+    return FALSE;
+
+  /* Check start of file and remove header from the data. */
+  len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
+  if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END))
+    return FALSE;
+  for (i = 0; i < len; i++) {
+    if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i])
+      return FALSE;
+    filedata++;
+  }
+  filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
+                  strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+
+  switch (encoding) {
+  case SILC_PKCS_FILE_BIN:
+    break;
+
+  case SILC_PKCS_FILE_BASE64:
+    data = silc_pem_decode(filedata, filedata_len, &filedata_len);
+    if (!data)
+      return FALSE;
+    filedata = data;
+    break;
+  }
+
+  ret = silc_pkcs_silc_import_public_key(filedata, filedata_len,
+                                        ret_public_key);
+  silc_free(data);
+
+  return ret;
+}
+
+/* Imports SILC protocol style public key */
+
+SilcBool silc_pkcs_silc_import_public_key(unsigned char *key,
+                                         SilcUInt32 key_len,
+                                         void **ret_public_key)
+{
+  const SilcPKCSAlgorithm *pkcs;
+  SilcBufferStruct buf, alg_key;
+  SilcSILCPublicKey silc_pubkey = NULL;
+  SilcAsn1 asn1 = NULL;
+  SilcUInt32 totlen, keydata_len;
+  SilcUInt16 pkcs_len, identifier_len;
+  unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
+  int ret;
+
+  SILC_LOG_DEBUG(("Parsing SILC public key"));
+
+  if (!ret_public_key)
+    return FALSE;
+
+  silc_buffer_set(&buf, key, key_len);
+
+  /* Get length */
+  ret = silc_buffer_unformat(&buf,
+                            SILC_STR_UI_INT(&totlen),
+                            SILC_STR_END);
+  if (ret == -1)
+    goto err;
+
+  if (totlen + 4 != key_len)
+    goto err;
+
+  /* Get algorithm name and identifier */
+  ret =
+    silc_buffer_unformat(&buf,
+                        SILC_STR_OFFSET(4),
+                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
+                        SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
+                        SILC_STR_END);
+  if (ret == -1)
+    goto err;
+
+  if (pkcs_len < 1 || identifier_len < 3 ||
+      pkcs_len + identifier_len > totlen)
+    goto err;
+
+  /* Get key data */
+  silc_buffer_pull(&buf, 4 + 2 + pkcs_len + 2 + identifier_len);
+  keydata_len = silc_buffer_len(&buf);
+  ret = silc_buffer_unformat(&buf,
+                            SILC_STR_UI_XNSTRING(&key_data,
+                                                 keydata_len),
+                            SILC_STR_END);
+  if (ret == -1)
+    goto err;
+
+  /* Allocate SILC public key context */
+  silc_pubkey = silc_calloc(1, sizeof(*silc_pubkey));
+  if (!silc_pubkey)
+    goto err;
+
+  /* Decode SILC identifier */
+  if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
+    goto err;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    goto err;
+
+  if (!strcmp(pkcs_name, "rsa")) {
+    /* Parse the SILC RSA public key */
+    SilcUInt32 e_len, n_len;
+    SilcMPInt n, e;
+
+    /* Get PKCS object */
+    pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+    if (!pkcs) {
+      SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+      goto err;
+    }
+    silc_pubkey->pkcs = pkcs;
+
+    if (keydata_len < 4)
+      goto err;
+    SILC_GET32_MSB(e_len, key_data);
+    if (!e_len || e_len + 4 > keydata_len)
+      goto err;
+    silc_mp_init(&e);
+    silc_mp_bin2mp(key_data + 4, e_len, &e);
+    if (keydata_len < 4 + e_len + 4) {
+      silc_mp_uninit(&e);
+      goto err;
+    }
+    SILC_GET32_MSB(n_len, key_data + 4 + e_len);
+    if (!n_len || e_len + 4 + n_len + 4 > keydata_len) {
+      silc_mp_uninit(&e);
+      goto err;
+    }
+    silc_mp_init(&n);
+    silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &n);
+
+    /* Encode to PKCS #1 format */
+    memset(&alg_key, 0, sizeof(alg_key));
+    if (!silc_asn1_encode(asn1, &alg_key,
+                         SILC_ASN1_SEQUENCE,
+                           SILC_ASN1_INT(&n),
+                           SILC_ASN1_INT(&e),
+                         SILC_ASN1_END, SILC_ASN1_END)) {
+      silc_mp_uninit(&e);
+      silc_mp_uninit(&n);
+      goto err;
+    }
+
+    silc_mp_uninit(&e);
+    silc_mp_uninit(&n);
+
+  } else if (!strcmp(pkcs_name, "dsa")) {
+    SILC_NOT_IMPLEMENTED("DSA SILC Public Key");
+    goto err;
+
+  } else {
+    SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+    goto err;
+  }
+
+  /* Import PKCS algorithm public key */
+  if (pkcs->import_public_key)
+    if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
+                                &silc_pubkey->public_key))
+      goto err;
+
+  silc_free(pkcs_name);
+  silc_free(ident);
+  silc_asn1_free(asn1);
+
+  *ret_public_key = silc_pubkey;
+
+  return TRUE;
+
+ err:
+  silc_free(pkcs_name);
+  silc_free(ident);
+  silc_free(silc_pubkey);
+  if (asn1)
+    silc_asn1_free(asn1);
+  return FALSE;
+}
+
+/* Exports public key as SILC protocol style public key file */
+
+unsigned char *
+silc_pkcs_silc_export_public_key_file(void *public_key,
+                                     SilcPKCSFileEncoding encoding,
+                                     SilcUInt32 *ret_len)
+{
+  SilcBuffer buf;
+  unsigned char *key, *data;
+  SilcUInt32 key_len;
+
+  SILC_LOG_DEBUG(("Encoding SILC public key file"));
+
+  /* Export key */
+  key = silc_pkcs_silc_export_public_key(public_key, &key_len);
+  if (!key)
+    return NULL;
+
+  switch (encoding) {
+  case SILC_PKCS_FILE_BIN:
+    break;
+
+  case SILC_PKCS_FILE_BASE64:
+    data = silc_pem_encode_file(key, key_len);
+    if (!data)
+      return NULL;
+    silc_free(key);
+    key = data;
+    key_len = strlen(data);
+    break;
+  }
+
+  /* Encode SILC public key file */
+  buf = silc_buffer_alloc_size(key_len +
+                              (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
+                               strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
+  if (!buf) {
+    silc_free(key);
+    return NULL;
+  }
+
+  if (silc_buffer_format(buf,
+                        SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
+                        SILC_STR_UI_XNSTRING(key, key_len),
+                        SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
+                        SILC_STR_END) < 0) {
+    silc_buffer_free(buf);
+    silc_free(key);
+    return NULL;
+  }
+
+  silc_free(key);
+  key = silc_buffer_steal(buf, ret_len);
+  silc_buffer_free(buf);
+
+  return key;
+}
+
+/* Exports public key as SILC protocol style public key */
+
+unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
+                                               SilcUInt32 *ret_len)
+{
+  SilcSILCPublicKey silc_pubkey = public_key;
+  const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
+  SilcBufferStruct alg_key;
+  SilcBuffer buf = NULL;
+  SilcAsn1 asn1 = NULL;
+  unsigned char *pk = NULL, *key = NULL, *ret;
+  SilcUInt32 pk_len, key_len, totlen;
+  char *identifier;
+
+  SILC_LOG_DEBUG(("Encoding SILC public key"));
+
+  /* Export PKCS algorithm public key */
+  if (pkcs->export_public_key)
+    pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len);
+  if (!pk)
+    return NULL;
+  silc_buffer_set(&alg_key, pk, pk_len);
+
+  /* Encode identifier */
+  identifier =
+    silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
+                                    silc_pubkey->identifier.host,
+                                    silc_pubkey->identifier.realname,
+                                    silc_pubkey->identifier.email,
+                                    silc_pubkey->identifier.org,
+                                    silc_pubkey->identifier.country);
+  if (!identifier)
+    goto err;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    goto err;
+
+  if (!strcmp(pkcs->name, "rsa")) {
+    /* Parse the PKCS #1 public key */
+    SilcMPInt n, e;
+    SilcUInt32 n_len, e_len;
+    unsigned char *nb, *eb;
+
+    memset(&n, 0, sizeof(n));
+    memset(&e, 0, sizeof(e));
+    if (!silc_asn1_decode(asn1, &alg_key,
+                         SILC_ASN1_SEQUENCE,
+                           SILC_ASN1_INT(&n),
+                           SILC_ASN1_INT(&e),
+                         SILC_ASN1_END, SILC_ASN1_END))
+      goto err;
+
+    /* Encode to SILC RSA public key */
+    eb = silc_mp_mp2bin(&e, 0, &e_len);
+    if (!eb)
+      goto err;
+    nb = silc_mp_mp2bin(&n, 0, &n_len);
+    if (!nb)
+      goto err;
+    key_len = e_len + 4 + n_len + 4;
+    key = silc_calloc(key_len, sizeof(*key));
+    if (!key)
+      goto err;
+
+    /* Put e length and e */
+    SILC_PUT32_MSB(e_len, key);
+    memcpy(key + 4, eb, e_len);
+
+    /* Put n length and n. */
+    SILC_PUT32_MSB(n_len, key + 4 + e_len);
+    memcpy(key + 4 + e_len + 4, nb, n_len);
+
+    silc_free(nb);
+    silc_free(eb);
+
+  } else if (!strcmp(pkcs->name, "dsa")) {
+    SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
+    goto err;
+
+  } else {
+    SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+    goto err;
+  }
+
+  /* Encode SILC Public Key */
+  totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
+  buf = silc_buffer_alloc_size(totlen + 4);
+  if (!buf)
+    goto err;
+  if (silc_buffer_format(buf,
+                        SILC_STR_UI_INT(totlen),
+                        SILC_STR_UI_SHORT(strlen(pkcs->name)),
+                        SILC_STR_UI32_STRING(pkcs->name),
+                        SILC_STR_UI_SHORT(strlen(identifier)),
+                        SILC_STR_UI32_STRING(identifier),
+                        SILC_STR_UI_XNSTRING(key, key_len),
+                        SILC_STR_END) < 0)
+    goto err;
+
+  ret = silc_buffer_steal(buf, ret_len);
+  silc_buffer_free(buf);
+  silc_free(key);
+  silc_free(identifier);
+  silc_asn1_free(asn1);
+
+  return ret;
+
+ err:
+  silc_free(identifier);
+  silc_free(pk);
+  silc_free(key);
+  if (buf)
+    silc_buffer_free(buf);
+  if (asn1)
+    silc_asn1_free(asn1);
+  return NULL;
+}
+
+/* Return key length */
+
+SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
+{
+  SilcSILCPublicKey silc_pubkey = public_key;
+  return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
+}
+
+/* Copy public key */
+
+void *silc_pkcs_silc_public_key_copy(void *public_key)
+{
+  SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
+
+  new_pubkey = silc_calloc(1, sizeof(*new_pubkey));
+  if (!new_pubkey)
+    return NULL;
+  new_pubkey->pkcs = silc_pubkey->pkcs;
+
+  new_pubkey->public_key =
+    silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
+  if (!new_pubkey->public_key) {
+    silc_free(new_pubkey);
+    return NULL;
+  }
+
+  return new_pubkey;
+}
+
+/* Compares public keys */
+
+SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
+{
+  SilcSILCPublicKey k1 = key1, k2 = key2;
+
+  if (strcmp(k1->pkcs->name, k2->pkcs->name))
+    return FALSE;
+
+  if ((k1->identifier.username && !k2->identifier.username) ||
+      (!k1->identifier.username && k2->identifier.username) ||
+      (k1->identifier.username && k2->identifier.username &&
+       strcmp(k1->identifier.username, k2->identifier.username)))
+    return FALSE;
+
+  if ((k1->identifier.host && !k2->identifier.host) ||
+      (!k1->identifier.host && k2->identifier.host) ||
+      (k1->identifier.host && k2->identifier.host &&
+       strcmp(k1->identifier.host, k2->identifier.host)))
+    return FALSE;
+
+  if ((k1->identifier.realname && !k2->identifier.realname) ||
+      (!k1->identifier.realname && k2->identifier.realname) ||
+      (k1->identifier.realname && k2->identifier.realname &&
+       strcmp(k1->identifier.realname, k2->identifier.realname)))
+    return FALSE;
+
+  if ((k1->identifier.email && !k2->identifier.email) ||
+      (!k1->identifier.email && k2->identifier.email) ||
+      (k1->identifier.email && k2->identifier.email &&
+       strcmp(k1->identifier.email, k2->identifier.email)))
+    return FALSE;
+
+  if ((k1->identifier.org && !k2->identifier.org) ||
+      (!k1->identifier.org && k2->identifier.org) ||
+      (k1->identifier.org && k2->identifier.org &&
+       strcmp(k1->identifier.org, k2->identifier.org)))
+    return FALSE;
+
+  if ((k1->identifier.country && !k2->identifier.country) ||
+      (!k1->identifier.country && k2->identifier.country) ||
+      (k1->identifier.country && k2->identifier.country &&
+       strcmp(k1->identifier.country, k2->identifier.country)))
+    return FALSE;
+
+  return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
+}
+
+/* Frees public key */
+
+void silc_pkcs_silc_public_key_free(void *public_key)
+{
+  SilcSILCPublicKey silc_pubkey = public_key;
+
+  silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
+
+  silc_free(silc_pubkey->identifier.username);
+  silc_free(silc_pubkey->identifier.host);
+  silc_free(silc_pubkey->identifier.realname);
+  silc_free(silc_pubkey->identifier.email);
+  silc_free(silc_pubkey->identifier.org);
+  silc_free(silc_pubkey->identifier.country);
+  silc_free(silc_pubkey);
+}
+
+
+/*************************** Private key routines ****************************/
+
+/* Private key file magic */
+#define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
+
+/* Imports SILC implementation style private key file */
+
+SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
+                                               SilcUInt32 filedata_len,
+                                               const char *passphrase,
+                                               SilcUInt32 passphrase_len,
+                                               SilcPKCSFileEncoding encoding,
+                                               void **ret_private_key)
+{
+  SilcCipher aes;
+  SilcHash sha1;
+  SilcHmac sha1hmac;
+  SilcUInt32 blocklen;
+  unsigned char tmp[32], keymat[64], *data = NULL;
+  SilcUInt32 i, len, magic, mac_len;
+  SilcBool ret;
+
+  SILC_LOG_DEBUG(("Parsing SILC private key file"));
+
+  /* Check start of file and remove header from the data. */
+  len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
+  if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END))
+    return FALSE;
+  for (i = 0; i < len; i++) {
+    if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i])
+      return FALSE;
+    filedata++;
+  }
+
+  len = filedata_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
+                       strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+
+  switch (encoding) {
+  case SILC_PKCS_FILE_BIN:
+    break;
+
+  case SILC_PKCS_FILE_BASE64:
+    data = silc_pem_decode(filedata, filedata_len, &len);
+    if (!data)
+      return FALSE;
+    filedata = data;
+    break;
+  }
+
+  memset(tmp, 0, sizeof(tmp));
+  memset(keymat, 0, sizeof(keymat));
+
+  /* Check file magic */
+  SILC_GET32_MSB(magic, filedata);
+  if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
+    SILC_LOG_ERROR(("Private key does not have correct magic"));
+    return FALSE;
+  }
+
+  /* Allocate the AES cipher */
+  if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
+    SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
+    return FALSE;
+  }
+  blocklen = silc_cipher_get_block_len(aes);
+  if (blocklen * 2 > sizeof(tmp)) {
+    silc_cipher_free(aes);
+    return FALSE;
+  }
+
+  /* Allocate SHA1 hash */
+  if (!silc_hash_alloc("sha1", &sha1)) {
+    SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
+    silc_cipher_free(aes);
+    return FALSE;
+  }
+
+  /* Allocate HMAC */
+  if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
+    SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
+    silc_hash_free(sha1);
+    silc_cipher_free(aes);
+    return FALSE;
+  }
+
+  /* Derive the decryption key from the provided key material.  The key
+     is 256 bits length, and derived by taking hash of the data, then
+     re-hashing the data and the previous digest, and using the first and
+     second digest as the key. */
+  silc_hash_init(sha1);
+  silc_hash_update(sha1, passphrase, passphrase_len);
+  silc_hash_final(sha1, keymat);
+  silc_hash_init(sha1);
+  silc_hash_update(sha1, passphrase, passphrase_len);
+  silc_hash_update(sha1, keymat, 16);
+  silc_hash_final(sha1, keymat + 16);
+
+  /* Set the key to the cipher */
+  silc_cipher_set_key(aes, keymat, 256);
+
+  /* First, verify the MAC of the private key data */
+  mac_len = silc_hmac_len(sha1hmac);
+  silc_hmac_init_with_key(sha1hmac, keymat, 16);
+  silc_hmac_update(sha1hmac, filedata, len - mac_len);
+  silc_hmac_final(sha1hmac, tmp, NULL);
+  if (memcmp(tmp, filedata + (len - mac_len), mac_len)) {
+    SILC_LOG_DEBUG(("Integrity check for private key failed"));
+    memset(keymat, 0, sizeof(keymat));
+    memset(tmp, 0, sizeof(tmp));
+    silc_hmac_free(sha1hmac);
+    silc_hash_free(sha1);
+    silc_cipher_free(aes);
+    return FALSE;
+  }
+  filedata += 4;
+  len -= 4;
+
+  /* Decrypt the private key buffer */
+  silc_cipher_decrypt(aes, filedata, filedata, len - mac_len, NULL);
+  SILC_GET32_MSB(i, filedata);
+  if (i > len) {
+    SILC_LOG_DEBUG(("Bad private key length in buffer!"));
+    memset(keymat, 0, sizeof(keymat));
+    memset(tmp, 0, sizeof(tmp));
+    silc_hmac_free(sha1hmac);
+    silc_hash_free(sha1);
+    silc_cipher_free(aes);
+    return FALSE;
+  }
+  filedata += 4;
+  len = i;
+
+  /* Cleanup */
+  memset(keymat, 0, sizeof(keymat));
+  memset(tmp, 0, sizeof(tmp));
+  silc_hmac_free(sha1hmac);
+  silc_hash_free(sha1);
+  silc_cipher_free(aes);
+
+  /* Import the private key */
+  ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
+
+  silc_free(data);
+
+  return ret;
+}
+
+/* Private key version */
+#define SILC_PRIVATE_KEY_VERSION_1 0x82171273
+
+/* Imports SILC implementation style private key */
+
+SilcBool silc_pkcs_silc_import_private_key(unsigned char *key,
+                                          SilcUInt32 key_len,
+                                          void **ret_private_key)
+{
+  SilcBufferStruct buf;
+  const SilcPKCSAlgorithm *pkcs;
+  SilcBufferStruct alg_key;
+  SilcSILCPrivateKey silc_privkey = NULL;
+  SilcAsn1 asn1 = NULL;
+  SilcUInt16 pkcs_len;
+  SilcUInt32 keydata_len;
+  unsigned char *pkcs_name = NULL, *key_data;
+  int ret;
+
+  SILC_LOG_DEBUG(("Parsing SILC private key"));
+
+  if (!ret_private_key)
+    return FALSE;
+
+  silc_buffer_set(&buf, key, key_len);
+
+  /* Get algorithm name and identifier */
+  ret =
+    silc_buffer_unformat(&buf,
+                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
+                        SILC_STR_END);
+  if (ret == -1) {
+    SILC_LOG_DEBUG(("Cannot decode private key buffer"));
+    goto err;
+  }
+
+  if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
+    SILC_LOG_DEBUG(("Malformed private key buffer"));
+    goto err;
+  }
+
+  /* Get key data. We assume that rest of the buffer is key data. */
+  silc_buffer_pull(&buf, 2 + pkcs_len);
+  keydata_len = silc_buffer_len(&buf);
+  ret = silc_buffer_unformat(&buf,
+                            SILC_STR_UI_XNSTRING(&key_data, keydata_len),
+                            SILC_STR_END);
+  if (ret == -1)
+    goto err;
+
+  /* Allocate SILC private key context */
+  silc_privkey = silc_calloc(1, sizeof(*silc_privkey));
+  if (!silc_privkey)
+    goto err;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    goto err;
+
+  if (!strcmp(pkcs_name, "rsa")) {
+    /* Parse the RSA SILC private key */
+    SilcBufferStruct k;
+    SilcMPInt n, e, d, dp, dq, qp, p, q;
+    SilcMPInt version;
+    unsigned char *tmp;
+    SilcUInt32 len, ver;
+
+    /* Get PKCS object */
+    pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+    if (!pkcs) {
+      SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+      goto err;
+    }
+    silc_privkey->pkcs = pkcs;
+
+    if (keydata_len < 4)
+      goto err;
+
+    silc_buffer_set(&k, key_data, keydata_len);
+
+    /* Get version.  Key without the version is old style private key
+       and we need to do some computation to get it to correct format. */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_INT(&ver),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_buffer_pull(&k, 4);
+
+    if (ver != SILC_PRIVATE_KEY_VERSION_1) {
+      len = ver;
+    } else {
+      if (silc_buffer_unformat(&k,
+                              SILC_STR_UI_INT(&len),
+                              SILC_STR_END) < 0)
+       goto err;
+      silc_buffer_pull(&k, 4);
+    }
+
+    /* Get e */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_mp_init(&e);
+    silc_mp_bin2mp(tmp, len, &e);
+    silc_buffer_pull(&k, len);
+
+    /* Get n */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_INT(&len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_buffer_pull(&k, 4);
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_mp_init(&n);
+    silc_mp_bin2mp(tmp, len, &n);
+    silc_buffer_pull(&k, len);
+
+    /* Get d */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_INT(&len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_buffer_pull(&k, 4);
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_mp_init(&d);
+    silc_mp_bin2mp(tmp, len, &d);
+    silc_buffer_pull(&k, len);
+
+    /* Get dP */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_INT(&len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_buffer_pull(&k, 4);
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_mp_init(&dp);
+    silc_mp_bin2mp(tmp, len, &dp);
+    silc_buffer_pull(&k, len);
+
+    /* Get dQ */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_INT(&len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_buffer_pull(&k, 4);
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_mp_init(&dq);
+    silc_mp_bin2mp(tmp, len, &dq);
+    silc_buffer_pull(&k, len);
+
+    if (ver != SILC_PRIVATE_KEY_VERSION_1) {
+      /* Old version */
+
+      /* Get pQ len */
+      if (silc_buffer_unformat(&k,
+                              SILC_STR_UI_INT(&len),
+                              SILC_STR_END) < 0)
+       goto err;
+      silc_buffer_pull(&k, 4);
+      if (silc_buffer_len(&k) < len)
+       goto err;
+      silc_buffer_pull(&k, len);
+
+      /* Get qP len */
+      if (silc_buffer_unformat(&k,
+                              SILC_STR_UI_INT(&len),
+                              SILC_STR_END) < 0)
+       goto err;
+      silc_buffer_pull(&k, 4);
+      if (silc_buffer_len(&k) < len)
+       goto err;
+      silc_buffer_pull(&k, len);
+    } else {
+      /* New version */
+
+      /* Get qP */
+      if (silc_buffer_unformat(&k,
+                              SILC_STR_UI_INT(&len),
+                              SILC_STR_END) < 0)
+       goto err;
+      silc_buffer_pull(&k, 4);
+      if (silc_buffer_unformat(&k,
+                              SILC_STR_UI_XNSTRING(&tmp, len),
+                              SILC_STR_END) < 0)
+       goto err;
+      silc_mp_init(&qp);
+      silc_mp_bin2mp(tmp, len, &qp);
+      silc_buffer_pull(&k, len);
+    }
+
+    /* Get p */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_INT(&len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_buffer_pull(&k, 4);
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_mp_init(&p);
+    silc_mp_bin2mp(tmp, len, &p);
+    silc_buffer_pull(&k, len);
+
+    /* Get q */
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_INT(&len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_buffer_pull(&k, 4);
+    if (silc_buffer_unformat(&k,
+                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_END) < 0)
+      goto err;
+    silc_mp_init(&q);
+    silc_mp_bin2mp(tmp, len, &q);
+    silc_buffer_pull(&k, len);
+
+    if (ver != SILC_PRIVATE_KEY_VERSION_1) {
+      /* Old version.  Compute to new version */
+      SILC_LOG_DEBUG(("Old version private key"));
+      silc_mp_init(&qp);
+      silc_mp_modinv(&qp, &q, &p);
+    }
+
+    /* Encode to PKCS #1 format */
+    silc_mp_init(&version);
+    silc_mp_set_ui(&version, 0);
+    memset(&alg_key, 0, sizeof(alg_key));
+    if (!silc_asn1_encode(asn1, &alg_key,
+                         SILC_ASN1_SEQUENCE,
+                           SILC_ASN1_INT(&version),
+                           SILC_ASN1_INT(&n),
+                           SILC_ASN1_INT(&e),
+                           SILC_ASN1_INT(&d),
+                           SILC_ASN1_INT(&p),
+                           SILC_ASN1_INT(&q),
+                           SILC_ASN1_INT(&dp),
+                           SILC_ASN1_INT(&dq),
+                           SILC_ASN1_INT(&qp),
+                         SILC_ASN1_END, SILC_ASN1_END))
+      goto err;
+
+    silc_mp_uninit(&version);
+    silc_mp_uninit(&n);
+    silc_mp_uninit(&e);
+    silc_mp_uninit(&e);
+    silc_mp_uninit(&d);
+    silc_mp_uninit(&p);
+    silc_mp_uninit(&q);
+    silc_mp_uninit(&dp);
+    silc_mp_uninit(&dq);
+    silc_mp_uninit(&qp);
+
+  } else if (!strcmp(pkcs_name, "dsa")) {
+    SILC_NOT_IMPLEMENTED("DSA SILC Private Key");
+    goto err;
+
+  } else {
+    SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+    goto err;
+  }
+
+  /* Import PKCS algorithm private key */
+  if (pkcs->import_private_key)
+    if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
+                                 &silc_privkey->private_key))
+      goto err;
+
+  silc_free(pkcs_name);
+  silc_asn1_free(asn1);
+
+  *ret_private_key = silc_privkey;
+
+  return TRUE;
+
+ err:
+  silc_free(pkcs_name);
+  silc_free(silc_privkey);
+  if (asn1)
+    silc_asn1_free(asn1);
+  return FALSE;
+}
+
+/* Exports private key as SILC implementation style private key file */
+
+unsigned char *
+silc_pkcs_silc_export_private_key_file(void *private_key,
+                                      const char *passphrase,
+                                      SilcUInt32 passphrase_len,
+                                      SilcPKCSFileEncoding encoding,
+                                      SilcRng rng,
+                                      SilcUInt32 *ret_len)
+{
+  SilcCipher aes;
+  SilcHash sha1;
+  SilcHmac sha1hmac;
+  SilcBuffer buf, enc;
+  SilcUInt32 len, blocklen, padlen, key_len;
+  unsigned char *key, *data;
+  unsigned char tmp[32], keymat[64];
+  int i;
+
+  SILC_LOG_DEBUG(("Encoding SILC private key file"));
+
+  /* Export the private key */
+  key = silc_pkcs_silc_export_private_key(private_key, &key_len);
+  if (!key)
+    return NULL;
+
+  memset(tmp, 0, sizeof(tmp));
+  memset(keymat, 0, sizeof(keymat));
+
+  /* Allocate the AES cipher */
+  if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
+    SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
+    silc_free(key);
+    return NULL;
+  }
+  blocklen = silc_cipher_get_block_len(aes);
+  if (blocklen * 2 > sizeof(tmp)) {
+    silc_cipher_free(aes);
+    silc_free(key);
+    return NULL;
+  }
+
+  /* Allocate SHA1 hash */
+  if (!silc_hash_alloc("sha1", &sha1)) {
+    SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
+    silc_cipher_free(aes);
+    return NULL;
+  }
+
+  /* Allocate HMAC */
+  if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
+    SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
+    silc_hash_free(sha1);
+    silc_cipher_free(aes);
+    return NULL;
+  }
+
+  /* Derive the encryption key from the provided key material.  The key
+     is 256 bits length, and derived by taking hash of the data, then
+     re-hashing the data and the previous digest, and using the first and
+     second digest as the key. */
+  silc_hash_init(sha1);
+  silc_hash_update(sha1, passphrase, passphrase_len);
+  silc_hash_final(sha1, keymat);
+  silc_hash_init(sha1);
+  silc_hash_update(sha1, passphrase, passphrase_len);
+  silc_hash_update(sha1, keymat, 16);
+  silc_hash_final(sha1, keymat + 16);
+
+  /* Set the key to the cipher */
+  silc_cipher_set_key(aes, keymat, 256);
+
+  /* Encode the buffer to be encrypted.  Add padding to it too, at least
+     block size of the cipher. */
+
+  /* Allocate buffer for encryption */
+  len = silc_hmac_len(sha1hmac);
+  padlen = 16 + (16 - ((key_len + 4) % blocklen));
+  enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len);
+  if (!enc) {
+    silc_hmac_free(sha1hmac);
+    silc_hash_free(sha1);
+    silc_cipher_free(aes);
+    return FALSE;
+  }
+
+  /* Generate padding */
+  for (i = 0; i < padlen; i++)
+    tmp[i] = silc_rng_get_byte_fast(rng);
+
+  /* Put magic number */
+  SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
+  silc_buffer_pull(enc, 4);
+
+  /* Encode the buffer */
+  silc_buffer_format(enc,
+                    SILC_STR_UI_INT(key_len),
+                    SILC_STR_UI_XNSTRING(key, key_len),
+                    SILC_STR_UI_XNSTRING(tmp, padlen),
+                    SILC_STR_END);
+  silc_free(key);
+
+  /* Encrypt. */
+  silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
+                     silc_cipher_get_iv(aes));
+
+  silc_buffer_push(enc, 4);
+
+  /* Compute HMAC over the encrypted data and append the MAC to data.
+     The key is the first digest of the original key material. */
+  key_len = silc_buffer_len(enc) - len;
+  silc_hmac_init_with_key(sha1hmac, keymat, 16);
+  silc_hmac_update(sha1hmac, enc->data, key_len);
+  silc_buffer_pull(enc, key_len);
+  silc_hmac_final(sha1hmac, enc->data, NULL);
+  silc_buffer_push(enc, key_len);
+
+  /* Cleanup */
+  memset(keymat, 0, sizeof(keymat));
+  memset(tmp, 0, sizeof(tmp));
+  silc_hmac_free(sha1hmac);
+  silc_hash_free(sha1);
+  silc_cipher_free(aes);
+
+  switch (encoding) {
+  case SILC_PKCS_FILE_BIN:
+    break;
+
+  case SILC_PKCS_FILE_BASE64:
+    data = silc_pem_encode_file(enc->data, silc_buffer_len(enc));
+    if (!data) {
+      silc_buffer_clear(enc);
+      silc_buffer_free(enc);
+      return NULL;
+    }
+    silc_free(silc_buffer_steal(enc, NULL));
+    silc_buffer_set(enc, data, strlen(data));
+    break;
+  }
+
+  key = enc->data;
+  key_len = silc_buffer_len(enc);
+
+  /* Encode the data and save to file */
+  len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
+                  strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+  buf = silc_buffer_alloc_size(len);
+  if (!buf) {
+    silc_buffer_free(enc);
+    return NULL;
+  }
+  silc_buffer_format(buf,
+                    SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
+                    SILC_STR_UI_XNSTRING(key, key_len),
+                    SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
+                    SILC_STR_END);
+
+  silc_buffer_free(enc);
+  data = silc_buffer_steal(buf, ret_len);
+  silc_buffer_free(buf);
+
+  return data;
+}
+
+/* Exports private key as SILC implementation style private key */
+
+unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
+                                                SilcUInt32 *ret_len)
+{
+  SilcSILCPrivateKey silc_privkey = private_key;
+  const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
+  SilcBufferStruct alg_key;
+  SilcBuffer buf = NULL;
+  SilcAsn1 asn1 = NULL;
+  unsigned char *prv = NULL, *key = NULL, *ret;
+  SilcUInt32 prv_len, key_len, totlen;
+
+  SILC_LOG_DEBUG(("Encoding SILC private key"));
+
+  /* Export PKCS algorithm private key */
+  if (pkcs->export_private_key)
+    prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len);
+  if (!prv)
+    return NULL;
+  silc_buffer_set(&alg_key, prv, prv_len);
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    goto err;
+
+  if (!strcmp(pkcs->name, "rsa")) {
+    /* Parse the PKCS #1 private key */
+    SilcMPInt n, e, d, dp, dq, qp, p, q;
+    SilcUInt32 e_len, n_len, d_len, dp_len, dq_len,
+      qp_len, p_len, q_len, len = 0;
+    unsigned char *nb, *eb, *db, *dpb, *dqb, *qpb, *pb, *qb;
+
+    if (!silc_asn1_decode(asn1, &alg_key,
+                         SILC_ASN1_SEQUENCE,
+                           SILC_ASN1_INT(NULL),
+                           SILC_ASN1_INT(&n),
+                           SILC_ASN1_INT(&e),
+                           SILC_ASN1_INT(&d),
+                           SILC_ASN1_INT(&p),
+                           SILC_ASN1_INT(&q),
+                           SILC_ASN1_INT(&dp),
+                           SILC_ASN1_INT(&dq),
+                           SILC_ASN1_INT(&qp),
+                         SILC_ASN1_END, SILC_ASN1_END))
+      goto err;
+
+    /* Encode to SILC RSA private key */
+    eb = silc_mp_mp2bin(&e, 0, &e_len);
+    nb = silc_mp_mp2bin(&n, 0, &n_len);
+    db = silc_mp_mp2bin(&d, 0, &d_len);
+    dpb = silc_mp_mp2bin(&dp, 0, &dp_len);
+    dqb = silc_mp_mp2bin(&dq, 0, &dq_len);
+    qpb = silc_mp_mp2bin(&qp, 0, &qp_len);
+    pb = silc_mp_mp2bin(&p, 0, &p_len);
+    qb = silc_mp_mp2bin(&q, 0, &q_len);
+    len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 +
+      dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4;
+
+    buf = silc_buffer_alloc_size(len);
+    if (!buf)
+      goto err;
+    if (silc_buffer_format(buf,
+                          SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1),
+                          SILC_STR_UI_INT(e_len),
+                          SILC_STR_UI_XNSTRING(eb, e_len),
+                          SILC_STR_UI_INT(n_len),
+                          SILC_STR_UI_XNSTRING(nb, n_len),
+                          SILC_STR_UI_INT(d_len),
+                          SILC_STR_UI_XNSTRING(db, d_len),
+                          SILC_STR_UI_INT(dp_len),
+                          SILC_STR_UI_XNSTRING(dpb, dp_len),
+                          SILC_STR_UI_INT(dq_len),
+                          SILC_STR_UI_XNSTRING(dqb, dq_len),
+                          SILC_STR_UI_INT(qp_len),
+                          SILC_STR_UI_XNSTRING(qpb, qp_len),
+                          SILC_STR_UI_INT(p_len),
+                          SILC_STR_UI_XNSTRING(pb, p_len),
+                          SILC_STR_UI_INT(q_len),
+                          SILC_STR_UI_XNSTRING(qb, q_len),
+                          SILC_STR_END) < 0)
+      goto err;
+
+    key = silc_buffer_steal(buf, &key_len);
+    silc_buffer_free(buf);
+    silc_free(nb);
+    silc_free(eb);
+    silc_free(db);
+    silc_free(dpb);
+    silc_free(dqb);
+    silc_free(qpb);
+    silc_free(pb);
+    silc_free(qb);
+
+  } else if (!strcmp(pkcs->name, "dsa")) {
+    SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
+    goto err;
+
+  } else {
+    SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+    goto err;
+  }
+
+  /* Encode SILC private key */
+  totlen = 2 + strlen(pkcs->name) + key_len;
+  buf = silc_buffer_alloc_size(totlen);
+  if (!buf)
+    goto err;
+  if (silc_buffer_format(buf,
+                        SILC_STR_UI_SHORT(strlen(pkcs->name)),
+                        SILC_STR_UI32_STRING(pkcs->name),
+                        SILC_STR_UI_XNSTRING(key, key_len),
+                        SILC_STR_END) < 0)
+    goto err;
+
+  ret = silc_buffer_steal(buf, ret_len);
+  silc_buffer_free(buf);
+  silc_free(prv);
+  silc_free(key);
+  silc_asn1_free(asn1);
+
+  return ret;
+
+ err:
+  silc_free(prv);
+  silc_free(key);
+  if (buf)
+    silc_buffer_free(buf);
+  return NULL;
+}
+
+/* Return key length */
+
+SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
+{
+  SilcSILCPrivateKey silc_privkey = private_key;
+  return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
+}
+
+/* Frees private key */
+
+void silc_pkcs_silc_private_key_free(void *private_key)
+{
+  SilcSILCPrivateKey silc_privkey = private_key;
+
+  silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
+
+  silc_free(silc_privkey);
+}
+
+
+/***************************** PKCS operations ******************************/
+
+/* Encrypts as specified in SILC protocol specification */
+
+SilcBool silc_pkcs_silc_encrypt(void *public_key,
+                               unsigned char *src,
+                               SilcUInt32 src_len,
+                               unsigned char *dst,
+                               SilcUInt32 dst_size,
+                               SilcUInt32 *ret_dst_len)
+{
+  SilcSILCPublicKey silc_pubkey = public_key;
+
+  if (!silc_pubkey->pkcs->encrypt)
+    return FALSE;
+
+  return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
+                                   src, src_len,
+                                   dst, dst_size, ret_dst_len);
+}
+
+/* Decrypts as specified in SILC protocol specification */
+
+SilcBool silc_pkcs_silc_decrypt(void *private_key,
+                               unsigned char *src,
+                               SilcUInt32 src_len,
+                               unsigned char *dst,
+                               SilcUInt32 dst_size,
+                               SilcUInt32 *ret_dst_len)
+{
+  SilcSILCPrivateKey silc_privkey = private_key;
+
+  if (!silc_privkey->pkcs->decrypt)
+    return FALSE;
+
+  return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
+                                    src, src_len,
+                                    dst, dst_size, ret_dst_len);
+}
+
+/* Signs as specified in SILC protocol specification */
+
+SilcBool silc_pkcs_silc_sign(void *private_key,
+                            unsigned char *src,
+                            SilcUInt32 src_len,
+                            unsigned char *signature,
+                            SilcUInt32 signature_size,
+                            SilcUInt32 *ret_signature_len,
+                            SilcHash hash)
+{
+  SilcSILCPrivateKey silc_privkey = private_key;
+
+  if (!silc_privkey->pkcs->sign)
+    return FALSE;
+
+  return silc_privkey->pkcs->sign(silc_privkey->private_key,
+                                 src, src_len,
+                                 signature, signature_size,
+                                 ret_signature_len, hash);
+}
+
+/* Verifies as specified in SILC protocol specification */
+
+SilcBool silc_pkcs_silc_verify(void *public_key,
+                              unsigned char *signature,
+                              SilcUInt32 signature_len,
+                              unsigned char *data,
+                              SilcUInt32 data_len,
+                              SilcHash hash)
+{
+  SilcSILCPublicKey silc_pubkey = public_key;
+
+  if (!silc_pubkey->pkcs->verify)
+    return FALSE;
+
+  return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
+                                  signature, signature_len,
+                                  data, data_len, hash);
+}
diff --git a/lib/silccrypt/silcpk.h b/lib/silccrypt/silcpk.h
new file mode 100644 (file)
index 0000000..3db2cf2
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+
+  silcpk.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 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* silccrypt/SILC Public Key Interface
+ *
+ * DESCRIPTION
+ *
+ * This interface implements the SILC protocol style public key, as defined
+ * by the SILC protocol specification.
+ *
+ ***/
+
+#ifndef SILCPK_H
+#define SILCPK_H
+
+/****s* silccrypt/SilcPubkeyAPI/SilcPublicKeyIdentifier
+ *
+ * NAME
+ *
+ *    typedef struct { ... } *SilcPublicKeyIdentifier,
+ *                            SilcPublicKeyIdentifierStruct;
+ *
+ * DESCRIPTION
+ *
+ *    This structure contains the SILC Public Key identifier.  Note that
+ *    some of the fields may be NULL.
+ *
+ * SOURCE
+ */
+typedef struct {
+  char *username;
+  char *host;
+  char *realname;
+  char *email;
+  char *org;
+  char *country;
+} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct;
+/***/
+
+/****s* silccrypt/SilcPubkeyAPI/SilcSILCPublicKey
+ *
+ * NAME
+ *
+ *    typedef struct { ... } *SilcSILCPublicKey;
+ *
+ * DESCRIPTION
+ *
+ *    This structure defines the SILC protocol style public key.  User
+ *    doesn't have to access this structure usually, except when access to
+ *    the identifier is required.  The silc_pkcs_get_context for the
+ *    PKCS type SILC_PKCS_SILC returns this context.
+ *
+ * SOURCE
+ */
+typedef struct {
+  SilcPublicKeyIdentifierStruct identifier;
+  const SilcPKCSAlgorithm *pkcs;   /* PKCS algorithm */
+  void *public_key;               /* MPKCS algorithm specific public key */
+} *SilcSILCPublicKey;
+/***/
+
+/****s* silccrypt/SilcPubkeyAPI/SilcSILCPrivateKey
+ *
+ * NAME
+ *
+ *    typedef struct { ... } *SilcSILCPrivateKey;
+ *
+ * DESCRIPTION
+ *
+ *    This structure defines the SILC protocol implementation specific
+ *    private key.  This structure isn't usually needed by the user.
+ *
+ * SOURCE
+ */
+typedef struct {
+  const SilcPKCSAlgorithm *pkcs;   /* PKCS algorithm */
+  void *private_key;              /* PKCS algorithm specific private key */
+} *SilcSILCPrivateKey;
+/***/
+
+/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_generate_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
+ *                                         const char *scheme,
+ *                                         SilcUInt32 bits_key_len,
+ *                                         SilcRng rng,
+ *                                         SilcPublicKey *ret_public_key,
+ *                                         SilcPrivateKey *ret_private_key)
+ *
+ * DESCRIPTION
+ *
+ *    Generate a new SILC key pair of the algorithm type `algorithm' with
+ *    the key length in bits of `bits_key_len'.  The `scheme' may be NULL.
+ *    Returns FALSE if key generation failed.
+ *
+ * EXAMPLE
+ *
+ *    // Generate RSA key pair with 2048 bit key length, using PKCS #1
+ *    // no OID scheme.
+ *    silc_pkcs_silc_generate_key("rsa", "pkcs1-no-oid", 2048,
+ *                                rng, &public_key, &private_key);
+ *
+ ***/
+SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
+                                    const char *scheme,
+                                    SilcUInt32 bits_key_len,
+                                    const char *identifier,
+                                    SilcRng rng,
+                                    SilcPublicKey *ret_public_key,
+                                    SilcPrivateKey *ret_private_key);
+
+/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_decode_identifier
+ *
+ * SYNOPSIS
+ *
+ *    char *silc_pkcs_silc_encode_identifier(char *username, char *host,
+ *                                           char *realname, char *email,
+ *                                           char *org, char *country)
+ *
+ * DESCRIPTION
+ *
+ *    Encodes and returns SILC public key identifier.  If some of the
+ *    arguments are NULL those are not encoded into the identifier string.
+ *    Protocol says that at least username and host must be provided.
+ *    Caller must free the returned identifier string.
+ *
+ ***/
+char *silc_pkcs_silc_encode_identifier(char *username, char *host,
+                                      char *realname, char *email,
+                                      char *org, char *country);
+
+/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_decode_identifier
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
+ *                                              SilcPublicKeyIdentifier ident);
+ *
+ * DESCRIPTION
+ *
+ *    Decodes SILC protocol public key identifier `identifier' into the
+ *    the `ident' structure.  Returns FALSE if the identifier is not valid
+ *    identifier string.
+ *
+ ***/
+SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
+                                         SilcPublicKeyIdentifier ident);
+
+#endif /* SILCPK_H */
diff --git a/lib/silccrypt/silcpk_i.h b/lib/silccrypt/silcpk_i.h
new file mode 100644 (file)
index 0000000..3802965
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+
+  silcpk_i.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 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 SILCPK_I_H
+#define SILCPK_I_H
+
+/* Public and private key file headers */
+#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n"
+
+const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key);
+SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
+                                              SilcUInt32 filedata_len,
+                                              SilcPKCSFileEncoding encoding,
+                                              void **ret_public_key);
+SilcBool silc_pkcs_silc_import_public_key(unsigned char *key,
+                                         SilcUInt32 key_len,
+                                         void **ret_public_key);
+unsigned char *
+silc_pkcs_silc_export_public_key_file(void *public_key,
+                                     SilcPKCSFileEncoding encoding,
+                                     SilcUInt32 *ret_len);
+unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
+                                               SilcUInt32 *ret_len);
+SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key);
+void *silc_pkcs_silc_public_key_copy(void *public_key);
+SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2);
+void silc_pkcs_silc_public_key_free(void *public_key);
+SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
+                                               SilcUInt32 filedata_len,
+                                               const char *passphrase,
+                                               SilcUInt32 passphrase_len,
+                                               SilcPKCSFileEncoding encoding,
+                                               void **ret_private_key);
+SilcBool silc_pkcs_silc_import_private_key(unsigned char *key,
+                                          SilcUInt32 key_len,
+                                          void **ret_private_key);
+unsigned char *
+silc_pkcs_silc_export_private_key_file(void *private_key,
+                                      const char *passphrase,
+                                      SilcUInt32 passphrase_len,
+                                      SilcPKCSFileEncoding encoding,
+                                      SilcRng rng,
+                                      SilcUInt32 *ret_len);
+unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
+                                                SilcUInt32 *ret_len);
+SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key);
+void silc_pkcs_silc_private_key_free(void *private_key);
+SilcBool silc_pkcs_silc_encrypt(void *public_key,
+                               unsigned char *src,
+                               SilcUInt32 src_len,
+                               unsigned char *dst,
+                               SilcUInt32 dst_size,
+                               SilcUInt32 *ret_dst_len);
+SilcBool silc_pkcs_silc_decrypt(void *private_key,
+                               unsigned char *src,
+                               SilcUInt32 src_len,
+                               unsigned char *dst,
+                               SilcUInt32 dst_size,
+                               SilcUInt32 *ret_dst_len);
+SilcBool silc_pkcs_silc_sign(void *private_key,
+                            unsigned char *src,
+                            SilcUInt32 src_len,
+                            unsigned char *signature,
+                            SilcUInt32 signature_size,
+                            SilcUInt32 *ret_signature_len,
+                            SilcHash hash);
+SilcBool silc_pkcs_silc_verify(void *public_key,
+                              unsigned char *signature,
+                              SilcUInt32 signature_len,
+                              unsigned char *data,
+                              SilcUInt32 data_len,
+                              SilcHash hash);
+
+#endif /* SILCPK_I_H */
index 240456ff481380d89647ee664654bb9700b4d430..7aeb3d1c09ecf41979fafe3abf4eefc8af9a93eb 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2006 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
 /* $Id$ */
 
 #include "silc.h"
-
-#include "rsa.h"
-
-/* The main SILC PKCS structure. */
-struct SilcPKCSStruct {
-  void *context;               /* Algorithm internal context */
-  SilcPKCSObject *pkcs;                /* Algorithm implementation */
-  SilcUInt32 key_len;          /* Key length in bits */
-};
+#include "silcpk_i.h"
+#include "silcpkcs1_i.h"
 
 #ifndef SILC_EPOC
 /* Dynamically registered list of PKCS. */
 SilcDList silc_pkcs_list = NULL;
+SilcDList silc_pkcs_alg_list = NULL;
 #define SILC_PKCS_LIST silc_pkcs_list
+#define SILC_PKCS_ALG_LIST silc_pkcs_alg_list
 #else
 #define SILC_PKCS_LIST TRUE
+#define SILC_PKCS_ALG_LIST TRUE
 #endif /* SILC_EPOC */
 
 /* Static list of PKCS for silc_pkcs_register_default(). */
 const SilcPKCSObject silc_default_pkcs[] =
 {
-  /* RSA with PKCS #1 for SILC PKCS */
-  { "rsa", SILC_PKCS_SILC,
-    silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
-    silc_rsa_get_private_key, silc_rsa_set_public_key,
-    silc_rsa_set_private_key, silc_rsa_context_len,
-    silc_pkcs1_encrypt, silc_pkcs1_decrypt,
-    silc_pkcs1_sign, silc_pkcs1_verify },
-
-  /* RSASSA-PKCS1-V1_5 for SSH2 PKCS */
-/*
-  { "rsa", SILC_PKCS_SSH2,
-    silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
-    silc_rsa_get_private_key, silc_rsa_set_public_key,
-    silc_rsa_set_private_key, silc_rsa_context_len,
-    silc_pkcs1_encrypt, silc_pkcs1_decrypt,
-    silc_pkcs1_sign, silc_pkcs1_verify },
-*/
+  /* SILC PKCS */
+  {
+    SILC_PKCS_SILC,
+    silc_pkcs_silc_get_algorithm,
+    silc_pkcs_silc_import_public_key_file,
+    silc_pkcs_silc_import_public_key,
+    silc_pkcs_silc_export_public_key_file,
+    silc_pkcs_silc_export_public_key,
+    silc_pkcs_silc_public_key_bitlen,
+    silc_pkcs_silc_public_key_copy,
+    silc_pkcs_silc_public_key_compare,
+    silc_pkcs_silc_public_key_free,
+    silc_pkcs_silc_import_private_key_file,
+    silc_pkcs_silc_import_private_key,
+    silc_pkcs_silc_export_private_key_file,
+    silc_pkcs_silc_export_private_key,
+    silc_pkcs_silc_private_key_bitlen,
+    silc_pkcs_silc_private_key_free,
+    silc_pkcs_silc_encrypt,
+    silc_pkcs_silc_decrypt,
+    silc_pkcs_silc_sign,
+    silc_pkcs_silc_verify,
+  },
+
+  {
+    0, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL
+  }
+};
+
+/* Builtin PKCS algorithms */
+const SilcPKCSAlgorithm silc_default_pkcs_alg[] =
+{
+  /* PKCS #1, Version 1.5 without hash OIDs */
+  {
+    "rsa",
+    "pkcs1-no-oid",
+    "sha1,md5",
+    silc_pkcs1_generate_key,
+    silc_pkcs1_import_public_key,
+    silc_pkcs1_export_public_key,
+    silc_pkcs1_public_key_bitlen,
+    silc_pkcs1_public_key_copy,
+    silc_pkcs1_public_key_compare,
+    silc_pkcs1_public_key_free,
+    silc_pkcs1_import_private_key,
+    silc_pkcs1_export_private_key,
+    silc_pkcs1_private_key_bitlen,
+    silc_pkcs1_private_key_free,
+    silc_pkcs1_encrypt,
+    silc_pkcs1_decrypt,
+    silc_pkcs1_sign_no_oid,
+    silc_pkcs1_verify_no_oid
+  },
+
+  /* PKCS #1, Version 1.5 */
+  {
+    "rsa",
+    "pkcs1",
+    "sha1,md5",
+    silc_pkcs1_generate_key,
+    silc_pkcs1_import_public_key,
+    silc_pkcs1_export_public_key,
+    silc_pkcs1_public_key_bitlen,
+    silc_pkcs1_public_key_copy,
+    silc_pkcs1_public_key_compare,
+    silc_pkcs1_public_key_free,
+    silc_pkcs1_import_private_key,
+    silc_pkcs1_export_private_key,
+    silc_pkcs1_private_key_bitlen,
+    silc_pkcs1_private_key_free,
+    silc_pkcs1_encrypt,
+    silc_pkcs1_decrypt,
+    silc_pkcs1_sign,
+    silc_pkcs1_verify
+  },
 
-  { NULL, 0, NULL, NULL, NULL, NULL,
-    NULL, NULL, NULL, NULL, NULL, NULL }
+  {
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL,
+    NULL, NULL
+  }
 };
 
-/* Register a new PKCS into SILC. This is used at the initialization of
-   the SILC. */
+/* Register a new PKCS into SILC. */
 
 SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs)
 {
 #ifndef SILC_EPOC
-  SilcPKCSObject *new;
+  SilcPKCSObject *newpkcs;
 
-  SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
+  SILC_LOG_DEBUG(("Registering new PKCS"));
 
   /* Check if exists already */
   if (silc_pkcs_list) {
     SilcPKCSObject *entry;
     silc_dlist_start(silc_pkcs_list);
     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
-      if (!strcmp(entry->name, pkcs->name) &&
-         entry->type == pkcs->type)
+      if (entry->type == pkcs->type)
         return FALSE;
     }
   }
 
-  new = silc_calloc(1, sizeof(*new));
-  new->name = strdup(pkcs->name);
-  new->type = pkcs->type;
-  new->init = pkcs->init;
-  new->clear_keys = pkcs->clear_keys;
-  new->get_public_key = pkcs->get_public_key;
-  new->get_private_key = pkcs->get_private_key;
-  new->set_public_key = pkcs->set_public_key;
-  new->set_private_key = pkcs->set_private_key;
-  new->context_len = pkcs->context_len;
-  new->encrypt = pkcs->encrypt;
-  new->decrypt = pkcs->decrypt;
-  new->sign = pkcs->sign;
-  new->verify = pkcs->verify;
+  newpkcs = silc_calloc(1, sizeof(*newpkcs));
+  if (!newpkcs)
+    return FALSE;
+  *newpkcs = *pkcs;
 
   /* Add to list */
   if (silc_pkcs_list == NULL)
     silc_pkcs_list = silc_dlist_init();
-  silc_dlist_add(silc_pkcs_list, new);
+  silc_dlist_add(silc_pkcs_list, newpkcs);
 
 #endif /* SILC_EPOC */
   return TRUE;
@@ -123,7 +170,6 @@ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs)
   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
     if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
       silc_dlist_del(silc_pkcs_list, entry);
-      silc_free(entry->name);
       silc_free(entry);
 
       if (silc_dlist_count(silc_pkcs_list) == 0) {
@@ -139,132 +185,149 @@ SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs)
   return FALSE;
 }
 
-/* Function that registers all the default PKCS (all builtin PKCS).
-   The application may use this to register the default PKCS if specific
-   PKCS in any specific order is not wanted. */
+/* Register algorithm */
 
-SilcBool silc_pkcs_register_default(void)
+SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs)
 {
 #ifndef SILC_EPOC
-  int i;
+  SilcPKCSAlgorithm *newalg;
 
-  for (i = 0; silc_default_pkcs[i].name; i++)
-    silc_pkcs_register(&(silc_default_pkcs[i]));
-
-#endif /* SILC_EPOC */
-  return TRUE;
-}
+  SILC_LOG_DEBUG(("Registering new PKCS algorithm %s",
+                 pkcs->name));
 
-SilcBool silc_pkcs_unregister_all(void)
-{
-#ifndef SILC_EPOC
-  SilcPKCSObject *entry;
+  /* Check if exists already */
+  if (silc_pkcs_alg_list) {
+    SilcPKCSAlgorithm *entry;
+    silc_dlist_start(silc_pkcs_alg_list);
+    while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
+      if (!strcmp(entry->name, pkcs->name) &&
+         entry->scheme && pkcs->scheme &&
+         !strcmp(entry->scheme, pkcs->scheme))
+        return FALSE;
+    }
+  }
 
-  if (!silc_pkcs_list)
+  newalg = silc_calloc(1, sizeof(*newalg));
+  if (!newalg)
     return FALSE;
 
-  silc_dlist_start(silc_pkcs_list);
-  while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
-    silc_pkcs_unregister(entry);
-    if (!silc_pkcs_list)
-      break;
+  *newalg = *pkcs;
+  newalg->name = strdup(pkcs->name);
+  if (!newalg->name)
+    return FALSE;
+  if (pkcs->scheme) {
+    newalg->scheme = strdup(pkcs->scheme);
+    if (!newalg->scheme)
+      return FALSE;
   }
+  newalg->hash = strdup(pkcs->hash);
+  if (!newalg->hash)
+    return FALSE;
+
+  /* Add to list */
+  if (silc_pkcs_alg_list == NULL)
+    silc_pkcs_alg_list = silc_dlist_init();
+  silc_dlist_add(silc_pkcs_alg_list, newalg);
+
 #endif /* SILC_EPOC */
   return TRUE;
 }
 
-/* Allocates a new SilcPKCS object. The new allocated object is returned
-   to the 'new_pkcs' argument. */
+/* Unregister algorithm */
 
-SilcBool silc_pkcs_alloc(const unsigned char *name, SilcPKCSType type,
-                        SilcPKCS *new_pkcs)
+SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs)
 {
-  SilcPKCSObject *entry = NULL;
+#ifndef SILC_EPOC
+  SilcPKCSAlgorithm*entry;
 
-  SILC_LOG_DEBUG(("Allocating new PKCS object"));
+  SILC_LOG_DEBUG(("Unregistering PKCS algorithm"));
 
-#ifndef SILC_EPOC
-  if (silc_pkcs_list) {
-    silc_dlist_start(silc_pkcs_list);
-    while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
-      if (!strcmp(entry->name, name) && entry->type == type)
-       break;
-    }
-  }
-#else
-  {
-    /* On EPOC which don't have globals we check our constant hash list. */
-    int i;
-    for (i = 0; silc_default_pkcs[i].name; i++) {
-      if (!strcmp(silc_default_pkcs[i].name, name) &&
-         silc_default_pkcs[i].type == type) {
-       entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
-       break;
+  if (!silc_pkcs_alg_list)
+    return FALSE;
+
+  silc_dlist_start(silc_pkcs_alg_list);
+  while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
+    if (pkcs == SILC_ALL_PKCS_ALG || entry == pkcs) {
+      silc_dlist_del(silc_pkcs_alg_list, entry);
+      silc_free(entry->name);
+      silc_free(entry->scheme);
+      silc_free(entry->hash);
+      silc_free(entry);
+
+      if (silc_dlist_count(silc_pkcs_alg_list) == 0) {
+       silc_dlist_uninit(silc_pkcs_alg_list);
+       silc_pkcs_alg_list = NULL;
       }
-    }
-  }
-#endif /* SILC_EPOC */
 
-  if (entry) {
-    *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
-    (*new_pkcs)->pkcs = entry;
-    (*new_pkcs)->context = silc_calloc(1, entry->context_len());
-    return TRUE;
+      return TRUE;
+    }
   }
 
+#endif /* SILC_EPOC */
   return FALSE;
 }
 
-/* Free's the PKCS object */
+/* Function that registers all the default PKCS and PKCS algorithms. */
 
-void silc_pkcs_free(SilcPKCS pkcs)
+SilcBool silc_pkcs_register_default(void)
 {
-  if (pkcs) {
-    pkcs->pkcs->clear_keys(pkcs->context);
-    silc_free(pkcs->context);
-  }
-  silc_free(pkcs);
-}
+#ifndef SILC_EPOC
+  int i;
+
+  for (i = 0; silc_default_pkcs[i].type; i++)
+    silc_pkcs_register(&(silc_default_pkcs[i]));
 
-/* Return TRUE if PKCS algorithm `name' is supported. */
+  for (i = 0; silc_default_pkcs_alg[i].name; i++)
+    silc_pkcs_algorithm_register(&(silc_default_pkcs_alg[i]));
+
+#endif /* SILC_EPOC */
+  return TRUE;
+}
 
-SilcBool silc_pkcs_is_supported(const unsigned char *name)
+SilcBool silc_pkcs_unregister_all(void)
 {
 #ifndef SILC_EPOC
   SilcPKCSObject *entry;
+  SilcPKCSAlgorithm *alg;
 
   if (silc_pkcs_list) {
     silc_dlist_start(silc_pkcs_list);
     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
-      if (!strcmp(entry->name, name))
-       return TRUE;
+      silc_pkcs_unregister(entry);
+      if (!silc_pkcs_list)
+       break;
     }
   }
-#else
-  {
-    int i;
-    for (i = 0; silc_default_pkcs[i].name; i++)
-      if (!strcmp(silc_default_pkcs[i].name, name))
-       return TRUE;
+
+  if (silc_pkcs_alg_list) {
+    silc_dlist_start(silc_pkcs_alg_list);
+    while ((alg = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
+      silc_pkcs_algorithm_unregister(alg);
+      if (!silc_pkcs_alg_list)
+       break;
+    }
   }
+
 #endif /* SILC_EPOC */
-  return FALSE;
+  return TRUE;
 }
 
 /* Returns comma separated list of supported PKCS algorithms */
 
 char *silc_pkcs_get_supported(void)
 {
-  SilcPKCSObject *entry;
+  SilcPKCSAlgorithm *entry;
   char *list = NULL;
   int len = 0;
 
 #ifndef SILC_EPOC
-  if (silc_pkcs_list) {
-    silc_dlist_start(silc_pkcs_list);
-    while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
+  if (silc_pkcs_alg_list) {
+    silc_dlist_start(silc_pkcs_alg_list);
+    while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
+      if (!list)
+       return NULL;
 
       memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
@@ -275,10 +338,12 @@ char *silc_pkcs_get_supported(void)
 #else
   {
     int i;
-    for (i = 0; silc_default_pkcs[i].name; i++) {
-      entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
+    for (i = 0; silc_default_pkcs_alg[i].name; i++) {
+      entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
+      if (!list)
+       return NULL;
 
       memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
@@ -293,626 +358,254 @@ char *silc_pkcs_get_supported(void)
   return list;
 }
 
-/* Generate new key pair into the `pkcs' context. */
+/* Finds PKCS object */
 
-SilcBool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
-                               SilcRng rng)
+const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type)
 {
-  SilcBool ret = pkcs->pkcs->init(pkcs->context, bits_key_len, rng);
-  if (ret)
-    pkcs->key_len = bits_key_len;
-  return ret;
-}
-
-/* Returns the length of the key */
+  SilcPKCSObject *entry;
 
-SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
-{
-  return pkcs->key_len;
-}
+#ifndef SILC_EPOC
+  if (silc_pkcs_list) {
+    silc_dlist_start(silc_pkcs_list);
+    while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
+      if (entry->type == type)
+       return (const SilcPKCSObject *)entry;
+    }
+  }
+#else
+  {
+    int i;
+    for (i = 0; silc_default_pkcs[i].name; i++) {
+      entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
+      if (entry->type == type)
+       return (const SilcPKCSObject *)entry;
+    }
+  }
+#endif /* SILC_EPOC */
 
-const char *silc_pkcs_get_name(SilcPKCS pkcs)
-{
-  return pkcs->pkcs->name;
+  return NULL;
 }
 
-/* Returns SILC style public key */
+/* Finds PKCS algorithms object */
 
-unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
+const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
+                                                 const char *scheme)
 {
-  return pkcs->pkcs->get_public_key(pkcs->context, len);
-}
+  SilcPKCSAlgorithm *entry;
 
-/* Returns SILC style private key */
+#ifndef SILC_EPOC
+  if (silc_pkcs_alg_list) {
+    silc_dlist_start(silc_pkcs_alg_list);
+    while ((entry = silc_dlist_get(silc_pkcs_alg_list)) != SILC_LIST_END) {
+      if (!strcmp(entry->name, algorithm) &&
+         (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
+       return (const SilcPKCSAlgorithm *)entry;
+    }
+  }
+#else
+  {
+    int i;
+    for (i = 0; silc_default_pkcs_alg[i].name; i++) {
+      entry = (SilcPKCSAlgorithm *)&(silc_default_pkcs_alg[i]);
+      if (!strcmp(entry->name, algorithm) &&
+         (!scheme || !entry->scheme || !strcmp(entry->scheme, scheme)))
+       return (const SilcPKCSAlgorithm *)entry;
+    }
+  }
+#endif /* SILC_EPOC */
 
-unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
-{
-  return pkcs->pkcs->get_private_key(pkcs->context, len);
+  return NULL;
 }
 
-/* Sets public key from SilcPublicKey. */
+/* Returns PKCS context */
 
-SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
+const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key)
 {
-  pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
-                                            public_key->pk_len);
-  return pkcs->key_len;
+  return public_key->pkcs;
 }
 
-/* Sets public key from data. */
+/* Returns PKCS algorithm context */
 
-SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
-                                    SilcUInt32 pk_len)
+const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(SilcPublicKey public_key)
 {
-  pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
-  return pkcs->key_len;
+  return public_key->pkcs->get_algorithm(public_key->public_key);
 }
 
-/* Sets private key from SilcPrivateKey. */
+/* Return algorithm name */
 
-SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
+const char *silc_pkcs_get_name(SilcPublicKey public_key)
 {
-  SilcUInt32 key_len;
-  key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
-                                       private_key->prv_len);
-  if (!pkcs->key_len)
-    pkcs->key_len = key_len;
-  return pkcs->key_len;
+  const SilcPKCSAlgorithm *pkcs = silc_pkcs_get_algorithm(public_key);
+  return pkcs->name;
 }
 
-/* Sets private key from data. */
+/* Returns PKCS type */
 
-SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
-                                         SilcUInt32 prv_len)
+SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key)
 {
-  SilcUInt32 key_len;
-  key_len = pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
-  if (!pkcs->key_len)
-    pkcs->key_len = key_len;
-  return pkcs->key_len;
+  return public_key->pkcs->type;
 }
 
-/* Encrypts */
+/* Allocates new public key from the key data */
 
-SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
-                      unsigned char *dst, SilcUInt32 *dst_len)
+SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
+                                   unsigned char *key,
+                                   SilcUInt32 key_len,
+                                   SilcPublicKey *ret_public_key)
 {
-  return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
-}
+  const SilcPKCSObject *pkcs;
+  SilcPublicKey public_key;
 
-/* Decrypts */
+  if (!ret_public_key)
+    return FALSE;
 
-SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
-                      unsigned char *dst, SilcUInt32 *dst_len)
-{
-  return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
-}
+  /* Allocate public key context */
+  public_key = silc_calloc(1, sizeof(*public_key));
+  if (!public_key)
+    return FALSE;
 
-/* Generates signature */
+  public_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
+  if (!public_key->pkcs) {
+    silc_free(public_key);
+    return FALSE;
+  }
 
-SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
-                   unsigned char *dst, SilcUInt32 *dst_len)
-{
-  return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
-}
+  /* Import the PKCS public key */
+  if (!pkcs->import_public_key(key, key_len, &public_key->public_key)) {
+    silc_free(public_key);
+    return FALSE;
+  }
 
-/* Verifies signature */
+  *ret_public_key = public_key;
 
-SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
-                     SilcUInt32 signature_len, unsigned char *data,
-                     SilcUInt32 data_len)
-{
-  return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
-                           data, data_len);
+  return TRUE;
 }
 
-/* Generates signature with hash. The hash is signed. */
+/* Frees the public key */
 
-SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
-                             unsigned char *src, SilcUInt32 src_len,
-                             unsigned char *dst, SilcUInt32 *dst_len)
+void silc_pkcs_public_key_free(SilcPublicKey public_key)
 {
-  unsigned char hashr[SILC_HASH_MAXLEN];
-  SilcUInt32 hash_len;
-  int ret;
-
-  silc_hash_make(hash, src, src_len, hashr);
-  hash_len = silc_hash_len(hash);
-
-  SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
-
-  ret = pkcs->pkcs->sign(pkcs->context, hashr, hash_len, dst, dst_len);
-  memset(hashr, 0, sizeof(hashr));
-
-  return ret;
+  public_key->pkcs->public_key_free(public_key->public_key);
 }
 
-/* Verifies signature with hash. The `data' is hashed and verified against
-   the `signature'. */
+/* Exports public key */
 
-SilcBool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
-                               unsigned char *signature,
-                               SilcUInt32 signature_len,
-                               unsigned char *data,
-                               SilcUInt32 data_len)
+unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
+                                          SilcUInt32 *ret_len)
 {
-  unsigned char hashr[SILC_HASH_MAXLEN];
-  SilcUInt32 hash_len;
-  int ret;
-
-  silc_hash_make(hash, data, data_len, hashr);
-  hash_len = silc_hash_len(hash);
-
-  SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
-
-  ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
-                          hashr, hash_len);
-  memset(hashr, 0, sizeof(hashr));
-
-  return ret;
+  return public_key->pkcs->export_public_key(public_key->public_key,
+                                            ret_len);
 }
 
-/* Encodes and returns SILC public key identifier. If some of the
-   arguments is NULL those are not encoded into the identifier string.
-   Protocol says that at least username and host must be provided. */
+/* Return key length */
 
-char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
-                                 char *email, char *org, char *country)
+SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key)
 {
-  SilcBuffer buf;
-  char *identifier;
-  SilcUInt32 len, tlen = 0;
-
-  if (!username || !host)
-    return NULL;
-
-  len = (username ? strlen(username) : 0) +
-       (host     ? strlen(host)     : 0) +
-       (realname ? strlen(realname) : 0) +
-       (email    ? strlen(email)    : 0) +
-       (org      ? strlen(org)      : 0) +
-       (country  ? strlen(country)  : 0);
-
-  if (len < 3)
-    return NULL;
-
-  len += 3 + 5 + 5 + 4 + 4 + 4;
-  buf = silc_buffer_alloc(len);
-  silc_buffer_pull_tail(buf, len);
-
-  if (username) {
-    silc_buffer_format(buf,
-                      SILC_STR_UI32_STRING("UN="),
-                      SILC_STR_UI32_STRING(username),
-                      SILC_STR_END);
-    silc_buffer_pull(buf, 3 + strlen(username));
-    tlen = 3 + strlen(username);
-  }
-
-  if (host) {
-    silc_buffer_format(buf,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("HN="),
-                      SILC_STR_UI32_STRING(host),
-                      SILC_STR_END);
-    silc_buffer_pull(buf, 5 + strlen(host));
-    tlen += 5 + strlen(host);
-  }
-
-  if (realname) {
-    silc_buffer_format(buf,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("RN="),
-                      SILC_STR_UI32_STRING(realname),
-                      SILC_STR_END);
-    silc_buffer_pull(buf, 5 + strlen(realname));
-    tlen += 5 + strlen(realname);
-  }
-
-  if (email) {
-    silc_buffer_format(buf,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("E="),
-                      SILC_STR_UI32_STRING(email),
-                      SILC_STR_END);
-    silc_buffer_pull(buf, 4 + strlen(email));
-    tlen += 4 + strlen(email);
-  }
-
-  if (org) {
-    silc_buffer_format(buf,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("O="),
-                      SILC_STR_UI32_STRING(org),
-                      SILC_STR_END);
-    silc_buffer_pull(buf, 4 + strlen(org));
-    tlen += 4 + strlen(org);
-  }
-
-  if (country) {
-    silc_buffer_format(buf,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("C="),
-                      SILC_STR_UI32_STRING(country),
-                      SILC_STR_END);
-    silc_buffer_pull(buf, 4 + strlen(country));
-    tlen += 4 + strlen(country);
-  }
-
-  silc_buffer_push(buf, buf->data - buf->head);
-  identifier = silc_calloc(tlen + 1, sizeof(*identifier));
-  memcpy(identifier, buf->data, tlen);
-  silc_buffer_free(buf);
-
-  return identifier;
+  return public_key->pkcs->public_key_bitlen(public_key->public_key);
 }
 
-/* Decodes the provided `identifier' and returns allocated context for
-   the identifier. */
+/* Returns internal PKCS public key context */
 
-SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
+void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key)
 {
-  SilcPublicKeyIdentifier ident;
-  char *cp, *item;
-  int len;
-
-  ident = silc_calloc(1, sizeof(*ident));
-
-  cp = identifier;
-  while (cp) {
-    len = strcspn(cp, ",");
-    if (len < 1) {
-      cp = NULL;
-      break;
-    }
-    if (len - 1 >= 0 && cp[len - 1] == '\\') {
-      while (cp) {
-       if (len + 1 > strlen(cp)) {
-         cp = NULL;
-         break;
-       }
-       cp += len + 1;
-       len = strcspn(cp, ",") + len;
-       if (len < 1) {
-         cp = NULL;
-         break;
-       }
-       if (len - 1 >= 0 && cp[len - 1] != '\\')
-         break;
-      }
-    }
-
-    if (!cp)
-      break;
-
-    item = silc_calloc(len + 1, sizeof(char));
-    if (len > strlen(cp))
-      break;
-    memcpy(item, cp, len);
-
-    if (strstr(item, "UN="))
-      ident->username = strdup(item + strcspn(cp, "=") + 1);
-    else if (strstr(item, "HN="))
-      ident->host = strdup(item + strcspn(cp, "=") + 1);
-    else if (strstr(item, "RN="))
-      ident->realname = strdup(item + strcspn(cp, "=") + 1);
-    else if (strstr(item, "E="))
-      ident->email = strdup(item + strcspn(cp, "=") + 1);
-    else if (strstr(item, "O="))
-      ident->org = strdup(item + strcspn(cp, "=") + 1);
-    else if (strstr(item, "C="))
-      ident->country = strdup(item + strcspn(cp, "=") + 1);
-
-    cp += len;
-    if (strlen(cp) < 1)
-      cp = NULL;
-    else
-      cp += 1;
-
-    if (item)
-      silc_free(item);
-  }
-
-  return ident;
+  if (public_key->pkcs->type != type)
+    return FALSE;
+  return public_key->public_key;
 }
 
-/* Free's decoded public key identifier context. Call this to free the
-   context returned by the silc_pkcs_decode_identifier. */
 
-void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
-{
-  silc_free(identifier->username);
-  silc_free(identifier->host);
-  silc_free(identifier->realname);
-  silc_free(identifier->email);
-  silc_free(identifier->org);
-  silc_free(identifier->country);
-  silc_free(identifier);
-}
+/* Allocates new private key from key data */
 
-/* Allocates SILC style public key formed from sent arguments. All data
-   is duplicated. */
-
-SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
-                                        const char *identifier,
-                                        const unsigned char *pk,
-                                        SilcUInt32 pk_len)
+SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
+                                    unsigned char *key,
+                                    SilcUInt32 key_len,
+                                    SilcPrivateKey *ret_private_key)
 {
-  SilcPublicKey public_key;
-  char *tmp = NULL;
-
-  public_key = silc_calloc(1, sizeof(*public_key));
-  public_key->name = strdup(name);
-  public_key->pk_len = pk_len;
-  public_key->pk = silc_memdup(pk, pk_len);
-  public_key->pk_type = SILC_SKE_PK_TYPE_SILC;
-
-  if (!silc_utf8_valid(identifier, strlen(identifier))) {
-    int len = silc_utf8_encoded_len(identifier, strlen(identifier), 0);
-    tmp = silc_calloc(len + 1, sizeof(*tmp));
-    silc_utf8_encode(identifier, strlen(identifier), 0, tmp, len);
-    identifier = tmp;
-  }
-
-  public_key->identifier = strdup(identifier);
-  public_key->len = 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
-  silc_free(tmp);
+  const SilcPKCSObject *pkcs;
+  SilcPrivateKey private_key;
 
-  return public_key;
-}
+  if (!ret_private_key)
+    return FALSE;
 
-/* Free's public key */
+  /* Allocate private key context */
+  private_key = silc_calloc(1, sizeof(*private_key));
+  if (!private_key)
+    return FALSE;
 
-void silc_pkcs_public_key_free(SilcPublicKey public_key)
-{
-  if (public_key) {
-    silc_free(public_key->name);
-    silc_free(public_key->identifier);
-    silc_free(public_key->pk);
-    silc_free(public_key);
+  private_key->pkcs = pkcs = silc_pkcs_find_pkcs(type);
+  if (!private_key->pkcs) {
+    silc_free(private_key);
+    return FALSE;
   }
-}
 
-/* Allocates SILC private key formed from sent arguments. All data is
-   duplicated. */
-
-SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
-                                          const unsigned char *prv,
-                                          SilcUInt32 prv_len)
-{
-  SilcPrivateKey private_key;
+  /* Import the PKCS private key */
+  if (!pkcs->import_private_key(key, key_len, &private_key->private_key)) {
+    silc_free(private_key);
+    return FALSE;
+  }
 
-  private_key = silc_calloc(1, sizeof(*private_key));
-  private_key->name = strdup(name);
-  private_key->prv_len = prv_len;
-  private_key->prv = silc_memdup(prv, prv_len);
+  *ret_private_key = private_key;
 
-  return private_key;
+  return TRUE;
 }
 
-/* Free's private key */
+/* Return key length */
 
-void silc_pkcs_private_key_free(SilcPrivateKey private_key)
+SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key)
 {
-  if (private_key) {
-    silc_free(private_key->name);
-    if (private_key->prv) {
-      memset(private_key->prv, 0, private_key->prv_len);
-      silc_free(private_key->prv);
-    }
-    silc_free(private_key);
-  }
+  return private_key->pkcs->private_key_bitlen(private_key->private_key);
 }
 
-/* Encodes SILC style public key from SilcPublicKey. Returns the encoded
-   data. */
+/* Frees the private key */
 
-unsigned char *
-silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
+void silc_pkcs_private_key_free(SilcPrivateKey private_key)
 {
-  return silc_pkcs_public_key_data_encode(public_key->pk,
-                                         public_key->pk_len,
-                                         public_key->name,
-                                         public_key->identifier, len);
+  private_key->pkcs->private_key_free(private_key->private_key);
 }
 
-/* Encodes SILC style public key. Returns the encoded data. */
+/* Encrypts */
 
-unsigned char *
-silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
-                                char *pkcs, char *identifier,
-                                SilcUInt32 *len)
+SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
+                          unsigned char *src, SilcUInt32 src_len,
+                          unsigned char *dst, SilcUInt32 dst_size,
+                          SilcUInt32 *dst_len)
 {
-  SilcBuffer buf;
-  unsigned char *ret;
-  SilcUInt32 totlen;
-
-  totlen = 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
-  buf = silc_buffer_alloc_size(totlen + 4);
-  if (!buf)
-    return NULL;
-
-  silc_buffer_format(buf,
-                    SILC_STR_UI_INT(totlen),
-                    SILC_STR_UI_SHORT(strlen(pkcs)),
-                    SILC_STR_UI32_STRING(pkcs),
-                    SILC_STR_UI_SHORT(strlen(identifier)),
-                    SILC_STR_UI32_STRING(identifier),
-                    SILC_STR_UI_XNSTRING(pk, pk_len),
-                    SILC_STR_END);
-
-  ret = silc_buffer_steal(buf, len);
-  silc_buffer_free(buf);
-  return ret;
+  return public_key->pkcs->encrypt(public_key->public_key, src, src_len,
+                                  dst, dst_size, dst_len);
 }
 
-/* Decodes SILC style public key. Returns TRUE if the decoding was
-   successful. Allocates new public key as well. */
+/* Decrypts */
 
-SilcBool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
-                                SilcPublicKey *public_key)
+SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
+                          unsigned char *src, SilcUInt32 src_len,
+                          unsigned char *dst, SilcUInt32 dst_size,
+                          SilcUInt32 *dst_len)
 {
-  SilcBufferStruct buf;
-  SilcPKCS alg;
-  SilcUInt16 pkcs_len, identifier_len;
-  SilcUInt32 totlen, key_len;
-  unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
-  int ret;
-
-  silc_buffer_set(&buf, data, data_len);
-
-  /* Get length */
-  ret = silc_buffer_unformat(&buf,
-                            SILC_STR_UI_INT(&totlen),
-                            SILC_STR_END);
-  if (ret == -1)
-    return FALSE;
-
-#if 1 /* Backwards support, remove! */
-  if (totlen == data_len)
-    totlen -= 4;
-#endif
-
-  if (totlen + 4 != data_len)
-    return FALSE;
-
-  /* Get algorithm name and identifier */
-  silc_buffer_pull(&buf, 4);
-  ret =
-    silc_buffer_unformat(&buf,
-                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
-                        SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
-                        SILC_STR_END);
-  if (ret == -1)
-    goto err;
-
-  if (pkcs_len < 1 || identifier_len < 3 ||
-      pkcs_len + identifier_len > totlen)
-    goto err;
-
-  /* See if we support this algorithm (check only if PKCS are registered) */
-  if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
-    SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
-    goto err;
-  }
-
-  /* Protocol says that at least UN and HN must be provided as identifier,
-     check for these. */
-  if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
-    SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
-                   "identifiers"));
-    goto err;
-  }
-
-  /* Get key data. We assume that rest of the buffer is key data. */
-  silc_buffer_pull(&buf, 2 + pkcs_len + 2 + identifier_len);
-  key_len = silc_buffer_len(&buf);
-  ret = silc_buffer_unformat(&buf,
-                            SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
-                            SILC_STR_END);
-  if (ret == -1)
-    goto err;
-
-  /* Try to set the key. If this fails the key must be malformed. This
-     code assumes that the PKCS routine checks the format of the key.
-     (check only if PKCS are registered) */
-  if (SILC_PKCS_LIST) {
-    silc_pkcs_alloc(pkcs_name, SILC_PKCS_SILC, &alg);
-    if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
-      goto err;
-    silc_pkcs_free(alg);
-  }
-
-  if (public_key) {
-    *public_key = silc_calloc(1, sizeof(**public_key));
-    (*public_key)->len = totlen;
-    (*public_key)->name = pkcs_name;
-    (*public_key)->identifier = ident;
-    (*public_key)->pk = key_data;
-    (*public_key)->pk_len = key_len;
-    (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
-  }
-
-  return TRUE;
-
- err:
-  silc_free(pkcs_name);
-  silc_free(ident);
-  silc_free(key_data);
-  return FALSE;
+  return private_key->pkcs->decrypt(private_key->private_key, src, src_len,
+                                   dst, dst_size, dst_len);
 }
 
-/* Encodes Public Key Payload for transmitting public keys and certificates. */
+/* Generates signature */
 
-SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key)
+SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
+                       unsigned char *src, SilcUInt32 src_len,
+                       unsigned char *dst, SilcUInt32 dst_size,
+                       SilcUInt32 *dst_len, SilcHash hash)
 {
-  SilcBuffer buffer;
-  unsigned char *pk;
-  SilcUInt32 pk_len;
-
-  if (!public_key)
-    return NULL;
-
-  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
-  if (!pk)
-    return NULL;
-
-  buffer = silc_buffer_alloc_size(4 + pk_len);
-  if (!buffer) {
-    silc_free(pk);
-    return NULL;
-  }
-
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_SHORT(pk_len),
-                    SILC_STR_UI_SHORT(public_key->pk_type),
-                    SILC_STR_UI_XNSTRING(pk, pk_len),
-                    SILC_STR_END);
-
-  silc_free(pk);
-  return buffer;
+  return private_key->pkcs->sign(private_key->private_key, src, src_len,
+                                dst, dst_size, dst_len, hash);
 }
 
-/* Decode Public Key Payload and decodes the public key inside it to
-   to `payload'. */
+/* Verifies signature */
 
-SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data,
-                                        SilcUInt32 data_len,
-                                        SilcPublicKey *public_key)
+SilcBool silc_pkcs_verify(SilcPublicKey public_key,
+                         unsigned char *signature,
+                         SilcUInt32 signature_len,
+                         unsigned char *data,
+                         SilcUInt32 data_len, SilcHash hash)
 {
-  SilcBufferStruct buf;
-  SilcUInt16 pk_len, pk_type;
-  unsigned char *pk;
-  int ret;
-
-  if (!public_key)
-    return FALSE;
-
-  silc_buffer_set(&buf, data, data_len);
-  ret = silc_buffer_unformat(&buf,
-                            SILC_STR_UI_SHORT(&pk_len),
-                            SILC_STR_UI_SHORT(&pk_type),
-                            SILC_STR_END);
-  if (ret < 0 || pk_len > data_len - 4)
-    return FALSE;
-
-  /* For now we support only SILC public keys */
-  if (pk_type != SILC_SKE_PK_TYPE_SILC)
-    return FALSE;
-
-  silc_buffer_pull(&buf, 4);
-  ret = silc_buffer_unformat(&buf,
-                            SILC_STR_UI_XNSTRING(&pk, pk_len),
-                            SILC_STR_END);
-  silc_buffer_push(&buf, 4);
-  if (ret < 0)
-    return FALSE;
-
-  if (!silc_pkcs_public_key_decode(pk, pk_len, public_key))
-    return FALSE;
-  (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC;
-
-  return TRUE;
+  return public_key->pkcs->verify(public_key->public_key, signature,
+                                 signature_len, data, data_len, hash);
 }
 
 /* Compares two public keys and returns TRUE if they are same key, and
@@ -920,18 +613,10 @@ SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data,
 
 SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
 {
-  if (key1 == key2)
-    return TRUE;
-
-  if (key1->len == key2->len &&
-      key1->name && key2->name && key1->identifier && key2->identifier &&
-      !strcmp(key1->name, key2->name) &&
-      !strcmp(key1->identifier, key2->identifier) &&
-      !memcmp(key1->pk, key2->pk, key1->pk_len) &&
-      key1->pk_len == key2->pk_len)
-    return TRUE;
+  if (key1->pkcs->type != key2->pkcs->type)
+    return FALSE;
 
-  return FALSE;
+  return key1->pkcs->public_key_compare(key1->public_key, key2->public_key);
 }
 
 /* Copies the public key indicated by `public_key' and returns new allocated
@@ -943,604 +628,169 @@ SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
   if (!key)
     return NULL;
 
-  key->len = public_key->len;
-  key->name = silc_memdup(public_key->name, strlen(public_key->name));
-  key->identifier = silc_memdup(public_key->identifier,
-                               strlen(public_key->identifier));
-  key->pk = silc_memdup(public_key->pk, public_key->pk_len);
-  key->pk_len = public_key->pk_len;
-  key->pk_type = public_key->pk_type;
+  key->pkcs = public_key->pkcs;
+  key->public_key = public_key->pkcs->public_key_copy(public_key->public_key);
+  if (!key->public_key) {
+    silc_free(key);
+    return NULL;
+  }
 
   return key;
 }
 
-/* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
-
-unsigned char *
-silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
-{
-  return silc_pkcs_private_key_data_encode(private_key->prv,
-                                          private_key->prv_len,
-                                          private_key->name, len);
-}
-
-/* Encodes SILC private key. Returns the encoded data. */
+/* Loads any kind of public key */
 
-unsigned char *
-silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
-                                 char *pkcs, SilcUInt32 *len)
+SilcBool silc_pkcs_load_public_key(const char *filename,
+                                  SilcPublicKey *ret_public_key)
 {
-  SilcBuffer buf;
-  unsigned char *ret;
-  SilcUInt32 totlen;
-
-  totlen = 2 + strlen(pkcs) + prv_len;
-  buf = silc_buffer_alloc_size(totlen);
-  if (!buf)
-    return NULL;
-
-  silc_buffer_format(buf,
-                    SILC_STR_UI_SHORT(strlen(pkcs)),
-                    SILC_STR_UI32_STRING(pkcs),
-                    SILC_STR_UI_XNSTRING(prv, prv_len),
-                    SILC_STR_END);
+  unsigned char *data;
+  SilcUInt32 data_len;
+  SilcPublicKey public_key;
+  SilcPKCSType type;
 
-  ret = silc_buffer_steal(buf, len);
-  silc_buffer_free(buf);
-  return ret;
-}
+  SILC_LOG_DEBUG(("Loading public key file '%s'", filename));
 
-/* Decodes SILC style private key. Returns TRUE if the decoding was
-   successful. Allocates new private key as well. */
+  if (!ret_public_key)
+    return FALSE;
 
-SilcBool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
-                                 SilcPrivateKey *private_key)
-{
-  SilcBufferStruct buf;
-  SilcPKCS alg;
-  SilcUInt16 pkcs_len;
-  SilcUInt32 key_len;
-  unsigned char *pkcs_name = NULL, *key_data = NULL;
-  int ret;
-
-  silc_buffer_set(&buf, data, data_len);
-
-  /* Get algorithm name and identifier */
-  ret =
-    silc_buffer_unformat(&buf,
-                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
-                        SILC_STR_END);
-  if (ret == -1) {
-    SILC_LOG_DEBUG(("Cannot decode private key buffer"));
-    goto err;
-  }
+  data = silc_file_readfile(filename, &data_len);
+  if (!data)
+    return FALSE;
 
-  if (pkcs_len < 1 || pkcs_len > silc_buffer_truelen(&buf)) {
-    SILC_LOG_DEBUG(("Malformed private key buffer"));
-    goto err;
+  /* Allocate public key context */
+  *ret_public_key = public_key = silc_calloc(1, sizeof(*public_key));
+  if (!public_key) {
+    silc_free(data);
+    return FALSE;
   }
 
-  /* See if we support this algorithm (check only if PKCS are registered). */
-  if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
-    SILC_LOG_DEBUG(("Unknown PKCS `%s'", pkcs_name));
-    goto err;
-  }
+  /* Try loading all types until one succeeds. */
+  for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
+    public_key->pkcs = silc_pkcs_find_pkcs(type);
+    if (!public_key->pkcs)
+      continue;
 
-  /* Get key data. We assume that rest of the buffer is key data. */
-  silc_buffer_pull(&buf, 2 + pkcs_len);
-  key_len = silc_buffer_len(&buf);
-  ret = silc_buffer_unformat(&buf,
-                            SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
-                            SILC_STR_END);
-  if (ret == -1)
-    goto err;
-
-  /* Try to set the key. If this fails the key must be malformed. This
-     code assumes that the PKCS routine checks the format of the key.
-     (check only if PKCS are registered) */
-  if (SILC_PKCS_LIST) {
-    silc_pkcs_alloc(pkcs_name, SILC_PKCS_SILC, &alg);
-    if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
-      SILC_LOG_DEBUG(("Could not set private key data"));
-      goto err;
-    }
-    silc_pkcs_free(alg);
-  }
+    if (public_key->pkcs->import_public_key_file(data, data_len,
+                                                SILC_PKCS_FILE_BASE64,
+                                                &public_key->public_key))
+      return TRUE;
 
-  if (private_key) {
-    *private_key = silc_calloc(1, sizeof(**private_key));
-    (*private_key)->name = pkcs_name;
-    (*private_key)->prv = key_data;
-    (*private_key)->prv_len = key_len;
+    if (public_key->pkcs->import_public_key_file(data, data_len,
+                                                SILC_PKCS_FILE_BIN,
+                                                &public_key->public_key))
+      return TRUE;
   }
 
-  return TRUE;
-
- err:
-  silc_free(pkcs_name);
-  silc_free(key_data);
+  silc_free(data);
+  silc_free(public_key);
   return FALSE;
 }
 
-/* Internal routine to save public key */
+/* Saves public key into a file */
 
-static SilcBool silc_pkcs_save_public_key_internal(const char *filename,
-                                              unsigned char *data,
-                                              SilcUInt32 data_len,
-                                              SilcUInt32 encoding)
+SilcBool silc_pkcs_save_public_key(const char *filename,
+                                  SilcPublicKey public_key,
+                                  SilcPKCSFileEncoding encoding)
 {
-  SilcBuffer buf;
-  SilcUInt32 len;
-  unsigned char *tmp = NULL;
-
-  switch(encoding) {
-  case SILC_PKCS_FILE_BIN:
-    break;
-  case SILC_PKCS_FILE_PEM:
-    tmp = data = silc_pem_encode_file(data, data_len);
-    data_len = strlen(data);
-    break;
-  }
+  unsigned char *data;
+  SilcUInt32 data_len;
 
-  len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
-                   strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
-  buf = silc_buffer_alloc_size(len);
-  if (!buf) {
-    silc_free(tmp);
+  /* Export the public key file */
+  data = public_key->pkcs->export_public_key_file(public_key->public_key,
+                                                 encoding, &data_len);
+  if (!data)
     return FALSE;
-  }
-
-  silc_buffer_format(buf,
-                    SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
-                    SILC_STR_UI_XNSTRING(data, data_len),
-                    SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
-                    SILC_STR_END);
 
-  /* Save into file */
-  if (silc_file_writefile(filename, buf->data, silc_buffer_len(buf))) {
-    silc_free(tmp);
-    silc_buffer_free(buf);
+  /* Write to file */
+  if (silc_file_writefile(filename, data, data_len)) {
+    silc_free(data);
     return FALSE;
   }
 
-  silc_free(tmp);
-  silc_buffer_free(buf);
+  silc_free(data);
   return TRUE;
 }
 
-/* Saves public key into file */
+/* Loads any kind of private key */
 
-SilcBool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key,
-                              SilcUInt32 encoding)
+SilcBool silc_pkcs_load_private_key(const char *filename,
+                                   const unsigned char *passphrase,
+                                   SilcUInt32 passphrase_len,
+                                   SilcPrivateKey *ret_private_key)
 {
   unsigned char *data;
   SilcUInt32 data_len;
-  SilcBool ret;
-
-  data = silc_pkcs_public_key_encode(public_key, &data_len);
-  ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
-                                          encoding);
-  silc_free(data);
-  return ret;
-}
-
-/* Saves public key into file */
-
-SilcBool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data,
-                                   SilcUInt32 data_len, SilcUInt32 encoding)
-{
-  return silc_pkcs_save_public_key_internal(filename, data, data_len,
-                                           encoding);
-}
-
-#define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
-
-/* Internal routine to save private key. */
-
-static SilcBool silc_pkcs_save_private_key_internal(const char *filename,
-                                               unsigned char *data,
-                                               SilcUInt32 data_len,
-                                               unsigned char *key,
-                                               SilcUInt32 key_len,
-                                               SilcUInt32 encoding)
-{
-  SilcCipher aes;
-  SilcHash sha1;
-  SilcHmac sha1hmac;
-  SilcBuffer buf, enc;
-  SilcUInt32 len, blocklen, padlen;
-  unsigned char tmp[32], keymat[64];
-  int i;
+  SilcPrivateKey private_key;
+  SilcPKCSType type;
 
-  memset(tmp, 0, sizeof(tmp));
-  memset(keymat, 0, sizeof(keymat));
+  SILC_LOG_DEBUG(("Loading private key file '%s'", filename));
 
-  /* Allocate the AES cipher */
-  if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
-    SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
-    return FALSE;
-  }
-  blocklen = silc_cipher_get_block_len(aes);
-  if (blocklen * 2 > sizeof(tmp))
+  if (!ret_private_key)
     return FALSE;
 
-  /* Allocate SHA1 hash */
-  if (!silc_hash_alloc("sha1", &sha1)) {
-    SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
-    silc_cipher_free(aes);
+  data = silc_file_readfile(filename, &data_len);
+  if (!data)
     return FALSE;
-  }
 
-  /* Allocate HMAC */
-  if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
-    SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
-    silc_hash_free(sha1);
-    silc_cipher_free(aes);
+  /* Allocate private key context */
+  *ret_private_key = private_key = silc_calloc(1, sizeof(*private_key));
+  if (!private_key) {
+    silc_free(data);
     return FALSE;
   }
 
-  /* Derive the encryption key from the provided key material.  The key
-     is 256 bits length, and derived by taking hash of the data, then
-     re-hashing the data and the previous digest, and using the first and
-     second digest as the key. */
-  silc_hash_init(sha1);
-  silc_hash_update(sha1, key, key_len);
-  silc_hash_final(sha1, keymat);
-  silc_hash_init(sha1);
-  silc_hash_update(sha1, key, key_len);
-  silc_hash_update(sha1, keymat, 16);
-  silc_hash_final(sha1, keymat + 16);
-
-  /* Set the key to the cipher */
-  silc_cipher_set_key(aes, keymat, 256);
-
-  /* Encode the buffer to be encrypted.  Add padding to it too, at least
-     block size of the cipher. */
-
-  /* Allocate buffer for encryption */
-  len = silc_hmac_len(sha1hmac);
-  padlen = 16 + (16 - ((data_len + 4) % blocklen));
-  enc = silc_buffer_alloc_size(4 + 4 + data_len + padlen + len);
-  if (!enc) {
-    silc_hmac_free(sha1hmac);
-    silc_hash_free(sha1);
-    silc_cipher_free(aes);
-    return FALSE;
-  }
+  /* Try loading all types until one succeeds. */
+  for (type = SILC_PKCS_SILC; type <= SILC_PKCS_SPKI; type++) {
+    private_key->pkcs = silc_pkcs_find_pkcs(type);
+    if (!private_key->pkcs)
+      continue;
 
-  /* Generate padding */
-  for (i = 0; i < padlen; i++)
-    tmp[i] = silc_rng_global_get_byte_fast();
-
-  /* Put magic number */
-  SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
-  silc_buffer_pull(enc, 4);
-
-  /* Encode the buffer */
-  silc_buffer_format(enc,
-                    SILC_STR_UI_INT(data_len),
-                    SILC_STR_UI_XNSTRING(data, data_len),
-                    SILC_STR_UI_XNSTRING(tmp, padlen),
-                    SILC_STR_END);
-
-  /* Encrypt. */
-  silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
-                     silc_cipher_get_iv(aes));
-
-  silc_buffer_push(enc, 4);
-
-  /* Compute HMAC over the encrypted data and append the MAC to data.
-     The key is the first digest of the original key material. */
-  data_len = silc_buffer_len(enc) - len;
-  silc_hmac_init_with_key(sha1hmac, keymat, 16);
-  silc_hmac_update(sha1hmac, enc->data, data_len);
-  silc_buffer_pull(enc, data_len);
-  silc_hmac_final(sha1hmac, enc->data, NULL);
-  silc_buffer_push(enc, data_len);
-
-  /* Cleanup */
-  memset(keymat, 0, sizeof(keymat));
-  memset(tmp, 0, sizeof(tmp));
-  silc_hmac_free(sha1hmac);
-  silc_hash_free(sha1);
-  silc_cipher_free(aes);
-
-  data = enc->data;
-  data_len = silc_buffer_len(enc);
-
-  switch (encoding) {
-  case SILC_PKCS_FILE_BIN:
-    break;
-  case SILC_PKCS_FILE_PEM:
-    data = silc_pem_encode_file(data, data_len);
-    data_len = strlen(data);
-    break;
-  }
+    if (private_key->pkcs->import_private_key_file(data, data_len,
+                                                  passphrase,
+                                                  passphrase_len,
+                                                  SILC_PKCS_FILE_BIN,
+                                                  &private_key->private_key))
+      return TRUE;
 
-  /* Encode the data and save to file */
-  len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
-                   strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
-  buf = silc_buffer_alloc_size(len);
-  silc_buffer_format(buf,
-                    SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
-                    SILC_STR_UI_XNSTRING(data, data_len),
-                    SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
-                    SILC_STR_END);
-
-  /* Save into a file */
-  if (silc_file_writefile_mode(filename, buf->data,
-                              silc_buffer_len(buf), 0600)) {
-    silc_buffer_clear(buf);
-    silc_buffer_free(buf);
-    silc_buffer_clear(enc);
-    silc_buffer_free(enc);
-    return FALSE;
+    if (private_key->pkcs->import_private_key_file(data, data_len,
+                                                  passphrase,
+                                                  passphrase_len,
+                                                  SILC_PKCS_FILE_BASE64,
+                                                  &private_key->private_key))
+      return TRUE;
   }
 
-  silc_buffer_clear(buf);
-  silc_buffer_free(buf);
-  silc_buffer_clear(enc);
-  silc_buffer_free(enc);
-  return TRUE;
+  silc_free(data);
+  silc_free(private_key);
+  return FALSE;
 }
 
-/* Saves private key into file. */
+/* Saves private key into a file */
 
 SilcBool silc_pkcs_save_private_key(const char *filename,
-                               SilcPrivateKey private_key,
-                               unsigned char *passphrase,
-                               SilcUInt32 passphrase_len,
-                               SilcUInt32 encoding)
+                                   SilcPrivateKey private_key,
+                                   const unsigned char *passphrase,
+                                   SilcUInt32 passphrase_len,
+                                   SilcPKCSFileEncoding encoding,
+                                   SilcRng rng)
 {
   unsigned char *data;
   SilcUInt32 data_len;
-  SilcBool ret;
-
-  data = silc_pkcs_private_key_encode(private_key, &data_len);
-  ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
-                                           passphrase, passphrase_len,
-                                           encoding);
-  memset(data, 0, data_len);
-  silc_free(data);
-  return ret;
-}
-
-/* Loads public key from file and allocates new public key. Returns TRUE
-   if loading was successful. */
-
-SilcBool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
-                              SilcUInt32 encoding)
-{
-  unsigned char *cp, *old, *data, byte;
-  SilcUInt32 i, data_len, len;
-
-  SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename,
-                 encoding == SILC_PKCS_FILE_PEM ? "Base64" :
-                 encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
 
-  old = data = silc_file_readfile(filename, &data_len);
+  /* Export the private key file */
+  data = private_key->pkcs->export_private_key_file(private_key->private_key,
+                                                   passphrase,
+                                                   passphrase_len,
+                                                   encoding, rng, &data_len);
   if (!data)
     return FALSE;
 
-  /* Check start of file and remove header from the data. */
-  len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
-  cp = data;
-  for (i = 0; i < len; i++) {
-    byte = cp[0];
-    cp++;
-    if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
-      memset(old, 0, data_len);
-      silc_free(old);
-      return FALSE;
-    }
-  }
-  data = cp;
-
-  /* Decode public key */
-  if (public_key) {
-    len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
-                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
-
-    switch(encoding) {
-    case SILC_PKCS_FILE_BIN:
-      break;
-    case SILC_PKCS_FILE_PEM:
-      data = silc_pem_decode(data, len, &len);
-      memset(old, 0, data_len);
-      silc_free(old);
-      old = data;
-      data_len = len;
-      break;
-    }
-
-    if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
-      memset(old, 0, data_len);
-      silc_free(old);
-      return FALSE;
-    }
-  }
-
-  memset(old, 0, data_len);
-  silc_free(old);
-  return TRUE;
-}
-
-/* Load private key from file and allocates new private key. Returns TRUE
-   if loading was successful. */
-
-SilcBool silc_pkcs_load_private_key(const char *filename,
-                               SilcPrivateKey *private_key,
-                               unsigned char *passphrase,
-                               SilcUInt32 passphrase_len,
-                               SilcUInt32 encoding)
-{
-  SilcCipher aes;
-  SilcHash sha1;
-  SilcHmac sha1hmac;
-  SilcUInt32 blocklen;
-  unsigned char tmp[32], keymat[64];
-  unsigned char *cp, *old, *data, byte;
-  SilcUInt32 i, data_len, len, magic, mac_len;
-
-  SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename,
-                 encoding == SILC_PKCS_FILE_PEM ? "Base64" :
-                 encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
-
-  old = data = silc_file_readfile(filename, &data_len);
-  if (!data)
+  /* Write to file */
+  if (silc_file_writefile(filename, data, data_len)) {
+    silc_free(data);
     return FALSE;
-
-  /* Check start of file and remove header from the data. */
-  len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
-  cp = data;
-  for (i = 0; i < len; i++) {
-    byte = cp[0];
-    cp++;
-    if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
-      memset(old, 0, data_len);
-      silc_free(old);
-      return FALSE;
-    }
-  }
-  data = cp;
-
-  /* Decode private key */
-  len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
-                   strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
-
-  switch(encoding) {
-  case SILC_PKCS_FILE_BIN:
-    break;
-  case SILC_PKCS_FILE_PEM:
-    data = silc_pem_decode(data, len, &len);
-    if (!data) {
-      memset(old, 0, data_len);
-      silc_free(old);
-      return FALSE;
-    }
-    break;
   }
 
-  memset(tmp, 0, sizeof(tmp));
-  memset(keymat, 0, sizeof(keymat));
-
-  /* Private key files without the specific magic number are assumed
-     to be the old-style private keys that are not encrypted. */
-  SILC_GET32_MSB(magic, data);
-  if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
-    SILC_LOG_DEBUG(("Private key does not have correct magic!"));
-
-    /* Now decode the actual private key */
-    if (!silc_pkcs_private_key_decode(data, len, private_key)) {
-      memset(old, 0, data_len);
-      silc_free(old);
-      return FALSE;
-    }
-
-    memset(old, 0, data_len);
-    silc_free(old);
-    return TRUE;
-  }
-
-  /* Allocate the AES cipher */
-  if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
-    SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
-    memset(old, 0, data_len);
-    silc_free(old);
-    return FALSE;
-  }
-  blocklen = silc_cipher_get_block_len(aes);
-  if (blocklen * 2 > sizeof(tmp)) {
-    memset(old, 0, data_len);
-    silc_free(old);
-    return FALSE;
-  }
-
-  /* Allocate SHA1 hash */
-  if (!silc_hash_alloc("sha1", &sha1)) {
-    SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
-    silc_cipher_free(aes);
-    memset(old, 0, data_len);
-    silc_free(old);
-    return FALSE;
-  }
-
-  /* Allocate HMAC */
-  if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
-    SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
-    silc_hash_free(sha1);
-    silc_cipher_free(aes);
-    memset(old, 0, data_len);
-    silc_free(old);
-    return FALSE;
-  }
-
-  /* Derive the decryption key from the provided key material.  The key
-     is 256 bits length, and derived by taking hash of the data, then
-     re-hashing the data and the previous digest, and using the first and
-     second digest as the key. */
-  silc_hash_init(sha1);
-  silc_hash_update(sha1, passphrase, passphrase_len);
-  silc_hash_final(sha1, keymat);
-  silc_hash_init(sha1);
-  silc_hash_update(sha1, passphrase, passphrase_len);
-  silc_hash_update(sha1, keymat, 16);
-  silc_hash_final(sha1, keymat + 16);
-
-  /* Set the key to the cipher */
-  silc_cipher_set_key(aes, keymat, 256);
-
-  /* First, verify the MAC of the private key data */
-  mac_len = silc_hmac_len(sha1hmac);
-  silc_hmac_init_with_key(sha1hmac, keymat, 16);
-  silc_hmac_update(sha1hmac, data, len - mac_len);
-  silc_hmac_final(sha1hmac, tmp, NULL);
-  if (memcmp(tmp, data + (len - mac_len), mac_len)) {
-    SILC_LOG_DEBUG(("Integrity check for private key failed"));
-    memset(keymat, 0, sizeof(keymat));
-    memset(tmp, 0, sizeof(tmp));
-    silc_hmac_free(sha1hmac);
-    silc_hash_free(sha1);
-    silc_cipher_free(aes);
-    memset(old, 0, data_len);
-    silc_free(old);
-    return FALSE;
-  }
-  data += 4;
-  len -= 4;
-
-  /* Decrypt the private key buffer */
-  silc_cipher_decrypt(aes, data, data, len - mac_len, NULL);
-  SILC_GET32_MSB(i, data);
-  if (i > len) {
-    SILC_LOG_DEBUG(("Bad private key length in buffer!"));
-    memset(keymat, 0, sizeof(keymat));
-    memset(tmp, 0, sizeof(tmp));
-    silc_hmac_free(sha1hmac);
-    silc_hash_free(sha1);
-    silc_cipher_free(aes);
-    memset(old, 0, data_len);
-    silc_free(old);
-    return FALSE;
-  }
-  data += 4;
-  len = i;
-
-  /* Cleanup */
-  memset(keymat, 0, sizeof(keymat));
-  memset(tmp, 0, sizeof(tmp));
-  silc_hmac_free(sha1hmac);
-  silc_hash_free(sha1);
-  silc_cipher_free(aes);
-
-  /* Now decode the actual private key */
-  if (!silc_pkcs_private_key_decode(data, len, private_key)) {
-    memset(old, 0, data_len);
-    silc_free(old);
-    return FALSE;
-  }
-
-  memset(old, 0, data_len);
-  silc_free(old);
+  silc_free(data);
   return TRUE;
 }
index eeaa240586c1a6878d280ba68fca094b2c778c68..b18747fbd1c28892e47d08d8ed485a988743901b 100644 (file)
 
 */
 
-#ifndef SILCPKCS_H
-#define SILCPKCS_H
-
 /****h* silccrypt/SILC PKCS Interface
  *
  * DESCRIPTION
  *
- *    This is the interface for public key cryptosystems, and various
- *    utility functions related to public keys and private keys.  This
- *    interface also defines the actual PKCS objects, public keys and
- *    private keys.  The interface is generic PKCS interface, which has
- *    capability of supporting any kind of public key algorithm.  This
- *    interface also implements the SILC Public Key and routines for
- *    encoding and decoding SILC Public Key (as defined by the SILC
- *    protocol specification).  Interface or encrypting, decrypting,
- *    producing digital signatures and verifying digital signatures are
- *    also defined in this header.
+ * SILC PKCS API provides generic interface for performing various
+ * public key cryptography related operations with different types of
+ * public and private keys.  Support for loading and saving of different
+ * types of public key and private keys are also provided.
  *
  ***/
 
-/****s* silccrypt/SilcPKCSAPI/SilcPKCS
- *
- * NAME
- *
- *    typedef struct SilcPKCSStruct *SilcPKCS;
- *
- * DESCRIPTION
- *
- *    This context is the actual PKCS context and is allocated
- *    by silc_pkcs_alloc and given as argument usually to all
- *    silc_pkcs_* functions.  It is freed by the silc_pkcs_free
- *    function.
- *
- ***/
-typedef struct SilcPKCSStruct *SilcPKCS;
+#ifndef SILCPKCS_H
+#define SILCPKCS_H
+
+/* Forward declarations */
+typedef struct SilcPKCSObjectStruct SilcPKCSObject;
 
 /****d* silccrypt/SilcPKCSAPI/SilcPKCSType
  *
  * NAME
  *
- *    typedef enum { ... } SilcPKCSType
+ *    typedef enum { ... } SilcPKCSType;
  *
  * DESCRIPTION
  *
@@ -67,7 +48,7 @@ typedef struct SilcPKCSStruct *SilcPKCS;
  * SOURCE
  */
 typedef enum {
-  SILC_PKCS_SILC    = 1,       /* SILC PKCS (mandatory) */
+  SILC_PKCS_SILC    = 1,       /* SILC PKCS */
   SILC_PKCS_SSH2    = 2,       /* SSH2 PKCS (not supported) */
   SILC_PKCS_X509V3  = 3,       /* X.509v3 PKCS (not supported) */
   SILC_PKCS_OPENPGP = 4,       /* OpenPGP PKCS (not supported) */
@@ -75,190 +56,242 @@ typedef enum {
 } SilcPKCSType;
 /***/
 
-/* The default SILC PKCS (Public Key Cryptosystem) object to represent
-   any PKCS in SILC. */
-typedef struct SilcPKCSObjectStruct {
-  char *name;
-  SilcPKCSType type;
-  int (*init)(void *, SilcUInt32, SilcRng);
-  void (*clear_keys)(void *);
-  unsigned char *(*get_public_key)(void *, SilcUInt32 *);
-  unsigned char *(*get_private_key)(void *, SilcUInt32 *);
-  SilcUInt32 (*set_public_key)(void *, unsigned char *, SilcUInt32);
-  SilcUInt32 (*set_private_key)(void *, unsigned char *, SilcUInt32);
-  SilcUInt32 (*context_len)();
-  int (*encrypt)(void *, unsigned char *, SilcUInt32,
-                unsigned char *, SilcUInt32 *);
-  int (*decrypt)(void *, unsigned char *, SilcUInt32,
-                unsigned char *, SilcUInt32 *);
-  int (*sign)(void *, unsigned char *, SilcUInt32,
-             unsigned char *, SilcUInt32 *);
-  int (*verify)(void *, unsigned char *, SilcUInt32,
-               unsigned char *, SilcUInt32);
-} SilcPKCSObject;
-
 /****s* silccrypt/SilcPKCSAPI/SilcPublicKey
  *
  * NAME
  *
- *    typedef struct { ... } *SilcPublicKey, SilcPublicKeyStruct;
+ *    typedef struct { ... } *SilcPublicKey;
  *
  * DESCRIPTION
  *
- *    SILC style public key object.  Public key is read from file to this
- *    object.  Public keys received from network must be in this format as
- *    well.  The format is defined by the SILC protocol specification.
- *    This object is allocated by silc_pkcs_public_key_alloc and freed
- *    by silc_pkcs_public_key_free.  The object is given as argument to
- *    all silc_pkcs_public_key_* functions.
+ *    This context represents any kind of PKCS public key.  It can be
+ *    allocated by silc_pkcs_public_key_alloc and is freed by the
+ *    silc_pkcs_public_key_free.  The PKCS specific public key context
+ *    can be retrieved by calling silc_pkcs_get_context.
  *
  * SOURCE
  */
 typedef struct {
-  SilcUInt16 pk_type;          /* Public key type (SilcSKEPKType) */
-  SilcUInt32 len;
-  char *name;
-  char *identifier;
-  unsigned char *pk;
-  SilcUInt32 pk_len;
-} *SilcPublicKey, SilcPublicKeyStruct;
+  const SilcPKCSObject *pkcs;  /* PKCS */
+  void *public_key;            /* PKCS specific public key */
+} *SilcPublicKey;
 /***/
 
-/****s* silccrypt/SilcPKCSAPI/SilcPublicKeyIdentifier
+/****s* silccrypt/SilcPKCSAPI/SilcPrivateKey
  *
  * NAME
  *
- *    typedef struct { ... } *SilcPublicKeyIdentifier,
- *                            SilcPublicKeyIdentifierStruct;
+ *    typedef struct { ... } *SilcPrivateKey;
  *
  * DESCRIPTION
  *
- *    Decoded SILC Public Key identifier.  Note that some of the fields
- *    may be NULL.  This context is allocated by the function
- *    silc_pkcs_decode_identifier and freed by silc_pkcs_free_identifier.
- *    The identifier in SilcPublicKey is the `identifier' field, which
- *    can be given as argument to silc_pkcs_decode_identifier.
+ *    This context represents any kind of PKCS private key.
  *
  * SOURCE
  */
 typedef struct {
-  char *username;
-  char *host;
-  char *realname;
-  char *email;
-  char *org;
-  char *country;
-} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct;
+  const SilcPKCSObject *pkcs;  /* PKCS */
+  void *private_key;           /* PKCS specific private key */
+} *SilcPrivateKey;
 /***/
 
-/****s* silccrypt/SilcPKCSAPI/SilcPrivateKey
+/****d* silccrypt/SilcPKCSAPI/SilcPKCSFileEncoding
  *
  * NAME
  *
- *    typedef struct { ... } *SilcPrivateKey, SilcPrivateKeyStruct;
+ *    typedef enum { ... } SilcPKCSType
  *
  * DESCRIPTION
  *
- *    SILC style private key object.  Public key is read from file to this
- *    object.  This object is allocated by silc_pkcs_private_key_alloc and
- *    freed by silc_pkcs_private_key_free.  The object is given as argument
- *    to all silc_pkcs_private_key_* functions.
+ *    Public and private key file encoding types.
  *
- ***/
+ * SOURCE
+ */
+typedef enum {
+  SILC_PKCS_FILE_BIN,          /* Binary encoding */
+  SILC_PKCS_FILE_BASE64                /* Base64 encoding */
+} SilcPKCSFileEncoding;
+/***/
+
+/* The PKCS Algorithm object to represent any PKCS algorithm. */
 typedef struct {
+  /* Algorithm name and scheme */
   char *name;
-  unsigned char *prv;
-  SilcUInt32 prv_len;
-} *SilcPrivateKey, SilcPrivateKeyStruct;
-
-/* Public and private key file headers */
-#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
-#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n"
-#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n"
-#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n"
+  char *scheme;
+
+  /* Supported hash functions, comma separated list */
+  char *hash;
+
+  /* Generate new key pair. Returns PKCS algorithm specific public key
+     and private key contexts. */
+  SilcBool (*generate_key)(SilcUInt32 keylen,
+                          SilcRng rng,
+                          void **ret_public_key,
+                          void **ret_private_key);
+
+  /* Public key routines */
+  SilcBool (*import_public_key)(unsigned char *key,
+                               SilcUInt32 key_len,
+                               void **ret_public_key);
+  unsigned char *(*export_public_key)(void *public_key,
+                                     SilcUInt32 *ret_len);
+  SilcUInt32 (*public_key_bitlen)(void *public_key);
+  void *(*public_key_copy)(void *public_key);
+  SilcBool (*public_key_compare)(void *key1, void *key2);
+  void (*public_key_free)(void *public_key);
+
+  /* Private key routines */
+  SilcBool (*import_private_key)(unsigned char *key,
+                                SilcUInt32 key_len,
+                                void **ret_private_key);
+  unsigned char *(*export_private_key)(void *private_key,
+                                      SilcUInt32 *ret_len);
+  SilcUInt32 (*private_key_bitlen)(void *public_key);
+  void (*private_key_free)(void *private_key);
+
+  /* Encrypt and decrypt operations */
+  SilcBool (*encrypt)(void *public_key,
+                     unsigned char *src,
+                     SilcUInt32 src_len,
+                     unsigned char *dst,
+                     SilcUInt32 dst_size,
+                     SilcUInt32 *ret_dst_len);
+  SilcBool (*decrypt)(void *private_key,
+                     unsigned char *src,
+                     SilcUInt32 src_len,
+                     unsigned char *dst,
+                     SilcUInt32 dst_size,
+                     SilcUInt32 *ret_dst_len);
+
+  /* Signature and verification operations */
+  SilcBool (*sign)(void *private_key,
+                  unsigned char *src,
+                  SilcUInt32 src_len,
+                  unsigned char *signature,
+                  SilcUInt32 signature_size,
+                  SilcUInt32 *ret_signature_len,
+                  SilcHash hash);
+  SilcBool (*verify)(void *public_key,
+                    unsigned char *signature,
+                    SilcUInt32 signature_len,
+                    unsigned char *data,
+                    SilcUInt32 data_len,
+                    SilcHash hash);
+} SilcPKCSAlgorithm;
+
+/* The PKCS (Public Key Cryptosystem) object to represent any PKCS. */
+struct SilcPKCSObjectStruct {
+  /* PKCS type */
+  SilcPKCSType type;
 
-/* Public and private key file encoding types */
-#define SILC_PKCS_FILE_BIN 0
-#define SILC_PKCS_FILE_PEM 1
+  /* Public key routines */
+
+  /* Returns PKCS algorithm context from public key */
+  const SilcPKCSAlgorithm *(*get_algorithm)(void *public_key);
+
+  /* Imports from public key file */
+  SilcBool (*import_public_key_file)(unsigned char *filedata,
+                                    SilcUInt32 filedata_len,
+                                    SilcPKCSFileEncoding encoding,
+                                    void **ret_public_key);
+
+  /* Imports from public key binary data */
+  SilcBool (*import_public_key)(unsigned char *key,
+                               SilcUInt32 key_len,
+                               void **ret_public_key);
+
+  /* Exports public key to file */
+  unsigned char *(*export_public_key_file)(void *public_key,
+                                          SilcPKCSFileEncoding encoding,
+                                          SilcUInt32 *ret_len);
+
+  /* Export public key as binary data */
+  unsigned char *(*export_public_key)(void *public_key,
+                                     SilcUInt32 *ret_len);
+
+  /* Returns key length in bits */
+  SilcUInt32 (*public_key_bitlen)(void *public_key);
+
+  /* Copy public key */
+  void *(*public_key_copy)(void *public_key);
+
+  /* Compares public keys */
+  SilcBool (*public_key_compare)(void *key1, void *key2);
+
+  /* Free public key */
+  void (*public_key_free)(void *public_key);
+
+  /* Private key routines */
+
+  /* Imports from private key file */
+  SilcBool (*import_private_key_file)(unsigned char *filedata,
+                                     SilcUInt32 filedata_len,
+                                     const char *passphrase,
+                                     SilcUInt32 passphrase_len,
+                                     SilcPKCSFileEncoding encoding,
+                                     void **ret_private_key);
+
+  /* Imports from private key binary data */
+  SilcBool (*import_private_key)(unsigned char *key,
+                                SilcUInt32 key_len,
+                                void **ret_private_key);
+
+  /* Exports private key to file */
+  unsigned char *(*export_private_key_file)(void *private_key,
+                                           const char *passphrase,
+                                           SilcUInt32 passphrase_len,
+                                           SilcPKCSFileEncoding encoding,
+                                           SilcRng rng,
+                                           SilcUInt32 *ret_len);
+
+  /* Export private key as binary data */
+  unsigned char *(*export_private_key)(void *private_key,
+                                      SilcUInt32 *ret_len);
+
+  /* Returns key length in bits */
+  SilcUInt32 (*private_key_bitlen)(void *private_key);
+
+  /* Free private key */
+  void (*private_key_free)(void *private_key);
+
+  /* Encrypt and decrypt operations */
+  SilcBool (*encrypt)(void *public_key,
+                     unsigned char *src,
+                     SilcUInt32 src_len,
+                     unsigned char *dst,
+                     SilcUInt32 dst_size,
+                     SilcUInt32 *ret_dst_len);
+  SilcBool (*decrypt)(void *private_key,
+                     unsigned char *src,
+                     SilcUInt32 src_len,
+                     unsigned char *dst,
+                     SilcUInt32 dst_size,
+                     SilcUInt32 *ret_dst_len);
+
+  /* Signature and verification operations */
+  SilcBool (*sign)(void *private_key,
+                  unsigned char *src,
+                  SilcUInt32 src_len,
+                  unsigned char *signature,
+                  SilcUInt32 signature_size,
+                  SilcUInt32 *ret_signature_len,
+                  SilcHash hash);
+  SilcBool (*verify)(void *public_key,
+                    unsigned char *signature,
+                    SilcUInt32 signature_len,
+                    unsigned char *data,
+                    SilcUInt32 data_len,
+                    SilcHash hash);
+};
 
 /* Marks for all PKCS in silc. This can be used in silc_pkcs_unregister
    to unregister all PKCS at once. */
 #define SILC_ALL_PKCS ((SilcPKCSObject *)1)
+#define SILC_ALL_PKCS_ALG ((SilcPKCSAlgorithm *)1)
 
-/* Static list of PKCS for silc_pkcs_register_default(). */
+/* Static lists of PKCS and PKCS algorithms. */
 extern DLLAPI const SilcPKCSObject silc_default_pkcs[];
-
-/* Default PKXS in the SILC protocol */
-#define SILC_DEFAULT_PKCS "rsa"
-
-/* Macros */
-
-/* Macros used to implement the SILC PKCS API */
-
-/* XXX: This needs slight redesigning. These needs to be made even
-   more generic. I don't like that the actual prime generation is done
-   in PKCS_API_INIT. The primes used in key generation should be sent
-   as argument to the init function. By doing this we would achieve
-   that PKCS could be used as SIM's. The only requirement would be
-   that they are compiled against GMP (well, actually even that would
-   not be a requirement, but the most generic case anyway). The new init
-   would look something like this:
-
-   #define SILC_PKCS_API_INIT(pkcs) \
-   inline int silc_##pkcs##_init(void *context, SilcUInt32 keylen, \
-                                 void *p1, void *p2)
-
-   Now we wouldn't have to send the SilcRng object since the primes are
-   provided as arguments. To send them as void * they could actually be
-   used as in anyway for real (MP_INT (SilcMPInt) or even something else
-   (the pointer could be kludged to be something else in the module))
-   (Plus, the SilcRng object management in prime generation would be
-   simpler and better what it is now (in silcprimegen.c, that is)).
-*/
-
-#define SILC_PKCS_API_INIT(pkcs) \
-int silc_##pkcs##_init(void *context, SilcUInt32 keylen, \
-                      SilcRng rng)
-#define SILC_PKCS_API_CLEAR_KEYS(pkcs) \
-void silc_##pkcs##_clear_keys(void *context)
-#define SILC_PKCS_API_GET_PUBLIC_KEY(pkcs) \
-unsigned char *silc_##pkcs##_get_public_key(void *context, \
-                                            SilcUInt32 *ret_len)
-#define SILC_PKCS_API_GET_PRIVATE_KEY(pkcs) \
-unsigned char *silc_##pkcs##_get_private_key(void *context, \
-                                             SilcUInt32 *ret_len)
-#define SILC_PKCS_API_SET_PUBLIC_KEY(pkcs) \
-SilcUInt32 silc_##pkcs##_set_public_key(void *context, unsigned char *key_data, \
-                                        SilcUInt32 key_len)
-#define SILC_PKCS_API_SET_PRIVATE_KEY(pkcs) \
-SilcUInt32 silc_##pkcs##_set_private_key(void *context, unsigned char *key_data, \
-                                         SilcUInt32 key_len)
-#define SILC_PKCS_API_CONTEXT_LEN(pkcs) \
-SilcUInt32 silc_##pkcs##_context_len()
-#define SILC_PKCS_API_ENCRYPT(pkcs) \
-int silc_##pkcs##_encrypt(void *context, \
-                         unsigned char *src, \
-                         SilcUInt32 src_len, \
-                         unsigned char *dst, \
-                         SilcUInt32 *dst_len)
-#define SILC_PKCS_API_DECRYPT(pkcs) \
-int silc_##pkcs##_decrypt(void *context, \
-                         unsigned char *src, \
-                         SilcUInt32 src_len, \
-                         unsigned char *dst, \
-                         SilcUInt32 *dst_len)
-#define SILC_PKCS_API_SIGN(pkcs) \
-int silc_##pkcs##_sign(void *context, \
-                      unsigned char *src, \
-                      SilcUInt32 src_len, \
-                      unsigned char *dst, \
-                      SilcUInt32 *dst_len)
-#define SILC_PKCS_API_VERIFY(pkcs) \
-int silc_##pkcs##_verify(void *context, \
-                        unsigned char *signature, \
-                        SilcUInt32 signature_len, \
-                        unsigned char *data, \
-                        SilcUInt32 data_len)
+extern DLLAPI const SilcPKCSAlgorithm silc_default_pkcs_alg[];
 
 /* Prototypes */
 
@@ -294,75 +327,61 @@ SilcBool silc_pkcs_register(const SilcPKCSObject *pkcs);
  ***/
 SilcBool silc_pkcs_unregister(SilcPKCSObject *pkcs);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_register_default
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_register_default(void);
- *
- * DESCRIPTION
- *
- *    Registers all the default PKCS (all builtin PKCS).  The application may
- *    use this to register the default PKCS if specific PKCS in any specific
- *    order is not wanted. Returns FALSE on error.
- *
- ***/
-SilcBool silc_pkcs_register_default(void);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_unregister_all
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_algorithm_register
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_unregister_all(void);
+ *    SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs);
  *
  * DESCRIPTION
  *
- *    Returns FALSE on error.
+ *    Registers a new PKCS Algorithm into the SILC.  This function is used
+ *    at the initialization of the SILC.  All registered PKCS algorithms
+ *    should be unregistered with silc_pkcs_unregister.
  *
  ***/
-SilcBool silc_pkcs_unregister_all(void);
+SilcBool silc_pkcs_algorithm_register(const SilcPKCSAlgorithm *pkcs);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_alloc
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_algorithm_unregister
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_alloc(const unsigned char *name,
- *                             SilcPKCSType type, SilcPKCS *new_pkcs);
+ *    SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs);
  *
  * DESCRIPTION
  *
- *    Allocates a new SilcPKCS object.  The new allocated object is returned
- *    to the 'new_pkcs' argument.  Returns FALSE on error.
+ *    Unregister a PKCS from the SILC. Returns FALSE on error.
  *
  ***/
-SilcBool silc_pkcs_alloc(const unsigned char *name,
-                        SilcPKCSType type, SilcPKCS *new_pkcs);
+SilcBool silc_pkcs_algorithm_unregister(SilcPKCSAlgorithm *pkcs);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_free
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_register_default
  *
  * SYNOPSIS
  *
- *    void silc_pkcs_free(SilcPKCS pkcs);
+ *    SilcBool silc_pkcs_register_default(void);
  *
  * DESCRIPTION
  *
- *    Frees the PKCS object.
+ *    Registers all the default PKCS (all builtin PKCS) and PKCS algorithms.
+ *    The application may use this to register the default PKCS if specific
+ *    PKCS in any specific order is not wanted.  Returns FALSE on error.
  *
  ***/
-void silc_pkcs_free(SilcPKCS pkcs);
+SilcBool silc_pkcs_register_default(void);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_is_supported
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_unregister_all
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_is_supported(const unsigned char *name);
+ *    SilcBool silc_pkcs_unregister_all(void);
  *
  * DESCRIPTION
  *
- *    Returns TRUE if PKCS algorithm `name' is supported.
+ *    Unregister all PKCS and PKCS algorithms. Returns FALSE on error.
  *
  ***/
-SilcBool silc_pkcs_is_supported(const unsigned char *name);
+SilcBool silc_pkcs_unregister_all(void);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_supported
  *
@@ -377,318 +396,126 @@ SilcBool silc_pkcs_is_supported(const unsigned char *name);
  ***/
 char *silc_pkcs_get_supported(void);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_generate_key
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
- *                               SilcRng rng);
- *
- * DESCRIPTION
- *
- *    Generate new key pair into the `pkcs' context. Returns FALSE on error.
- *    If the `rng' is NULL global SILC RNG will be used.
- *
- ***/
-SilcBool silc_pkcs_generate_key(SilcPKCS pkcs, SilcUInt32 bits_key_len,
-                               SilcRng rng);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_key_len
- *
- * SYNOPSIS
- *
- *    SilcUInt32 silc_pkcs_get_key_len(SilcPKCS self);
- *
- * DESCRIPTION
- *
- *    Returns the length of the key in bits.
- *
- ***/
-SilcUInt32 silc_pkcs_get_key_len(SilcPKCS self);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_name
- *
- * SYNOPSIS
- *
- *    const char *silc_pkcs_get_name(SilcPKCS pkcs);
- *
- * DESCRIPTION
- *
- *    Returns PKCS name.
- *
- ***/
-const char *silc_pkcs_get_name(SilcPKCS pkcs);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_public_key
- *
- * SYNOPSIS
- *
- *    unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len);
- *
- * DESCRIPTION
- *
- *    Returns SILC style public key for the PKCS.  Note that this is not
- *    the SILC Public Key, but the raw public key data from the PKCS.
- *    The caller must free the returned data.
- *
- ***/
-unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_private_key
- *
- * SYNOPSIS
- *
- *    unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs,
- *                                             SilcUInt32 *len);
- *
- * DESCRIPTION
- *
- *    Returns SILC style private key.  Note that this is not SilcPrivateKey
- *    but the raw private key bits from the PKCS.  The caller must free the
- *    returned data and SHOULD zero the memory area before freeing.
- *
- ***/
-unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_set
- *
- * SYNOPSIS
- *
- *    SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs,
- *                                        SilcPublicKey public_key);
- *
- * DESCRIPTION
- *
- *    Sets public key from SilcPublicKey. Returns the length of the key in
- *    bits.
- *
- ***/
-SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_data_set
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_find_pkcs
  *
  * SYNOPSIS
  *
- *    SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs,
- *                                             unsigned char *pk,
- *                                             SilcUInt32 pk_len);
+ *    const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPKCSType type);
  *
  * DESCRIPTION
  *
- *    Sets public key from data. Returns the length of the key.
+ *    Finds PKCS context by the PKCS type.
  *
  ***/
-SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
-                                        SilcUInt32 pk_len);
+const SilcPKCSObject *silc_pkcs_find_pkcs(SilcPKCSType type);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_set
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_find_algorithm
  *
  * SYNOPSIS
  *
- *    SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs,
- *                                         SilcPrivateKey private_key);
+ *    const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
+ *                                                      const char *scheme);
  *
  * DESCRIPTION
  *
- *    Sets private key from SilcPrivateKey. Returns the length of the key
- *    in bits.
+ *    Finds PKCS algorithm context by the algorithm name `algorithm' and
+ *    the algorithm scheme `scheme'.  The `scheme' may be NULL.
  *
  ***/
-SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs,
-                                    SilcPrivateKey private_key);
+const SilcPKCSAlgorithm *silc_pkcs_find_algorithm(const char *algorithm,
+                                                 const char *scheme);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_data_set
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_pkcs
  *
  * SYNOPSIS
  *
- *    SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs,
- *                                              unsigned char *prv,
- *                                              SilcUInt32 prv_len);
+ *    const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key);
  *
  * DESCRIPTION
  *
- *    Sets private key from data. Returns the length of the key.
+ *    Returns the PKCS object from `public_key'.
  *
  ***/
-SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
-                                         SilcUInt32 prv_len);
+const SilcPKCSObject *silc_pkcs_get_pkcs(SilcPublicKey public_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encrypt
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_algorithm
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src,
- *                           SilcUInt32 src_len, unsigned char *dst,
- *                           SilcUInt32 *dst_len);
+ *    const SilcPKCSObject *silc_pkcs_get_algorithm(SilcPublicKey public_key);
  *
  * DESCRIPTION
  *
- *    Encrypts. Returns FALSE on error.
+ *    Returns the PKCS algorithm object from `public_key'.
  *
  ***/
-SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src,
-                          SilcUInt32 src_len,
-                          unsigned char *dst, SilcUInt32 *dst_len);
+const SilcPKCSAlgorithm *silc_pkcs_get_algorithm(SilcPublicKey public_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decrypt
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src,
- *                           SilcUInt32 src_len, unsigned char *dst,
- *                           SilcUInt32 *dst_len);
- *
- * DESCRIPTION
- *
- *    Decrypts.  Returns FALSE on error.
- *
- ***/
-SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src,
-                          SilcUInt32 src_len,
-                          unsigned char *dst, SilcUInt32 *dst_len);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src,
- *                        SilcUInt32 src_len, unsigned char *dst,
- *                        SilcUInt32 *dst_len);
- *
- * DESCRIPTION
- *
- *    Generates signature.  Returns FALSE on error.
- *
- ***/
-SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
-                       unsigned char *dst, SilcUInt32 *dst_len);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
- *                          SilcUInt32 signature_len, unsigned char *data,
- *                          SilcUInt32 data_len);
- *
- * DESCRIPTION
- *
- *    Verifies signature.  Returns FALSE on error.  The 'signature' is
- *    verified against the 'data'.
- *
- ***/
-SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
-                         SilcUInt32 signature_len, unsigned char *data,
-                         SilcUInt32 data_len);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign_with_hash
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
- *                                  unsigned char *src, SilcUInt32 src_len,
- *                                  unsigned char *dst, SilcUInt32 *dst_len);
- *
- * DESCRIPTION
- *
- *    Generates signature with hash.  The hash is signed.  Returns FALSE on
- *    error.
- *
- ***/
-SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
-                                 unsigned char *src, SilcUInt32 src_len,
-                                 unsigned char *dst, SilcUInt32 *dst_len);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify_with_hash
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_name
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
- *                                    unsigned char *signature,
- *                                    SilcUInt32 signature_len,
- *                                    unsigned char *data,
- *                                    SilcUInt32 data_len);
+ *    const char *silc_pkcs_get_name(SilcPublicKey public_key)
  *
  * DESCRIPTION
  *
- *    Verifies signature with hash.  The `data' is hashed and verified against
- *    the `signature'.  Returns FALSE on error.
+ *    Returns PKCS algorithm name from the public key.
  *
  ***/
-SilcBool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
-                                   unsigned char *signature,
-                                   SilcUInt32 signature_len,
-                                   unsigned char *data,
-                                   SilcUInt32 data_len);
+const char *silc_pkcs_get_name(SilcPublicKey public_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encode_identifier
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_type
  *
  * SYNOPSIS
  *
- *    char *silc_pkcs_encode_identifier(char *username, char *host,
- *                                      char *realname, char *email,
- *                                      char *org, char *country);
+ *    SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key);
  *
  * DESCRIPTION
  *
- *    Encodes and returns SILC public key identifier. If some of the
- *    arguments is NULL those are not encoded into the identifier string.
- *    Protocol says that at least username and host must be provided.
+ *    Returns PKCS type from the public key.
  *
  ***/
-char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
-                                 char *email, char *org, char *country);
+SilcPKCSType silc_pkcs_get_type(SilcPublicKey public_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decode_identifier
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_get_context
  *
  * SYNOPSIS
  *
- *    SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier);
+ *    void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key);
  *
  * DESCRIPTION
  *
- *    Decodes the provided `identifier' and returns allocated context for
- *    the identifier.
+ *    Returns the internal PKCS `type' specific public key context from the
+ *    `public_key'.  The caller needs to explicitly type cast it to correct
+ *    type.  Returns NULL on error.
  *
- ***/
-SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_free_identifier
- *
- * SYNOPSIS
- *
- *    void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier);
- *
- * DESCRIPTION
- *
- *    Frees decoded public key identifier context.  Call this to free the
- *    context returned by the silc_pkcs_decode_identifier.
+ *    For SILC_PKCS_SILC the returned context is SilcSILCPublicKey.
  *
  ***/
-void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier);
+void *silc_pkcs_get_context(SilcPKCSType type, SilcPublicKey public_key);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_alloc
  *
  * SYNOPSIS
  *
- *    SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
- *                                             const char *identifier,
- *                                             const unsigned char *pk,
- *                                             SilcUInt32 pk_len);
+ *    SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
+ *                                        unsigned char *key,
+ *                                        SilcUInt32 key_len
+ *                                        SilcPublicKey *ret_public_key);
  *
  * DESCRIPTION
  *
- *    Allocates SILC style public key formed from sent arguments.  The
- *    'name' is the algorithm (PKCS) name, the 'identifier' is the public
- *    key identifier generated with silc_pkcs_encode_identifier, and the
- *    'pk' and 'pk_len' are the raw public key data returned for example
- *    by silc_pkcs_get_public_key.
+ *    Allocates SilcPublicKey of the type of `type' from the key data
+ *    `key' of length of `key_len' bytes.  Returns FALSE if the `key'
+ *    is malformed or unsupported public key type.  This function can be
+ *    used to create public key from any kind of PKCS public keys that
+ *    the implementation supports.
  *
  ***/
-SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
-                                        const char *identifier,
-                                        const unsigned char *pk,
-                                        SilcUInt32 pk_len);
+SilcBool silc_pkcs_public_key_alloc(SilcPKCSType type,
+                                   unsigned char *key,
+                                   SilcUInt32 key_len,
+                                   SilcPublicKey *ret_public_key);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_free
  *
@@ -698,304 +525,278 @@ SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
  *
  * DESCRIPTION
  *
- *    Frees public key and all data in it.
+ *    Frees the public key.
  *
  ***/
 void silc_pkcs_public_key_free(SilcPublicKey public_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_alloc
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_export
  *
  * SYNOPSIS
  *
- *    SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
- *                                               const unsigned char *prv,
- *                                               SilcUInt32 prv_len);
+ *    unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
+ *                                               SilcUInt32 *ret_len);
  *
  * DESCRIPTION
  *
- *    Allocates SILC private key formed from sent arguments.  The 'name'
- *    is the algorithm name, and the 'prv' and 'prv_len' are the raw
- *    private key bits returned by silc_pkcs_get_private_key.
+ *    Encodes the `public_key' into a binary format and returns it.  Returns
+ *    NULL on error.  Caller must free the returned buffer.
  *
  ***/
-SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
-                                          const unsigned char *prv,
-                                          SilcUInt32 prv_len);
+unsigned char *silc_pkcs_public_key_encode(SilcPublicKey public_key,
+                                          SilcUInt32 *ret_len);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_free
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_get_len
  *
  * SYNOPSIS
  *
- *    void silc_pkcs_private_key_free(SilcPrivateKey private_key);
+ *    SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key);
  *
  * DESCRIPTION
  *
- *    Frees private key and all data in it.  The private key is zeroed
- *    before it is freed.
+ *    Returns the key length in bits from the public key.
  *
  ***/
-void silc_pkcs_private_key_free(SilcPrivateKey private_key);
+SilcUInt32 silc_pkcs_public_key_get_len(SilcPublicKey public_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_encode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_compare
  *
  * SYNOPSIS
  *
- *    unsigned char *
- *    silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len);
+ *    SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1,
+ *                                          SilcPublicKey key2);
  *
  * DESCRIPTION
  *
- *    Encodes SILC style public key from SilcPublicKey.  Returns the encoded
- *    data.
+ *    Compares two public keys and returns TRUE if they are same key, and
+ *    FALSE if they are not same.
  *
  ***/
-unsigned char *
-silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len);
+SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_data_encode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_copy
  *
  * SYNOPSIS
  *
- *    unsigned char *
- *    silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
- *                                     char *pkcs, char *identifier,
- *                                     SilcUInt32 *len);
+ *    SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
  *
  * DESCRIPTION
  *
- *    Encodes SILC style public key.  Returns the encoded data.
+ *    Copies the public key indicated by `public_key' and returns new
+ *    allocated public key which is indentical to the `public_key'.
  *
  ***/
-unsigned char *
-silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
-                                 char *pkcs, char *identifier,
-                                 SilcUInt32 *len);
+SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_decode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_alloc
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_public_key_decode(unsigned char *data,
- *                                     SilcUInt32 data_len,
- *                                     SilcPublicKey *public_key);
+ *    SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
+ *                                         unsigned char *key,
+ *                                         SilcUInt32 key_len,
+ *                                         SilcPrivateKey *ret_private_key);
  *
  * DESCRIPTION
  *
- *    Decodes SILC style public key. Returns TRUE if the decoding was
- *    successful. Allocates new public key as well.
+ *    Allocates SilcPrivateKey of the type of `type' from the key data
+ *    `key' of length of `key_len' bytes.  Returns FALSE if the `key'
+ *    is malformed or unsupported private key type.
  *
  ***/
-SilcBool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
-                                SilcPublicKey *public_key);
+SilcBool silc_pkcs_private_key_alloc(SilcPKCSType type,
+                                    unsigned char *key,
+                                    SilcUInt32 key_len,
+                                    SilcPrivateKey *ret_private_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_payload_encode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_get_len
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_public_key_payload_encode(SilcPublicKey public_key);
+ *    SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key);
  *
  * DESCRIPTION
  *
- *    Encodes the Public Key Payload from the public key indicated by
- *    `public_key' of type of `pk_type'.  The type is SilcSKEPKType.
- *    Returns the encoded payload buffer.
+ *    Returns the key length in bits from the public key.
  *
  ***/
-SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key);
+SilcUInt32 silc_pkcs_private_key_get_len(SilcPrivateKey private_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_payload_decode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_free
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data,
- *                                             SilcUInt32 data_len,
- *                                             SilcPublicKey *public_key);
+ *    void silc_pkcs_private_key_free(SilcPrivateKey private_key;
  *
  * DESCRIPTION
  *
- *    Decodes Public Key Payload from `data' of `data_len' bytes in length
- *    data buffer into `public_key' pointer.  Returns FALSE if the payload
- *    cannot be decoded.
+ *    Frees the private key.
  *
  ***/
-SilcBool silc_pkcs_public_key_payload_decode(unsigned char *data,
-                                        SilcUInt32 data_len,
-                                        SilcPublicKey *public_key);
+void silc_pkcs_private_key_free(SilcPrivateKey private_key);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_compare
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_encrypt
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1,
- *                                      SilcPublicKey key2);
+ *    SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
+ *                               unsigned char *src, SilcUInt32 src_len,
+ *                               unsigned char *dst, SilcUInt32 dst_size,
+ *                               SilcUInt32 *dst_len);
  *
  * DESCRIPTION
  *
- *    Compares two public keys and returns TRUE if they are same key, and
- *    FALSE if they are not same.
+ *    Encrypts with the public key. Returns FALSE on error.
  *
  ***/
-SilcBool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2);
+SilcBool silc_pkcs_encrypt(SilcPublicKey public_key,
+                          unsigned char *src, SilcUInt32 src_len,
+                          unsigned char *dst, SilcUInt32 dst_size,
+                          SilcUInt32 *dst_len);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_public_key_copy
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_decrypt
  *
  * SYNOPSIS
  *
- *    SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
+ *    SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
+ *                               unsigned char *src, SilcUInt32 src_len,
+ *                               unsigned char *dst, SilcUInt32 dst_size,
+ *                               SilcUInt32 *dst_len);
  *
  * DESCRIPTION
  *
- *    Copies the public key indicated by `public_key' and returns new allocated
- *    public key which is indentical to the `public_key'.
+ *    Decrypts with the private key.  Returns FALSE on error.
  *
  ***/
-SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
+SilcBool silc_pkcs_decrypt(SilcPrivateKey private_key,
+                          unsigned char *src, SilcUInt32 src_len,
+                          unsigned char *dst, SilcUInt32 dst_size,
+                          SilcUInt32 *dst_len);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_encode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign
  *
  * SYNOPSIS
  *
- *    unsigned char *
- *    silc_pkcs_private_key_encode(SilcPrivateKey private_key,
- *                                 SilcUInt32 *len);
+ *    SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
+ *                            unsigned char *src, SilcUInt32 src_len,
+ *                            unsigned char *dst, SilcUInt32 dst_size,
+ *                            SilcUInt32 *dst_len, SilcHash hash);
  *
  * DESCRIPTION
  *
- *    Encodes SILC private key from SilcPrivateKey.  Returns the encoded data.
+ *    Generates signature with the private key.  Returns FALSE on error.
+ *    If `hash' is non-NULL the `src' will be hashed before signing.
  *
  ***/
-unsigned char *
-silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len);
+SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
+                       unsigned char *src, SilcUInt32 src_len,
+                       unsigned char *dst, SilcUInt32 dst_size,
+                       SilcUInt32 *dst_len, SilcHash hash);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_data_encode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify
  *
  * SYNOPSIS
  *
- *    unsigned char *
- *    silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
- *                                      char *pkcs, SilcUInt32 *len);
+ *    SilcBool silc_pkcs_verify(SilcPublicKey public_key,
+ *                              unsigned char *signature,
+ *                              SilcUInt32 signature_len,
+ *                              unsigned char *data,
+ *                              SilcUInt32 data_len, SilcHash hash);
  *
  * DESCRIPTION
  *
- *    Encodes SILC private key.  Returns the encoded data.
+ *    Verifies signature.  Returns FALSE on error.  The 'signature' is
+ *    verified against the 'data'.  If the `hash' is non-NULL then the `data'
+ *    will hashed before verification.  If the `hash' is NULL, then the
+ *    hash algorithm to be used is retrieved from the signature.  If it
+ *    isn't present in the signature the verification is done as is without
+ *    hashing.
  *
  ***/
-unsigned char *
-silc_pkcs_private_key_data_encode(unsigned char *prv, SilcUInt32 prv_len,
-                                 char *pkcs, SilcUInt32 *len);
+SilcBool silc_pkcs_verify(SilcPublicKey public_key,
+                         unsigned char *signature,
+                         SilcUInt32 signature_len,
+                         unsigned char *data,
+                         SilcUInt32 data_len, SilcHash hash);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_private_key_decode
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_public_key
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_private_key_decode(unsigned char *data,
- *                                      SilcUInt32 data_len,
- *                                      SilcPrivateKey *private_key);
+ *    SilcBool silc_pkcs_load_public_key(const char *filename,
+ *                                       SilcPublicKey *ret_public_key);
  *
  * DESCRIPTION
  *
- *    Decodes SILC style private key.  Returns TRUE if the decoding was
- *    successful.  Allocates new private key as well.
+ *    Loads public key from file and allocates new public key.  Returns TRUE
+ *    if loading was successful.
  *
  ***/
-SilcBool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
-                                 SilcPrivateKey *private_key);
+SilcBool silc_pkcs_load_public_key(const char *filename,
+                                  SilcPublicKey *ret_public_key);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_public_key
  *
  * SYNOPSIS
  *
  *    SilcBool silc_pkcs_save_public_key(const char *filename,
- *                                   SilcPublicKey public_key,
- *                                   SilcUInt32 encoding);
+ *                                       SilcPublicKey public_key,
+ *                                       SilcPKCSFileEncoding encoding);
  *
  * DESCRIPTION
  *
- *    Saves public key into file.  Returns FALSE on error.
+ *    Saves public key into file with specified encoding.  Returns FALSE
+ *    on error.
  *
  ***/
-SilcBool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key,
-                              SilcUInt32 encoding);
+SilcBool silc_pkcs_save_public_key(const char *filename,
+                                  SilcPublicKey public_key,
+                                  SilcPKCSFileEncoding encoding);
 
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_public_key_data
+/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_private_key
  *
  * SYNOPSIS
  *
- *    SilcBool silc_pkcs_save_public_key_data(const char *filename,
- *                                        unsigned char *data,
- *                                        SilcUInt32 data_len,
- *                                        SilcUInt32 encoding);
+ *    SilcBool silc_pkcs_load_private_key(const char *filename,
+ *                                        const unsigned char *passphrase,
+ *                                        SilcUInt32 passphrase_len,
+ *                                        SilcPrivateKey *ret_private_key);
  *
  * DESCRIPTION
  *
- *    Saves public key into file.  The public key is already encoded as
- *    data when calling this function.  Returns FALSE on error.
+ *    Loads private key from file and allocates new private key.  Returns TRUE
+ *    if loading was successful.  The `passphrase' is used as decryption
+ *    key of the private key file, in case it is encrypted.
  *
  ***/
-SilcBool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data,
-                                   SilcUInt32 data_len, SilcUInt32 encoding);
+SilcBool silc_pkcs_load_private_key(const char *filename,
+                                   const unsigned char *passphrase,
+                                   SilcUInt32 passphrase_len,
+                                   SilcPrivateKey *ret_private_key);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_private_key
  *
  * SYNOPSIS
  *
  *    SilcBool silc_pkcs_save_private_key(const char *filename,
- *                                    SilcPrivateKey private_key,
- *                                    unsigned char *passphrase,
- *                                    SilcUInt32 passphrase_len,
- *                                    SilcUInt32 encoding);
+ *                                        SilcPrivateKey private_key,
+ *                                        const unsigned char *passphrase,
+ *                                        SilcUInt32 passphrase_len,
+ *                                        SilcPKCSFileEncoding encoding,
+ *                                        SilcRng rng);
  *
  * DESCRIPTION
  *
  *    Saves private key into file.  The private key is encrypted into
- *    the file with the `passphrase' as a key.  The encryption algorithm
- *    is AES with 256 bit key in CBC mode.  Returns FALSE on error.
+ *    the file with the `passphrase' as a key, if PKCS supports encrypted
+ *    private keys.  Returns FALSE on error.
  *
  ***/
 SilcBool silc_pkcs_save_private_key(const char *filename,
-                               SilcPrivateKey private_key,
-                               unsigned char *passphrase,
-                               SilcUInt32 passphrase_len,
-                               SilcUInt32 encoding);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_public_key
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_load_public_key(const char *filename,
- *                                   SilcPublicKey *public_key,
- *                                   SilcUInt32 encoding);
- *
- * DESCRIPTION
- *
- *    Loads public key from file and allocates new public key.  Returns TRUE
- *    if loading was successful.
- *
- ***/
-SilcBool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
-                              SilcUInt32 encoding);
-
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_private_key
- *
- * SYNOPSIS
- *
- *    SilcBool silc_pkcs_load_private_key(const char *filename,
- *                                    SilcPrivateKey *private_key,
- *                                    unsigned char *passphrase,
- *                                    SilcUInt32 passphrase_len,
- *                                    SilcUInt32 encoding);
- *
- * DESCRIPTION
- *
- *    Loads private key from file and allocates new private key.  Returns TRUE
- *    if loading was successful.  The `passphrase' is used as decryption
- *    key of the private key file.
- *
- ***/
-SilcBool silc_pkcs_load_private_key(const char *filename,
-                               SilcPrivateKey *private_key,
-                               unsigned char *passphrase,
-                               SilcUInt32 passphrase_len,
-                               SilcUInt32 encoding);
+                                   SilcPrivateKey private_key,
+                                   const unsigned char *passphrase,
+                                   SilcUInt32 passphrase_len,
+                                   SilcPKCSFileEncoding encoding,
+                                   SilcRng rng);
 
 #endif /* !SILCPKCS_H */
index bfdded05218f814f7ab93838cbe1d20bf3caae70..57f25e675fa2b597926db3bd163c85cb2de2ed60 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2003 Pekka Riikonen
+  Copyright (C) 2003 - 2006 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
@@ -19,7 +19,9 @@
 /* $Id$ */
 
 #include "silc.h"
-#include "silcpkcs1.h"
+#include "rsa.h"
+
+/************************** PKCS #1 message format ***************************/
 
 /* Minimum padding in block */
 #define SILC_PKCS1_MIN_PADDING 8
    success. */
 
 SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
-                      const unsigned char *data,
-                      SilcUInt32 data_len,
-                      unsigned char *dest_data,
-                      SilcUInt32 dest_data_size,
-                      SilcRng rng)
+                          const unsigned char *data,
+                          SilcUInt32 data_len,
+                          unsigned char *dest_data,
+                          SilcUInt32 dest_data_size,
+                          SilcRng rng)
 {
   SilcInt32 padlen;
   int i;
@@ -46,7 +48,8 @@ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
   SILC_LOG_DEBUG(("PKCS#1 encoding, bt %d", bt));
 
   if (!data || !dest_data ||
-      dest_data_size < 3 || dest_data_size < data_len) {
+      dest_data_size < SILC_PKCS1_MIN_PADDING + 3 ||
+      dest_data_size < data_len) {
     SILC_LOG_DEBUG(("Data to be encoded is too long"));
     return FALSE;
   }
@@ -97,11 +100,11 @@ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
    Returns TRUE on success. */
 
 SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt,
-                      const unsigned char *data,
-                      SilcUInt32 data_len,
-                      unsigned char *dest_data,
-                      SilcUInt32 dest_data_size,
-                      SilcUInt32 *dest_len)
+                          const unsigned char *data,
+                          SilcUInt32 data_len,
+                          unsigned char *dest_data,
+                          SilcUInt32 dest_data_size,
+                          SilcUInt32 *dest_len)
 {
   int i = 0;
 
@@ -158,3 +161,537 @@ SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt,
 
   return TRUE;
 }
+
+
+/***************************** PKCS #1 PKCS API ******************************/
+
+/* Generates RSA key pair. */
+
+SilcBool silc_pkcs1_generate_key(SilcUInt32 keylen,
+                                SilcRng rng,
+                                void **ret_public_key,
+                                void **ret_private_key)
+{
+  SilcUInt32 prime_bits = keylen / 2;
+  SilcMPInt p, q;
+  SilcBool found = FALSE;
+
+  if (keylen < 768 || keylen > 16384)
+    return FALSE;
+
+  silc_mp_init(&p);
+  silc_mp_init(&q);
+
+  /* Find p and q */
+  while (!found) {
+    silc_math_gen_prime(&p, prime_bits, FALSE, rng);
+    silc_math_gen_prime(&q, prime_bits, FALSE, rng);
+    if ((silc_mp_cmp(&p, &q)) != 0)
+      found = TRUE;
+  }
+
+  /* If p is smaller than q, switch them */
+  if ((silc_mp_cmp(&p, &q)) > 0) {
+    SilcMPInt hlp;
+    silc_mp_init(&hlp);
+
+    silc_mp_set(&hlp, &p);
+    silc_mp_set(&p, &q);
+    silc_mp_set(&q, &hlp);
+
+    silc_mp_uninit(&hlp);
+  }
+
+  /* Generate the actual keys */
+  if (!rsa_generate_keys(keylen, &p, &q, ret_public_key, ret_private_key))
+    return FALSE;
+
+  silc_mp_uninit(&p);
+  silc_mp_uninit(&q);
+
+  return TRUE;
+}
+
+/* Import PKCS #1 compliant public key */
+
+SilcBool silc_pkcs1_import_public_key(unsigned char *key,
+                                     SilcUInt32 key_len,
+                                     void **ret_public_key)
+{
+  SilcAsn1 asn1 = NULL;
+  SilcBufferStruct alg_key;
+  RsaPublicKey *pubkey;
+
+  if (!ret_public_key)
+    return FALSE;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    return FALSE;
+
+  /* Allocate RSA public key */
+  *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey));
+  if (!pubkey)
+    goto err;
+
+  /* Parse the PKCS #1 public key */
+  silc_buffer_set(&alg_key, key, key_len);
+  if (!silc_asn1_decode(asn1, &alg_key,
+                       SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
+                       SILC_ASN1_SEQUENCE,
+                       SILC_ASN1_INT(&pubkey->n),
+                       SILC_ASN1_INT(&pubkey->e),
+                       SILC_ASN1_END, SILC_ASN1_END))
+    goto err;
+
+  /* Set key length */
+  pubkey->bits = silc_mp_sizeinbase(&pubkey->n, 2);
+
+  silc_asn1_free(asn1);
+
+  return TRUE;
+
+ err:
+  silc_asn1_free(asn1);
+  return FALSE;
+}
+
+/* Export PKCS #1 compliant public key */
+
+unsigned char *silc_pkcs1_export_public_key(void *public_key,
+                                           SilcUInt32 *ret_len)
+{
+  RsaPublicKey *key = public_key;
+  SilcAsn1 asn1 = NULL;
+  SilcBufferStruct alg_key;
+  unsigned char *ret;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    goto err;
+
+  /* Encode to PKCS #1 public key */
+  memset(&alg_key, 0, sizeof(alg_key));
+  if (!silc_asn1_encode(asn1, &alg_key,
+                       SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
+                       SILC_ASN1_SEQUENCE,
+                       SILC_ASN1_INT(&key->n),
+                       SILC_ASN1_INT(&key->e),
+                       SILC_ASN1_END, SILC_ASN1_END))
+    goto err;
+
+  ret = silc_buffer_steal(&alg_key, ret_len);
+  silc_asn1_free(asn1);
+
+  return ret;
+
+ err:
+  if (asn1)
+    silc_asn1_free(asn1);
+  return NULL;
+}
+
+/* Returns key length */
+
+SilcUInt32 silc_pkcs1_public_key_bitlen(void *public_key)
+{
+  RsaPublicKey *key = public_key;
+  return key->bits;
+}
+
+/* Copy public key */
+
+void *silc_pkcs1_public_key_copy(void *public_key)
+{
+  RsaPublicKey *key = public_key, *new_key;
+
+  new_key = silc_calloc(1, sizeof(*new_key));
+  if (!new_key)
+    return NULL;
+
+  silc_mp_init(&new_key->n);
+  silc_mp_init(&new_key->e);
+  silc_mp_set(&new_key->n, &key->n);
+  silc_mp_set(&new_key->e, &key->e);
+  new_key->bits = key->bits;
+
+  return new_key;
+}
+
+/* Compare public keys */
+
+SilcBool silc_pkcs1_public_key_compare(void *key1, void *key2)
+{
+  RsaPublicKey *k1 = key1, *k2 = key2;
+
+  if (k1->bits != k2->bits)
+    return FALSE;
+  if (silc_mp_cmp(&k1->e, &k2->e) != 0)
+    return FALSE;
+  if (silc_mp_cmp(&k1->n, &k2->n) != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Frees public key */
+
+void silc_pkcs1_public_key_free(void *public_key)
+{
+  RsaPublicKey *key = public_key;
+
+  silc_mp_uninit(&key->n);
+  silc_mp_uninit(&key->e);
+  silc_free(key);
+}
+
+/* Import PKCS #1 compliant private key */
+
+SilcBool silc_pkcs1_import_private_key(unsigned char *key,
+                                      SilcUInt32 key_len,
+                                      void **ret_private_key)
+{
+  SilcAsn1 asn1;
+  SilcBufferStruct alg_key;
+  RsaPrivateKey *privkey;
+
+  if (!ret_private_key)
+    return FALSE;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    return FALSE;
+
+  /* Allocate RSA private key */
+  *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey));
+  if (!privkey)
+    goto err;
+
+  /* Parse the PKCS #1 private key */
+  silc_buffer_set(&alg_key, key, key_len);
+  if (!silc_asn1_decode(asn1, &alg_key,
+                       SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
+                       SILC_ASN1_SEQUENCE,
+                       SILC_ASN1_INT(NULL),
+                       SILC_ASN1_INT(&privkey->n),
+                       SILC_ASN1_INT(&privkey->e),
+                       SILC_ASN1_INT(&privkey->d),
+                       SILC_ASN1_INT(&privkey->p),
+                       SILC_ASN1_INT(&privkey->q),
+                       SILC_ASN1_INT(&privkey->dP),
+                       SILC_ASN1_INT(&privkey->dQ),
+                       SILC_ASN1_INT(&privkey->qP),
+                       SILC_ASN1_END, SILC_ASN1_END))
+    goto err;
+
+  /* Set key length */
+  privkey->bits = silc_mp_sizeinbase(&privkey->n, 2);
+
+  silc_asn1_free(asn1);
+
+  return TRUE;
+
+ err:
+  silc_asn1_free(asn1);
+  return FALSE;
+}
+
+/* Export PKCS #1 compliant private key */
+
+unsigned char *silc_pkcs1_export_private_key(void *private_key,
+                                            SilcUInt32 *ret_len)
+{
+  RsaPrivateKey *key = private_key;
+  SilcAsn1 asn1;
+  SilcBufferStruct alg_key;
+  SilcMPInt version;
+  unsigned char *ret;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    return FALSE;
+
+  /* Encode to PKCS #1 private key */
+  silc_mp_init(&version);
+  silc_mp_set_ui(&version, 0);
+  memset(&alg_key, 0, sizeof(alg_key));
+  if (!silc_asn1_encode(asn1, &alg_key,
+                       SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
+                       SILC_ASN1_SEQUENCE,
+                       SILC_ASN1_INT(&version),
+                       SILC_ASN1_INT(&key->n),
+                       SILC_ASN1_INT(&key->e),
+                       SILC_ASN1_INT(&key->d),
+                       SILC_ASN1_INT(&key->p),
+                       SILC_ASN1_INT(&key->q),
+                       SILC_ASN1_INT(&key->dP),
+                       SILC_ASN1_INT(&key->dQ),
+                       SILC_ASN1_INT(&key->qP),
+                       SILC_ASN1_END, SILC_ASN1_END))
+    goto err;
+  silc_mp_uninit(&version);
+
+  ret = silc_buffer_steal(&alg_key, ret_len);
+  silc_asn1_free(asn1);
+
+  return ret;
+
+ err:
+  silc_asn1_free(asn1);
+  return NULL;
+}
+
+/* Returns key length */
+
+SilcUInt32 silc_pkcs1_private_key_bitlen(void *private_key)
+{
+  RsaPrivateKey *key = private_key;
+  return key->bits;
+}
+
+/* Frees private key */
+
+void silc_pkcs1_private_key_free(void *private_key)
+{
+  RsaPrivateKey *key = private_key;
+
+  silc_mp_uninit(&key->n);
+  silc_mp_uninit(&key->e);
+  silc_mp_uninit(&key->d);
+  silc_mp_uninit(&key->dP);
+  silc_mp_uninit(&key->dQ);
+  silc_mp_uninit(&key->qP);
+  silc_mp_uninit(&key->p);
+  silc_mp_uninit(&key->q);
+  silc_free(key);
+}
+
+/* PKCS #1 RSA routines */
+
+SilcBool silc_pkcs1_encrypt(void *public_key,
+                           unsigned char *src,
+                           SilcUInt32 src_len,
+                           unsigned char *dst,
+                           SilcUInt32 dst_size,
+                           SilcUInt32 *ret_dst_len)
+{
+  RsaPublicKey *key = public_key;
+  SilcMPInt mp_tmp;
+  SilcMPInt mp_dst;
+  unsigned char padded[2048 + 1];
+  SilcUInt32 len = (key->bits + 7) / 8;
+
+  if (sizeof(padded) < len)
+    return FALSE;
+  if (dst_size < len)
+    return FALSE;
+
+  /* Pad data */
+  if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len,
+                        padded, len, NULL))
+    return FALSE;
+
+  silc_mp_init(&mp_tmp);
+  silc_mp_init(&mp_dst);
+
+  /* Data to MP */
+  silc_mp_bin2mp(padded, len, &mp_tmp);
+
+  /* Encrypt */
+  rsa_public_operation(key, &mp_tmp, &mp_dst);
+
+  /* MP to data */
+  silc_mp_mp2bin_noalloc(&mp_dst, dst, len);
+  *ret_dst_len = len;
+
+  memset(padded, 0, sizeof(padded));
+  silc_mp_uninit(&mp_tmp);
+  silc_mp_uninit(&mp_dst);
+
+  return TRUE;
+}
+
+SilcBool silc_pkcs1_decrypt(void *private_key,
+                           unsigned char *src,
+                           SilcUInt32 src_len,
+                           unsigned char *dst,
+                           SilcUInt32 dst_size,
+                           SilcUInt32 *ret_dst_len)
+{
+  RsaPrivateKey *key = private_key;
+  SilcMPInt mp_tmp;
+  SilcMPInt mp_dst;
+  unsigned char *padded, unpadded[2048 + 1];
+  SilcUInt32 padded_len;
+
+  if (dst_size < (key->bits + 7) / 8)
+    return FALSE;
+
+  silc_mp_init(&mp_tmp);
+  silc_mp_init(&mp_dst);
+
+  /* Data to MP */
+  silc_mp_bin2mp(src, src_len, &mp_tmp);
+
+  /* Decrypt */
+  rsa_private_operation(key, &mp_tmp, &mp_dst);
+
+  /* MP to data */
+  padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len);
+
+  /* Unpad data */
+  if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len,
+                        unpadded, sizeof(unpadded), ret_dst_len)) {
+    memset(padded, 0, padded_len);
+    silc_free(padded);
+    silc_mp_uninit(&mp_tmp);
+    silc_mp_uninit(&mp_dst);
+    return FALSE;
+  }
+
+  /* Copy to destination */
+  memcpy(dst, unpadded, *ret_dst_len);
+
+  memset(padded, 0, padded_len);
+  memset(unpadded, 0, sizeof(unpadded));
+  silc_free(padded);
+  silc_mp_uninit(&mp_tmp);
+  silc_mp_uninit(&mp_dst);
+
+  return TRUE;
+}
+
+SilcBool silc_pkcs1_sign(void *private_key,
+                        unsigned char *src,
+                        SilcUInt32 src_len,
+                        unsigned char *signature,
+                        SilcUInt32 signature_size,
+                        SilcUInt32 *ret_signature_len,
+                        SilcHash hash)
+{
+  return FALSE;
+}
+
+SilcBool silc_pkcs1_verify(void *public_key,
+                          unsigned char *signature,
+                          SilcUInt32 signature_len,
+                          unsigned char *data,
+                          SilcUInt32 data_len,
+                          SilcHash hash)
+{
+  return FALSE;
+}
+
+/* PKCS #1 sign without hash oid */
+
+SilcBool silc_pkcs1_sign_no_oid(void *private_key,
+                               unsigned char *src,
+                               SilcUInt32 src_len,
+                               unsigned char *signature,
+                               SilcUInt32 signature_size,
+                               SilcUInt32 *ret_signature_len,
+                               SilcHash hash)
+{
+  RsaPrivateKey *key = private_key;
+  SilcMPInt mp_tmp;
+  SilcMPInt mp_dst;
+  unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
+  SilcUInt32 len = (key->bits + 7) / 8;
+
+  if (sizeof(padded) < len)
+    return FALSE;
+  if (signature_size < len)
+    return FALSE;
+
+  /* Compute hash if requested */
+  if (hash) {
+    silc_hash_make(hash, src, src_len, hashr);
+    src = hashr;
+    src_len = silc_hash_len(hash);
+  }
+
+  /* Pad data */
+  if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len,
+                        padded, len, NULL))
+    return FALSE;
+
+  silc_mp_init(&mp_tmp);
+  silc_mp_init(&mp_dst);
+
+  /* Data to MP */
+  silc_mp_bin2mp(padded, len, &mp_tmp);
+
+  /* Sign */
+  rsa_private_operation(key, &mp_tmp, &mp_dst);
+
+  /* MP to data */
+  silc_mp_mp2bin_noalloc(&mp_dst, signature, len);
+  *ret_signature_len = len;
+
+  memset(padded, 0, sizeof(padded));
+  silc_mp_uninit(&mp_tmp);
+  silc_mp_uninit(&mp_dst);
+  if (hash)
+    memset(hashr, 0, sizeof(hashr));
+
+  return TRUE;
+}
+
+/* PKCS #1 verify without hash oid */
+
+SilcBool silc_pkcs1_verify_no_oid(void *public_key,
+                                 unsigned char *signature,
+                                 SilcUInt32 signature_len,
+                                 unsigned char *data,
+                                 SilcUInt32 data_len,
+                                 SilcHash hash)
+{
+  RsaPublicKey *key = public_key;
+  int ret = TRUE;
+  SilcMPInt mp_tmp2;
+  SilcMPInt mp_dst;
+  unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
+  SilcUInt32 verify_len, len = (key->bits + 7) / 8;
+
+  silc_mp_init(&mp_tmp2);
+  silc_mp_init(&mp_dst);
+
+  /* Format the signature into MP int */
+  silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
+
+  /* Verify */
+  rsa_public_operation(key, &mp_tmp2, &mp_dst);
+
+  /* MP to data */
+  verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);
+
+  /* Unpad data */
+  if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
+                        unpadded, sizeof(unpadded), &len)) {
+    memset(verify, 0, verify_len);
+    silc_free(verify);
+    silc_mp_uninit(&mp_tmp2);
+    silc_mp_uninit(&mp_dst);
+    return FALSE;
+  }
+
+  /* Hash data if requested */
+  if (hash) {
+    silc_hash_make(hash, data, data_len, hashr);
+    data = hashr;
+  }
+
+  /* Compare */
+  if (memcmp(data, unpadded, len))
+    ret = FALSE;
+
+  memset(verify, 0, verify_len);
+  memset(unpadded, 0, sizeof(unpadded));
+  silc_free(verify);
+  silc_mp_uninit(&mp_tmp2);
+  silc_mp_uninit(&mp_dst);
+  if (hash)
+    memset(hashr, 0, sizeof(hashr));
+
+  return ret;
+}
index 9b113297a06a5a2e959065f82fe427a36cba1bba..30cee1cd6b8aa1e2e74625e6862c2b7aa0114dc6 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2003 Pekka Riikonen
+  Copyright (C) 2003 - 2005 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
@@ -78,11 +78,11 @@ typedef enum {
  *
  ***/
 SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
-                      const unsigned char *data,
-                      SilcUInt32 data_len,
-                      unsigned char *dest_data,
-                      SilcUInt32 dest_data_size,
-                      SilcRng rng);
+                          const unsigned char *data,
+                          SilcUInt32 data_len,
+                          unsigned char *dest_data,
+                          SilcUInt32 dest_data_size,
+                          SilcRng rng);
 
 /****f* silccrypt/SilcPKCS1API/silc_pkcs1_decode
  *
@@ -106,10 +106,10 @@ SilcBool silc_pkcs1_encode(SilcPkcs1BlockType bt,
  *
  ***/
 SilcBool silc_pkcs1_decode(SilcPkcs1BlockType bt,
-                      const unsigned char *data,
-                      SilcUInt32 data_len,
-                      unsigned char *dest_data,
-                      SilcUInt32 dest_data_size,
-                      SilcUInt32 *dest_len);
+                          const unsigned char *data,
+                          SilcUInt32 data_len,
+                          unsigned char *dest_data,
+                          SilcUInt32 dest_data_size,
+                          SilcUInt32 *dest_len);
 
 #endif /* SILCPKCS1_H */
diff --git a/lib/silccrypt/silcpkcs1_i.h b/lib/silccrypt/silcpkcs1_i.h
new file mode 100644 (file)
index 0000000..6c05049
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+
+  silcpkcs1_i.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C); 2006 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 SILCPKCS1_I_H
+#define SILCPKCS1_I_H
+
+SilcBool silc_pkcs1_generate_key(SilcUInt32 keylen,
+                                SilcRng rng,
+                                void **ret_public_key,
+                                void **ret_private_key);
+SilcBool silc_pkcs1_import_public_key(unsigned char *key,
+                                     SilcUInt32 key_len,
+                                     void **ret_public_key);
+unsigned char *silc_pkcs1_export_public_key(void *public_key,
+                                           SilcUInt32 *ret_len);
+SilcUInt32 silc_pkcs1_public_key_bitlen(void *public_key);
+void *silc_pkcs1_public_key_copy(void *public_key);
+SilcBool silc_pkcs1_public_key_compare(void *key1, void *key2);
+void silc_pkcs1_public_key_free(void *public_key);
+SilcBool silc_pkcs1_import_private_key(unsigned char *key,
+                                      SilcUInt32 key_len,
+                                      void **ret_private_key);
+unsigned char *silc_pkcs1_export_private_key(void *private_key,
+                                            SilcUInt32 *ret_len);
+SilcUInt32 silc_pkcs1_private_key_bitlen(void *private_key);
+void silc_pkcs1_private_key_free(void *private_key);
+SilcBool silc_pkcs1_encrypt(void *public_key,
+                           unsigned char *src,
+                           SilcUInt32 src_len,
+                           unsigned char *dst,
+                           SilcUInt32 dst_size,
+                           SilcUInt32 *ret_dst_len);
+SilcBool silc_pkcs1_decrypt(void *private_key,
+                           unsigned char *src,
+                           SilcUInt32 src_len,
+                           unsigned char *dst,
+                           SilcUInt32 dst_size,
+                           SilcUInt32 *ret_dst_len);
+SilcBool silc_pkcs1_sign(void *private_key,
+                        unsigned char *src,
+                        SilcUInt32 src_len,
+                        unsigned char *signature,
+                        SilcUInt32 signature_size,
+                        SilcUInt32 *ret_signature_len,
+                        SilcHash hash);
+SilcBool silc_pkcs1_verify(void *public_key,
+                          unsigned char *signature,
+                          SilcUInt32 signature_len,
+                          unsigned char *data,
+                          SilcUInt32 data_len,
+                          SilcHash hash);
+SilcBool silc_pkcs1_sign_no_oid(void *private_key,
+                               unsigned char *src,
+                               SilcUInt32 src_len,
+                               unsigned char *signature,
+                               SilcUInt32 signature_size,
+                               SilcUInt32 *ret_signature_len,
+                               SilcHash hash);
+SilcBool silc_pkcs1_verify_no_oid(void *public_key,
+                                 unsigned char *signature,
+                                 SilcUInt32 signature_len,
+                                 unsigned char *data,
+                                 SilcUInt32 data_len,
+                                 SilcHash hash);
+
+#endif /* SILCPKCS1_I_H */
index 02b7e941024cd3f4be9d24101e9402c36accffc6..76f90e7784ab4696be9c2c46558aadca6c12f068 100644 (file)
@@ -34,6 +34,8 @@ unsigned char *silc_mp_mp2bin(SilcMPInt *val, SilcUInt32 len,
 
   size = (len ? len : ((silc_mp_sizeinbase(val, 2) + 7) / 8));
   ret = silc_calloc(size, sizeof(*ret));
+  if (!ret)
+    return NULL;
 
   silc_mp_init(&tmp);
   silc_mp_set(&tmp, val);
index b1b59d19440f6500e40381dc2cf4fc7d2d05167e..08a08c0c00d149e67a88b1c5bc652c7e9b601207 100644 (file)
@@ -1,15 +1,15 @@
 /*
 
   silcmath.h
+
   Author: Pekka Riikonen <priikone@silcnet.org>
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+
+  Copyright (C) 1997 - 2005 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
  *
  * SYNOPSIS
  *
- *    int silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits, SilcBool verbose,
- *                            SilcRng);
+ *    SilcBool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits,
+ *                                 SilcBool verbose, SilcRng rng);
  *
  * DESCRIPTION
  *
- *    Find appropriate prime. It generates a number by taking random bytes. 
- *    It then tests the number that it's not divisible by any of the small 
- *    primes and then it performs Fermat's prime test. I thank Rieks Joosten 
- *    (r.joosten@pijnenburg.nl) for such a good help with prime tests. 
+ *    Find appropriate prime. It generates a number by taking random bytes.
+ *    It then tests the number that it's not divisible by any of the small
+ *    primes and then it performs Fermat's prime test. I thank Rieks Joosten
+ *    (r.joosten@pijnenburg.nl) for such a good help with prime tests.
  *
  *    If argument verbose is TRUE this will display some status information
  *    about the progress of generation.  If the `rng' is NULL then global
@@ -63,7 +63,7 @@ SilcBool silc_math_gen_prime(SilcMPInt *prime, SilcUInt32 bits,
  *
  * DESCRIPTION
  *
- *    Performs primality testings for given number. Returns TRUE if the 
+ *    Performs primality testings for given number. Returns TRUE if the
  *    number is probably a prime.
  *
  ***/
index 4b7bff9fdb9a537b86cf32bf55f510367ca12ebf..aaff041274be97127ee878f6258d72e27daa54da 100644 (file)
@@ -662,7 +662,7 @@ unsigned char *silc_mp_mp2bin(SilcMPInt *val, SilcUInt32 len,
  * DESCRIPTION
  *
  *    Same as silc_mp_mp2bin but does not allocate any memory.  The
- *    encoded data is returned into `dst' and it's length to the `ret_len'.
+ *    encoded data is returned into `dst' of size of `dst_len'.
  *
  ***/
 void silc_mp_mp2bin_noalloc(SilcMPInt *val, unsigned char *dst,
index cf325a44e3c81da3db6b52abac6ef1de29571240..974e14d9572057cdf97b65ccd23d6a3420ec8499 100644 (file)
@@ -634,13 +634,6 @@ SilcServer silc_server_alloc(void *app_context, SilcServerParams params,
   server->params->server_info->public_key = NULL;
   server->params->server_info->private_key = NULL;
 
-  /* Allocate PKCS context for local public and private keys */
-  if (!silc_pkcs_alloc(server->public_key->name, SILC_PKCS_SILC,
-                      &server->pkcs))
-    goto err;
-  silc_pkcs_public_key_set(server->pkcs, server->public_key);
-  silc_pkcs_private_key_set(server->pkcs, server->private_key);
-
   /* Create network listener(s) */
   server->listeners = silc_dlist_init();
   if (!server->listeners)
index 5e1b90e987279ec704ca1b477d6963fbd55cdeaa..64a971b6ddd375fcc0acdb0ff59d03d77fef8428 100644 (file)
@@ -330,7 +330,6 @@ struct SilcServerStruct {
   SilcUInt16 cmd_ident;
 
   /* Server public key */
-  SilcPKCS pkcs;
   SilcPublicKey public_key;
   SilcPrivateKey private_key;
 
index 38e4acdcc6b1063f92c30d76f4bb976fe53cdf2d..b6e638842840f9a830b97d0bf3ea45dc56de8835 100644 (file)
@@ -27,9 +27,8 @@
 
 static void
 silc_server_accept_verify_key(SilcSKE ske,
-                             const unsigned char *pk_data,
-                             SilcUInt32 pk_len,
                              SilcSKEPKType pk_type,
+                             SilcPublicKey public_key,
                              void *context,
                              SilcSKEVerifyCbCompletion completion,
                              void *completion_context)
index 36c3d9ea7ff95cd948f10960d6e6b56f2c4b63e6..70f5e2d0dcb9e62feca0db869e9f633abc96fce0 100644 (file)
@@ -183,8 +183,8 @@ void silc_server_command_free(SilcServerCommand cmd)
 
   silc_mutex_lock(thread->server->lock);
 
-  /* Check for double free */
 #if defined(SILC_DEBUG)
+  /* Check for double free */
   assert(cmd->packet != NULL);
 #endif /* SILC_DEBUG */
 
index 5fd7c34f6d53370a2899deb9b93dc44f30e0861c..83ddfd0686895d4411b75be508085c932a8b31ae 100644 (file)
@@ -451,7 +451,7 @@ SILC_FSM_STATE(silc_server_st_command_reply_getkey)
   tmp = silc_argument_get_arg_type(args, 3, &len);
   if (!tmp)
     goto out;
-  if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+  if (!silc_public_key_payload_decode(tmp, len, &public_key))
     goto out;
 
   /* Store the public key */
index dc1e6d575cd1f30fa1f95cd613680610ad7293c5..765e71261cab3d78c29408e4ae2598fde3a8ab8f 100644 (file)
@@ -303,14 +303,6 @@ SILC_FSM_STATE(silc_server_st_packet_received)
     return SILC_FSM_CONTINUE;
     break;
 
-  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
-    /** Packet CONNECTION_AUTH_REQUEST */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_fsm_next(fsm, silc_server_st_packet_connection_auth_request);
-    return SILC_FSM_CONTINUE;
-    break;
-
   case SILC_PACKET_HEARTBEAT:
   case SILC_PACKET_SUCCESS:
   case SILC_PACKET_FAILURE:
index 5c27a3eee7dc22c5ea8751ef3caafa78fb2cc7b5..a1953a64fae8e660eeffa104d563dbb3de1ea0b1 100644 (file)
@@ -26,7 +26,7 @@ int main(int argc, char **argv)
   if (argc > 1 && !strcmp(argv[1], "-d")) {
     silc_log_debug(TRUE);
     silc_log_debug_hexdump(TRUE);
-    silc_log_set_debug_string("*server*,*skr*,*ske*,*connauth*,*packet*,*stream*,*net*");
+    silc_log_set_debug_string("*server*,*skr*,*ske*,*connauth*,*packet*,*stream*,*net*,*pkcs*,*asn1*");
   }
 
   SILC_LOG_DEBUG(("Allocating scheduler"));
@@ -49,11 +49,10 @@ int main(int argc, char **argv)
     goto err;
   info->server_name = strdup("test server");
 
-  if (!silc_load_key_pair("test.pub", "test.prv", "", NULL,
+  if (!silc_load_key_pair("test.pub", "test.prv", "",
                          &info->public_key,
                          &info->private_key)) {
     if (!silc_create_key_pair("rsa", 2048, "test.pub", "test.prv", NULL, "",
-                             NULL,
                              &info->public_key,
                              &info->private_key, FALSE)) {
       goto err;
index c230e36b72ed4a7b820d58aa1296d2316c7228d2..c0e8d7f153392b7a95b077defe7e538cbba654c3 100644 (file)
@@ -224,7 +224,7 @@ silc_ske_select_security_properties(SilcSKE ske,
 
       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
 
-      if (silc_pkcs_is_supported(item) == TRUE) {
+      if (silc_pkcs_find_algorithm(item, NULL)) {
        SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
 
        payload->pkcs_alg_len = len;
@@ -635,6 +635,8 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
       return SILC_SKE_STATUS_ERROR;
     }
 
+    SILC_LOG_HEXDUMP(("hash buf"), buf->data, silc_buffer_len(buf));
+
     memset(e, 0, e_len);
     silc_free(e);
   }
@@ -707,8 +709,6 @@ void silc_ske_free(SilcSKE ske)
     if (ske->prop) {
       if (ske->prop->group)
        silc_ske_group_free(ske->prop->group);
-      if (ske->prop->pkcs)
-       silc_pkcs_free(ske->prop->pkcs);
       if (ske->prop->cipher)
        silc_cipher_free(ske->prop->cipher);
       if (ske->prop->hash)
@@ -876,8 +876,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1)
 
   prop->group = group;
 
-  if (silc_pkcs_alloc(payload->pkcs_alg_list, ske->pk_type,
-                     &prop->pkcs) == FALSE) {
+  if (silc_pkcs_find_algorithm(payload->pkcs_alg_list, NULL) == NULL) {
     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
     goto err;
   }
@@ -907,8 +906,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1)
 
   silc_ske_group_free(group);
 
-  if (prop->pkcs)
-    silc_pkcs_free(prop->pkcs);
   if (prop->cipher)
     silc_cipher_free(prop->cipher);
   if (prop->hash)
@@ -1016,10 +1013,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase2)
     SILC_LOG_DEBUG(("Signing HASH_i value"));
 
     /* Sign the hash value */
-    silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv,
-                                  ske->private_key->prv_len);
-    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
-       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
+    if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign,
+                       sizeof(sign) - 1, &sign_len, NULL)) {
       /** Error computing signature */
       silc_mp_uninit(x);
       silc_free(x);
@@ -1106,14 +1101,24 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase3)
   silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
   ske->KEY = KEY;
 
-  if (payload->pk_data && ske->callbacks->verify_key) {
+  /* Decode the remote's public key */
+  if (payload->pk_data &&
+      !silc_pkcs_public_key_alloc(payload->pk_type,
+                                 payload->pk_data, payload->pk_len,
+                                 &ske->prop->public_key)) {
+    SILC_LOG_ERROR(("Unsupported/malformed public key received"));
+    status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+    goto err;
+  }
+
+  if (ske->prop->public_key && ske->callbacks->verify_key) {
     SILC_LOG_DEBUG(("Verifying public key"));
 
     /** Waiting public key verification */
     silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
-    SILC_FSM_CALL(ske->callbacks->verify_key(ske, payload->pk_data,
-                                            payload->pk_len,
+    SILC_FSM_CALL(ske->callbacks->verify_key(ske,
                                             payload->pk_type,
+                                            ske->prop->public_key,
                                             ske->callbacks->context,
                                             silc_ske_pk_verified, NULL));
     /* NOT REACHED */
@@ -1149,7 +1154,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4)
   SilcSKEKEPayload payload;
   unsigned char hash[SILC_HASH_MAXLEN];
   SilcUInt32 hash_len;
-  SilcPublicKey public_key = NULL;
   int key_len, block_len;
 
   if (ske->aborted) {
@@ -1168,15 +1172,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4)
 
   payload = ske->ke2_payload;
 
-  if (payload->pk_data) {
-    /* Decode the public key */
-    if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
-                                    &public_key)) {
-      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
-      status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
-      goto err;
-    }
-
+  if (ske->prop->public_key) {
     SILC_LOG_DEBUG(("Public key is authentic"));
 
     /* Compute the hash value */
@@ -1190,9 +1186,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4)
     SILC_LOG_DEBUG(("Verifying signature (HASH)"));
 
     /* Verify signature */
-    silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
-    if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
-                        payload->sign_len, hash, hash_len) == FALSE) {
+    if (!silc_pkcs_verify(ske->prop->public_key, payload->sign_data,
+                        payload->sign_len, hash, hash_len, NULL)) {
       SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
       status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
       goto err;
@@ -1200,7 +1195,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4)
 
     SILC_LOG_DEBUG(("Signature is Ok"));
 
-    silc_pkcs_public_key_free(public_key);
     memset(hash, 'F', hash_len);
   }
 
@@ -1234,9 +1228,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4)
   silc_free(ske->KEY);
   ske->KEY = NULL;
 
-  if (public_key)
-    silc_pkcs_public_key_free(public_key);
-
   if (ske->hash) {
     memset(ske->hash, 'F', hash_len);
     silc_free(ske->hash);
@@ -1475,8 +1466,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2)
   /* XXX these shouldn't be allocated before we know the remote's
      public key type.  It's unnecessary to allocate these because the
      select_security_properties has succeeded already. */
-  if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list,
-                     SILC_PKCS_SILC, &prop->pkcs) == FALSE) {
+  if (!silc_pkcs_find_algorithm(ske->start_payload->pkcs_alg_list, NULL)) {
     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
     goto err;
   }
@@ -1517,8 +1507,6 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2)
   if (group)
     silc_ske_group_free(group);
 
-  if (prop->pkcs)
-    silc_pkcs_free(prop->pkcs);
   if (prop->cipher)
     silc_cipher_free(prop->cipher);
   if (prop->hash)
@@ -1590,14 +1578,27 @@ SILC_FSM_STATE(silc_ske_st_responder_phase3)
       return SILC_FSM_CONTINUE;
     }
 
-    if (recv_payload->pk_data && ske->callbacks->verify_key) {
+    /* Decode the remote's public key */
+    if (recv_payload->pk_data &&
+       !silc_pkcs_public_key_alloc(recv_payload->pk_type,
+                                   recv_payload->pk_data,
+                                   recv_payload->pk_len,
+                                   &ske->prop->public_key)) {
+      /** Error decoding public key */
+      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
+      ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
+    }
+
+    if (ske->prop->public_key && ske->callbacks->verify_key) {
       SILC_LOG_DEBUG(("Verifying public key"));
 
       /** Waiting public key verification */
       silc_fsm_next(fsm, silc_ske_st_responder_phase4);
-      SILC_FSM_CALL(ske->callbacks->verify_key(ske, recv_payload->pk_data,
-                                              recv_payload->pk_len,
+      SILC_FSM_CALL(ske->callbacks->verify_key(ske,
                                               recv_payload->pk_type,
+                                              ske->prop->public_key,
                                               ske->callbacks->context,
                                               silc_ske_pk_verified, NULL));
       /* NOT REACHED */
@@ -1638,21 +1639,9 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4)
      Authentication flag is set. */
   if (ske->start_payload &&
       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    SilcPublicKey public_key = NULL;
     unsigned char hash[SILC_HASH_MAXLEN];
     SilcUInt32 hash_len;
 
-    /* Decode the public key */
-    if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
-                                    recv_payload->pk_len,
-                                    &public_key)) {
-      /** Error decoding public key */
-      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
-      ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
-
     SILC_LOG_DEBUG(("Public key is authentic"));
 
     /* Compute the hash value */
@@ -1667,9 +1656,8 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4)
     SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
 
     /* Verify signature */
-    silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
-    if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
-                        recv_payload->sign_len, hash, hash_len) == FALSE) {
+    if (!silc_pkcs_verify(ske->prop->public_key, recv_payload->sign_data,
+                         recv_payload->sign_len, hash, hash_len, NULL)) {
       /** Incorrect signature */
       SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
       ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
@@ -1679,7 +1667,6 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4)
 
     SILC_LOG_DEBUG(("Signature is Ok"));
 
-    silc_pkcs_public_key_free(public_key);
     memset(hash, 'F', hash_len);
   }
 
@@ -1769,10 +1756,8 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5)
     SILC_LOG_DEBUG(("Signing HASH value"));
 
     /* Sign the hash value */
-    silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv,
-                                  ske->private_key->prv_len);
-    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
-       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
+    if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign,
+                       sizeof(sign) - 1, &sign_len, NULL)) {
       /** Error computing signature */
       status = SILC_SKE_STATUS_SIGNATURE_ERROR;
       silc_fsm_next(fsm, silc_ske_st_responder_error);
index 6efd1d4577d08d9d0dc2ce897fd72cbe39fb4bed..ffe9f7c4d521ca7fa9eb3ac933b8ab9e5539e616 100644 (file)
@@ -121,8 +121,7 @@ typedef struct {
   SilcCipher cipher;                    /* Selected cipher */
   SilcHmac hmac;                        /* Selected HMAC */
   SilcHash hash;                        /* Selected hash algorithm */
-  SilcPKCS pkcs;                        /* Selected PKCS and remote's
-                                           public key/certificate */
+  SilcPublicKey public_key;              /* Remote public key */
 } *SilcSKESecurityProperties;
 /***/
 
@@ -229,9 +228,8 @@ typedef void (*SilcSKEVerifyCbCompletion)(SilcSKE ske,
  * SYNOPSIS
  *
  *    typedef void (*SilcSKEVerifyCb)(SilcSKE ske,
- *                                    const unsigned char *pk_data,
- *                                    SilcUInt32 pk_len,
  *                                    SilcSKEPKType pk_type,
+ *                                    SilcPublicKey public_key,
  *                                    void *context,
  *                                    SilcSKEVerifyCbCompletion completion,
  *                                    void *completion_context);
@@ -247,9 +245,8 @@ typedef void (*SilcSKEVerifyCbCompletion)(SilcSKE ske,
  *
  ***/
 typedef void (*SilcSKEVerifyCb)(SilcSKE ske,
-                               const unsigned char *pk_data,
-                               SilcUInt32 pk_len,
                                SilcSKEPKType pk_type,
+                               SilcPublicKey public_key,
                                void *context,
                                SilcSKEVerifyCbCompletion completion,
                                void *completion_context);
index 1d17c62fd892550144df7fda7a0a5ecdc0568584..8efc9ca71845b066985076371bd3b2a72348c397 100644 (file)
@@ -82,8 +82,7 @@ static void silc_skr_type_string(SilcSKRFindType type, void *data,
     break;
 
   case SILC_SKR_FIND_PUBLIC_KEY:
-    snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
-            ((SilcPublicKey)data)->identifier);
+    snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data);
     break;
 
   default:
@@ -131,18 +130,11 @@ static void silc_skr_destructor(void *key, void *context, void *user_context)
 
   /* Destroy key */
   entry->refcnt--;
-  if (entry->refcnt == 0) {
-    switch (entry->key.pk_type) {
-    case SILC_PKCS_SILC:
-      silc_pkcs_public_key_free(entry->key.key);
-      break;
-
-    default:
-      break;
-    }
+  if (entry->refcnt > 0)
+    return;
 
-    silc_free(entry);
-  }
+  silc_pkcs_public_key_free(entry->key.key);
+  silc_free(entry);
 }
 
 /* Hash table hash function for key entries */
@@ -285,11 +277,16 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
                                       SilcSKRKeyUsage usage,
                                       void *key_context)
 {
-  SilcPublicKeyIdentifier ident = NULL;
   SilcSKRKeyInternal key;
   SilcSKRStatus status = SILC_SKR_ERROR;
+  SilcPublicKeyIdentifier ident;
+  SilcSILCPublicKey silc_pubkey;
+
+  /* Get the SILC public key */
+  silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
+  ident = &silc_pubkey->identifier;
 
-  SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier));
+  SILC_LOG_DEBUG(("Adding SILC public key [%s]", ident->username));
 
   silc_mutex_lock(skr->lock);
 
@@ -298,7 +295,7 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
                          public_key, NULL, key_context, 0)) {
     silc_mutex_unlock(skr->lock);
     SILC_LOG_DEBUG(("Key already added"));
-    return status;
+    return status | SILC_SKR_ALREADY_EXIST;
   }
 
   /* Allocate key entry */
@@ -309,17 +306,9 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
   }
 
   key->key.usage = usage;
-  key->key.pk_type = public_key->pk_type;
   key->key.key = public_key;
   key->key.key_context = key_context;
 
-  ident = silc_pkcs_decode_identifier(public_key->identifier);
-  if (!ident) {
-    silc_mutex_unlock(skr->lock);
-    silc_pkcs_free_identifier(ident);
-    return status | SILC_SKR_NO_MEMORY;
-  }
-
   /* Add key specifics */
 
   if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
@@ -328,7 +317,7 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
   key->refcnt++;
 
   if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
-                         SILC_32_TO_PTR(public_key->pk_type), key))
+                         SILC_32_TO_PTR(SILC_PKCS_SILC), key))
     goto err;
   key->refcnt++;
 
@@ -383,12 +372,10 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
 
   silc_mutex_unlock(skr->lock);
 
-  silc_free(ident);
   return SILC_SKR_OK;
 
  err:
   silc_mutex_unlock(skr->lock);
-  silc_free(ident);
   return status;
 }
 
@@ -403,7 +390,7 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
   SilcSKRKeyInternal key;
   SilcSKRStatus status = SILC_SKR_ERROR;
 
-  SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier));
+  SILC_LOG_DEBUG(("Adding SILC public key"));
 
   silc_mutex_lock(skr->lock);
 
@@ -412,7 +399,7 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
                          public_key, NULL, key_context, 0)) {
     silc_mutex_unlock(skr->lock);
     SILC_LOG_DEBUG(("Key already added"));
-    return status;
+    return status | SILC_SKR_ALREADY_EXIST;
   }
 
   /* Allocate key entry */
@@ -423,7 +410,6 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
   }
 
   key->key.usage = usage;
-  key->key.pk_type = public_key->pk_type;
   key->key.key = public_key;
   key->key.key_context = key_context;
 
@@ -567,12 +553,16 @@ SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
                                      SilcSKRKeyUsage usage,
                                      void *key_context)
 {
+  SilcPKCSType type;
+
   if (!public_key)
     return SILC_SKR_ERROR;
 
+  type = silc_pkcs_get_type(public_key);
+
   SILC_LOG_DEBUG(("Adding public key to repository"));
 
-  switch (public_key->pk_type) {
+  switch (type) {
 
   case SILC_PKCS_SILC:
     return silc_skr_add_silc(skr, public_key, usage, key_context);
@@ -592,12 +582,16 @@ SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
                                             SilcSKRKeyUsage usage,
                                             void *key_context)
 {
+  SilcPKCSType type;
+
   if (!public_key)
     return SILC_SKR_ERROR;
 
+  type = silc_pkcs_get_type(public_key);
+
   SILC_LOG_DEBUG(("Adding public key to repository"));
 
-  switch (public_key->pk_type) {
+  switch (type) {
 
   case SILC_PKCS_SILC:
     return silc_skr_add_silc_simple(skr, public_key, usage, key_context);
@@ -809,36 +803,3 @@ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
 
   return NULL;
 }
-
-/* Helper function to find specificly SILC style public keys */
-
-SilcAsyncOperation silc_skr_find_silc(SilcSKR skr,
-                                     SilcPublicKey public_key,
-                                     SilcSKRFindCallback callback,
-                                     void *callback_context)
-{
-  SilcSKRFind find = NULL;
-  SilcAsyncOperation op;
-
-  SILC_LOG_DEBUG(("Finding SILC public key"));
-
-  if (!public_key || public_key->pk_type != SILC_PKCS_SILC)
-    goto err;
-
-  find = silc_skr_find_alloc();
-  if (!find)
-    goto err;
-
-  if (!silc_skr_find_set_public_key(find, public_key))
-    goto err;
-
-  op = silc_skr_find(skr, find, callback, callback_context);
-
-  return op;
-
- err:
-  if (find)
-    silc_skr_find_free(find);
-  callback(skr, NULL, SILC_SKR_ERROR, NULL, callback_context);
-  return NULL;
-}
index a2e9abfd65cfec19248e3dbdeac60400f5afe398..c0ede323a1dfcc68ed39abe2d5268ee80064c267 100644 (file)
@@ -95,26 +95,20 @@ typedef enum {
  *
  * NAME
  *
- *    typedef struct SilcSKRKeyStruct { ... } *SilcSKRKey
+ *    typedef struct SilcSKRKeyStruct { ... } *SilcSKRKey;
  *
  * DESCRIPTION
  *
- *    This context holds the public key cryptosystem key type and the key
- *    context that has been saved in the key repository.  This context is
- *    returned in the SilcSKRFindCallback list.  Each entry in the list is
- *    SilcSKRKey.
- *
- *    The key context saved in SilcSKRKey is based on the PKCS type and
- *    caller can explicitly type cast the key to correct type based on the
- *    PKCS type.
+ *    This context holds the public key, optional public key specific
+ *    context and public key usage bits.  This context is returned in
+ *    the SilcSKRFindCallback list.  Each entry in the list is SIlcSKRKey.
  *
  * SOURCE
  *
  */
 typedef struct SilcSKRKeyStruct {
   SilcSKRKeyUsage usage;       /* Key usage */
-  SilcPKCSType pk_type;                /* PKCS type */
-  void *key;                   /* SILC_PKCS_SILC: SilcPublicKey */
+  SilcPublicKey key;           /* Public key */
   void *key_context;           /* Optional key specific context */
 } *SilcSKRKey;
 /***/
@@ -251,7 +245,7 @@ void silc_skr_uninit(SilcSKR skr);
  *
  *    // Add a key to repository
  *    if (silc_skr_add_public_key(repository, public_key,
- *                                SILC_SKR_USAGW_ANY, NULL) != SILC_SKR_OK)
+ *                                SILC_SKR_USAGE_ANY, NULL) != SILC_SKR_OK)
  *      goto error;
  *
  ***/
@@ -494,39 +488,14 @@ SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage);
  *    `find'.  As the finding procedure may be asynchronous this returns
  *    SilcAsyncOperation that may be used to control (like abort) the
  *    operation.  The `callback' with `callback_context' will be called
- *    to return found keys.  If this returns NULL, operation cannot be
- *    controlled, however it is not an error.
+ *    to return found keys.  If this returns NULL the finding was not
+ *    asynchronous, and the `callback' has been called already.
  *
  ***/
 SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
                                 SilcSKRFindCallback callback,
                                 void *callback_context);
 
-/****f* silcskr/SilcSKRAPI/silc_skr_find_silc
- *
- * SYNOPSIS
- *
- *    SilcAsyncOperation silc_skr_find_silc(SilcSKR skr,
- *                                          SilcPublicKey public_key,
- *                                          SilcSKRFindCallback callback,
- *                                          void *callback_context);
- *
- * DESCRIPTION
- *
- *    A helper function that can be used to find specificly SILC style
- *    public keys from the repository.  This returns found key(s) by
- *    the `public_key'.  As the finding procedure may be asynchronous
- *    this returns SilcAsyncOperation that may be used to control (like
- *    abort) the operation.  The `callback' with `callback_context' will
- *    be called to return found keys.  If this returns NULL, operation
- *    cannot be controlled, however it is not an error.
- *
- ***/
-SilcAsyncOperation silc_skr_find_silc(SilcSKR skr,
-                                     SilcPublicKey public_key,
-                                     SilcSKRFindCallback callback,
-                                     void *callback_context);
-
 #include "silcskr_i.h"
 
 #endif /* SILCSKR_H */
index d1d6739ff751b56e8f8173e93273d18a21f9b1cb..ff85ccf16e752a6a54e646af2ee03b397348f5a2 100644 (file)
@@ -42,8 +42,8 @@ static char *silc_create_pk_identifier(void)
   /* Create default email address, whether it is right or not */
   snprintf(email, sizeof(email), "%s@%s", username, hostname);
 
-  ident = silc_pkcs_encode_identifier(username, hostname, realname, email,
-                                     NULL, NULL);
+  ident = silc_pkcs_silc_encode_identifier(username, hostname, realname,
+                                          email, NULL, NULL);
   if (realname)
     silc_free(realname);
   silc_free(hostname);
@@ -55,22 +55,16 @@ static char *silc_create_pk_identifier(void)
 /* Generate key pair */
 
 SilcBool silc_create_key_pair(const char *pkcs_name,
-                         SilcUInt32 key_len_bits,
-                         const char *pub_filename,
-                         const char *prv_filename,
-                         const char *pub_identifier,
-                         const char *passphrase,
-                         SilcPKCS *return_pkcs,
-                         SilcPublicKey *return_public_key,
-                         SilcPrivateKey *return_private_key,
-                         SilcBool interactive)
+                             SilcUInt32 key_len_bits,
+                             const char *pub_filename,
+                             const char *prv_filename,
+                             const char *pub_identifier,
+                             const char *passphrase,
+                             SilcPublicKey *return_public_key,
+                             SilcPrivateKey *return_private_key,
+                             SilcBool interactive)
 {
-  SilcPKCS pkcs;
-  SilcPublicKey pub_key;
-  SilcPrivateKey prv_key;
   SilcRng rng;
-  unsigned char *key;
-  SilcUInt32 key_len;
   char line[256];
   char *pkfile = pub_filename ? strdup(pub_filename) : NULL;
   char *prvfile = prv_filename ? strdup(prv_filename) : NULL;
@@ -103,7 +97,7 @@ New pair of keys will be created.  Please, answer to following questions.\n\
     }
   }
 
-  if (!silc_pkcs_is_supported(alg)) {
+  if (!silc_pkcs_find_algorithm(alg, NULL)) {
     fprintf(stderr, "Unknown PKCS algorithm `%s' or crypto library"
            "is not initialized", alg);
     return FALSE;
@@ -197,34 +191,18 @@ New pair of keys will be created.  Please, answer to following questions.\n\
   }
 
   /* Generate keys */
-  silc_pkcs_alloc(alg, SILC_PKCS_SILC, &pkcs);
-  silc_pkcs_generate_key(pkcs, key_len_bits, rng);
+  if (!silc_pkcs_silc_generate_key(alg, "pkcs1-no-oid", key_len_bits,
+                                  identifier, rng, return_public_key,
+                                  return_private_key))
+    return FALSE;
 
   /* Save public key into file */
-  key = silc_pkcs_get_public_key(pkcs, &key_len);
-  pub_key = silc_pkcs_public_key_alloc(silc_pkcs_get_name(pkcs),
-                                      identifier, key, key_len);
-  silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
-  if (return_public_key)
-    *return_public_key = pub_key;
-  else
-    silc_pkcs_public_key_free(pub_key);
-  memset(key, 0, key_len);
-  silc_free(key);
+  silc_pkcs_save_public_key(pkfile, *return_public_key, SILC_PKCS_FILE_BASE64);
 
   /* Save private key into file */
-  key = silc_pkcs_get_private_key(pkcs, &key_len);
-  prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
-                                       key, key_len);
-  silc_pkcs_save_private_key(prvfile, prv_key,
-                            (unsigned char *)pass, strlen(pass),
-                            SILC_PKCS_FILE_BIN);
-  if (return_private_key)
-    *return_private_key = prv_key;
-  else
-    silc_pkcs_private_key_free(prv_key);
-  memset(key, 0, key_len);
-  silc_free(key);
+  silc_pkcs_save_private_key(prvfile, *return_private_key,
+                            (const unsigned char *)pass, strlen(pass),
+                            SILC_PKCS_FILE_BIN, rng);
 
   printf("Public key has been saved into `%s'.\n", pkfile);
   printf("Private key has been saved into `%s'.\n", prvfile);
@@ -233,11 +211,6 @@ New pair of keys will be created.  Please, answer to following questions.\n\
     getchar();
   }
 
-  if (return_pkcs)
-    *return_pkcs = pkcs;
-  else
-    silc_pkcs_free(pkcs);
-
   silc_rng_free(rng);
   silc_free(alg);
   silc_free(pkfile);
@@ -252,25 +225,21 @@ New pair of keys will be created.  Please, answer to following questions.\n\
 /* Load key pair */
 
 SilcBool silc_load_key_pair(const char *pub_filename,
-                       const char *prv_filename,
-                       const char *passphrase,
-                       SilcPKCS *return_pkcs,
-                       SilcPublicKey *return_public_key,
-                       SilcPrivateKey *return_private_key)
+                           const char *prv_filename,
+                           const char *passphrase,
+                           SilcPublicKey *return_public_key,
+                           SilcPrivateKey *return_private_key)
 {
   char *pass = passphrase ? strdup(passphrase) : NULL;
 
   SILC_LOG_DEBUG(("Loading public and private keys"));
 
-  if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
-                               SILC_PKCS_FILE_PEM) == FALSE)
-    if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
-                                 SILC_PKCS_FILE_BIN) == FALSE) {
-      if (pass)
-       memset(pass, 0, strlen(pass));
-      silc_free(pass);
-      return FALSE;
-    }
+  if (!silc_pkcs_load_public_key(pub_filename, return_public_key)) {
+    if (pass)
+      memset(pass, 0, strlen(pass));
+    silc_free(pass);
+    return FALSE;
+  }
 
   if (!pass) {
     pass = silc_get_input("Private key passphrase: ", TRUE);
@@ -278,21 +247,12 @@ SilcBool silc_load_key_pair(const char *pub_filename,
       pass = strdup("");
   }
 
-  if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
-                                (unsigned char *)pass, strlen(pass),
-                                SILC_PKCS_FILE_BIN) == FALSE)
-    if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
-                                  (unsigned char *)pass, strlen(pass),
-                                  SILC_PKCS_FILE_PEM) == FALSE) {
-      memset(pass, 0, strlen(pass));
-      silc_free(pass);
-      return FALSE;
-    }
-
-  if (return_pkcs) {
-    silc_pkcs_alloc((*return_public_key)->name, SILC_PKCS_SILC, return_pkcs);
-    silc_pkcs_public_key_set(*return_pkcs, *return_public_key);
-    silc_pkcs_private_key_set(*return_pkcs, *return_private_key);
+  if (!silc_pkcs_load_private_key(prv_filename,
+                                 (const unsigned char *)pass, strlen(pass),
+                                 return_private_key)) {
+    memset(pass, 0, strlen(pass));
+    silc_free(pass);
+    return FALSE;
   }
 
   memset(pass, 0, strlen(pass));
@@ -305,34 +265,36 @@ SilcBool silc_load_key_pair(const char *pub_filename,
 SilcBool silc_show_public_key(const char *pub_filename)
 {
   SilcPublicKey public_key;
+  SilcSILCPublicKey silc_pubkey;
   SilcPublicKeyIdentifier ident;
   char *fingerprint, *babbleprint;
   unsigned char *pk;
   SilcUInt32 pk_len;
-  SilcPKCS pkcs;
   SilcUInt32 key_len = 0;
 
-  if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
-                               SILC_PKCS_FILE_PEM) == FALSE)
-    if (silc_pkcs_load_public_key((char *)pub_filename, &public_key,
-                                 SILC_PKCS_FILE_BIN) == FALSE) {
-      fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
-      return FALSE;
-    }
+  if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) {
+    fprintf(stderr, "Could not load public key file `%s'\n", pub_filename);
+    return FALSE;
+  }
 
-  ident = silc_pkcs_decode_identifier(public_key->identifier);
+  silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
+  if (!silc_pubkey) {
+    silc_pkcs_public_key_free(public_key);
+    return FALSE;
+  }
 
+  ident = &silc_pubkey->identifier;
+  key_len = silc_pkcs_public_key_get_len(public_key);
   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  if (!pk) {
+    silc_pkcs_public_key_free(public_key);
+    return FALSE;
+  }
   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
 
-  if (silc_pkcs_alloc(public_key->name, SILC_PKCS_SILC, &pkcs)) {
-    key_len = silc_pkcs_public_key_set(pkcs, public_key);
-    silc_pkcs_free(pkcs);
-  }
-
   printf("Public key file    : %s\n", pub_filename);
-  printf("Algorithm          : %s\n", public_key->name);
+  printf("Algorithm          : %s\n", silc_pkcs_get_name(public_key));
   if (key_len)
     printf("Key length (bits)  : %d\n", (unsigned int)key_len);
   if (ident->realname)
@@ -356,7 +318,6 @@ SilcBool silc_show_public_key(const char *pub_filename)
   silc_free(babbleprint);
   silc_free(pk);
   silc_pkcs_public_key_free(public_key);
-  silc_pkcs_free_identifier(ident);
 
   return TRUE;
 }
@@ -364,12 +325,12 @@ SilcBool silc_show_public_key(const char *pub_filename)
 /* Change private key passphrase */
 
 SilcBool silc_change_private_key_passphrase(const char *prv_filename,
-                                       const char *old_passphrase,
-                                       const char *new_passphrase)
+                                           const char *old_passphrase,
+                                           const char *new_passphrase)
 {
   SilcPrivateKey private_key;
-  SilcBool base64 = FALSE;
   char *pass;
+  SilcRng rng;
 
   pass = old_passphrase ? strdup(old_passphrase) : NULL;
   if (!pass) {
@@ -378,18 +339,13 @@ SilcBool silc_change_private_key_passphrase(const char *prv_filename,
       pass = strdup("");
   }
 
-  if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
-                                (unsigned char *)pass, strlen(pass),
-                                SILC_PKCS_FILE_BIN) == FALSE) {
-    base64 = TRUE;
-    if (silc_pkcs_load_private_key((char *)prv_filename, &private_key,
-                                  (unsigned char *)pass, strlen(pass),
-                                  SILC_PKCS_FILE_PEM) == FALSE) {
-      memset(pass, 0, strlen(pass));
-      silc_free(pass);
-      fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
-      return FALSE;
-    }
+  if (!silc_pkcs_load_private_key(prv_filename,
+                                 (const unsigned char *)pass, strlen(pass),
+                                 &private_key)) {
+    memset(pass, 0, strlen(pass));
+    silc_free(pass);
+    fprintf(stderr, "Could not load private key `%s' file\n", prv_filename);
+    return FALSE;
   }
 
   memset(pass, 0, strlen(pass));
@@ -416,9 +372,12 @@ SilcBool silc_change_private_key_passphrase(const char *prv_filename,
     }
   }
 
+  rng = silc_rng_alloc();
+  silc_rng_init(rng);
+
   silc_pkcs_save_private_key((char *)prv_filename, private_key,
                             (unsigned char *)pass, strlen(pass),
-                            base64 ? SILC_PKCS_FILE_PEM : SILC_PKCS_FILE_BIN);
+                            SILC_PKCS_FILE_BIN, rng);
 
   fprintf(stdout, "\nPassphrase changed\n");
 
@@ -426,5 +385,7 @@ SilcBool silc_change_private_key_passphrase(const char *prv_filename,
   silc_free(pass);
 
   silc_pkcs_private_key_free(private_key);
+  silc_rng_free(rng);
+
   return TRUE;
 }
index 8b9039313f17acec81de992019a38708b01e17f9..fd1717359cc39201478183331c8d5d011fbead9c 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcapputil.h 
+  silcapputil.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002 - 2005 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
  * SYNOPSIS
  *
  *    SilcBool silc_create_key_pair(const char *pkcs_name,
- *                              SilcUInt32 key_len_bits,
- *                              const char *pub_filename,
- *                              const char *prv_filename,
- *                              const char *pub_identifier,
- *                              const char *passphrase,
- *                              SilcPKCS *return_pkcs,
- *                              SilcPublicKey *return_public_key,
- *                              SilcPrivateKey *return_private_key,
- *                              SilcBool interactive);
+ *                                  SilcUInt32 key_len_bits,
+ *                                  const char *pub_filename,
+ *                                  const char *prv_filename,
+ *                                  const char *pub_identifier,
+ *                                  const char *passphrase,
+ *                                  SilcPublicKey *return_public_key,
+ *                                  SilcPrivateKey *return_private_key,
+ *                                  SilcBool interactive);
  *
  * DESCRIPTION
  *
  *    private key file.  It is recommended that you would protect your
  *    private key file with a passphrase.
  *
- *    The routine returns FALSE if error occurs during key generation.
- *    Function returns TRUE when success and returns the created SilcPKCS
- *    object, which can be used to perform public key cryptography into
- *    `return_pkcs' pointer, created public key into `return_public_key',
- *    and created private key into `return_private_key' pointer.
- *
  *    If the `interactive' is TRUE then this asks the user (by blocking
  *    the process for input) some questions about key generation (like
  *    public key algorithm, key length, filenames, etc).  If all
  *
  ***/
 SilcBool silc_create_key_pair(const char *pkcs_name,
-                         SilcUInt32 key_len_bits,
-                         const char *pub_filename,
-                         const char *prv_filename,
-                         const char *pub_identifier,
-                         const char *passphrase,
-                         SilcPKCS *return_pkcs,
-                         SilcPublicKey *return_public_key,
-                         SilcPrivateKey *return_private_key,
-                         SilcBool interactive);
+                             SilcUInt32 key_len_bits,
+                             const char *pub_filename,
+                             const char *prv_filename,
+                             const char *pub_identifier,
+                             const char *passphrase,
+                             SilcPublicKey *return_public_key,
+                             SilcPrivateKey *return_private_key,
+                             SilcBool interactive);
 
 /****f* silcutil/SilcAppUtil/silc_load_key_pair
  *
  * SYNOPSIS
  *
  *    SilcBool silc_load_key_pair(const char *pub_filename,
- *                            const char *prv_filename,
- *                            const char *passphrase,
- *                            SilcPKCS *return_pkcs,
- *                            SilcPublicKey *return_public_key,
- *                            SilcPrivateKey *return_private_key);
+ *                                const char *prv_filename,
+ *                                const char *passphrase,
+ *                                SilcPublicKey *return_public_key,
+ *                                SilcPrivateKey *return_private_key);
  *
  * DESCRIPTION
  *
  *    This routine can be used to load the public key and private key
  *    from files.  This retuns FALSE it either of the key could not be
  *    loaded.  This function returns TRUE on success and returns the
- *    public key into `return_public_key' pointer, private key into
- *    `return_private_key' pointer and the SilcPKCS object to the
- *    `return_pkcs'.  The SilcPKCS can be used to perform public key
- *    cryptographic operations.  The `passphrase' is the passphrase
- *    which will be used to decrypt the private key file.
+ *    public key into `return_public_key' pointer and private key into
+ *    `return_private_key'.  The `passphrase' is the passphrase which
+ *    will be used to decrypt the private key file.
  *
  ***/
 SilcBool silc_load_key_pair(const char *pub_filename,
-                       const char *prv_filename,
-                       const char *passphrase,
-                       SilcPKCS *return_pkcs,
-                       SilcPublicKey *return_public_key,
-                       SilcPrivateKey *return_private_key);
+                           const char *prv_filename,
+                           const char *passphrase,
+                           SilcPublicKey *return_public_key,
+                           SilcPrivateKey *return_private_key);
 
 /****f* silcutil/SilcAppUtil/silc_show_public_key
  *
@@ -145,8 +133,8 @@ SilcBool silc_show_public_key(const char *pub_filename);
  * SYNOPSIS
  *
  *    SilcBool silc_change_private_key_passphrase(const char *prv_filename,
- *                                            const char *old_passphrase,
- *                                            const char *new_passphrase);
+ *                                                const char *old_passphrase,
+ *                                                const char *new_passphrase);
  *
  * DESCRIPTION
  *
@@ -157,7 +145,7 @@ SilcBool silc_show_public_key(const char *pub_filename);
  *
  ***/
 SilcBool silc_change_private_key_passphrase(const char *prv_filename,
-                                       const char *old_passphrase,
-                                       const char *new_passphrase);
+                                           const char *old_passphrase,
+                                           const char *new_passphrase);
 
 #endif /* SILCAPPUTIL_H */
index 86b2f850b3546b99cdfb13bba8c901881b2511db..e0e664fa344e1415d78f5a10c5fc5e1ef12adbb6 100644 (file)
@@ -593,14 +593,23 @@ SilcUInt32 silc_hash_data(void *key, void *user_context)
   return h;
 }
 
-/* Hashed SILC Public key. */
+/* Hash public key of any type. */
 
 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
 {
-  SilcPublicKey pk = (SilcPublicKey)key;
-  return (pk->len + (silc_hash_string(pk->name, NULL) ^
-                    silc_hash_string(pk->identifier, NULL) ^
-                    silc_hash_data(pk->pk, SILC_32_TO_PTR(pk->pk_len))));
+  SilcPublicKey public_key = key;
+  unsigned char *pk;
+  SilcUInt32 pk_len;
+  SilcUInt32 hash = 0;
+
+  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  if (!pk)
+    return hash;
+
+  hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len));
+  silc_free(pk);
+
+  return hash;
 }
 
 /* Compares two strings. It may be used as SilcHashTable comparison
@@ -633,7 +642,8 @@ SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
 
 /* Compare two Client ID's entirely and not just the hash from the ID. */
 
-SilcBool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
+SilcBool silc_hash_client_id_compare(void *key1, void *key2,
+                                    void *user_context)
 {
   return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
 }
@@ -660,7 +670,8 @@ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
 /* Compares two SILC Public keys. It may be used as SilcHashTable
    comparison function. */
 
-SilcBool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
+SilcBool silc_hash_public_key_compare(void *key1, void *key2,
+                                     void *user_context)
 {
   return silc_pkcs_public_key_compare(key1, key2);
 }
index 1e2a68eacfcabe8c3b34b38f04b4b0a044a3bdd4..2f7ca30687334e6bee77ce7ab83813a3c005b0b8 100644 (file)
@@ -290,7 +290,7 @@ SilcUInt32 silc_hash_data(void *key, void *user_context);
  *
  * DESCRIPTION
  *
- *    Hashed SILC Public key.
+ *    Hash public key of any type.
  *
  ***/
 SilcUInt32 silc_hash_public_key(void *key, void *user_context);