Added SILC Thread Queue API
[silc.git] / lib / silccrypt / silcpk.c
index 20b7c5e76bde31d11065224168f7f2289af82aae..42aada1c1b7c2d7f6c9c6c924a4d74100c79d332 100644 (file)
@@ -85,7 +85,8 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
     silc_free(privkey);
     return FALSE;
   }
-  (*ret_public_key)->pkcs = pkcs;
+  (*ret_public_key)->pkcs = (SilcPKCSObject *)pkcs;
+  (*ret_public_key)->alg = alg;
   (*ret_public_key)->public_key = pubkey;
 
   /* Allocate private key */
@@ -96,11 +97,12 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
     silc_free(*ret_public_key);
     return FALSE;
   }
-  (*ret_private_key)->pkcs = pkcs;
+  (*ret_private_key)->pkcs = (SilcPKCSObject *)pkcs;
+  (*ret_private_key)->alg = alg;
   (*ret_private_key)->private_key = privkey;
 
   /* Generate the algorithm key pair */
-  if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key,
+  if (!alg->generate_key(alg, bits_key_len, rng, &pubkey->public_key,
                         &privkey->private_key)) {
     silc_free(pubkey);
     silc_free(privkey);
@@ -124,7 +126,7 @@ SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
   int len;
 
   /* Protocol says that at least UN and HN must be provided as identifier */
-  if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) {
+  if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) {
     SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
                    "identifiers"));
     return FALSE;
@@ -196,7 +198,8 @@ SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
    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 *silc_pkcs_silc_encode_identifier(SilcStack stack,
+                                      char *username, char *host,
                                       char *realname, char *email,
                                       char *org, char *country,
                                       char *version)
@@ -204,74 +207,77 @@ char *silc_pkcs_silc_encode_identifier(char *username, char *host,
   SilcBufferStruct buf;
   char *identifier;
 
-  if (!username || !host)
+  if (!username || !host) {
+    SILC_LOG_ERROR(("Public key identifier is missing UN and/or HN"));
     return NULL;
-  if (strlen(username) < 3 || strlen(host) < 3)
+  }
+  if (strlen(username) < 1 || strlen(host) < 1)
     return NULL;
 
   memset(&buf, 0, sizeof(buf));
 
   if (username)
-    silc_buffer_format(&buf,
-                      SILC_STR_ADVANCE,
-                      SILC_STR_UI32_STRING("UN="),
-                      SILC_STR_UI32_STRING(username),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, &buf,
+                       SILC_STR_ADVANCE,
+                       SILC_STR_UI32_STRING("UN="),
+                       SILC_STR_UI32_STRING(username),
+                       SILC_STR_END);
 
   if (host)
-    silc_buffer_format(&buf,
-                      SILC_STR_ADVANCE,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("HN="),
-                      SILC_STR_UI32_STRING(host),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, &buf,
+                       SILC_STR_ADVANCE,
+                       SILC_STR_UI32_STRING(", "),
+                       SILC_STR_UI32_STRING("HN="),
+                       SILC_STR_UI32_STRING(host),
+                       SILC_STR_END);
 
   if (realname)
-    silc_buffer_format(&buf,
-                      SILC_STR_ADVANCE,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("RN="),
-                      SILC_STR_UI32_STRING(realname),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, &buf,
+                       SILC_STR_ADVANCE,
+                       SILC_STR_UI32_STRING(", "),
+                       SILC_STR_UI32_STRING("RN="),
+                       SILC_STR_UI32_STRING(realname),
+                       SILC_STR_END);
 
   if (email)
-    silc_buffer_format(&buf,
-                      SILC_STR_ADVANCE,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("E="),
-                      SILC_STR_UI32_STRING(email),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, &buf,
+                       SILC_STR_ADVANCE,
+                       SILC_STR_UI32_STRING(", "),
+                       SILC_STR_UI32_STRING("E="),
+                       SILC_STR_UI32_STRING(email),
+                       SILC_STR_END);
 
   if (org)
-    silc_buffer_format(&buf,
-                      SILC_STR_ADVANCE,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("O="),
-                      SILC_STR_UI32_STRING(org),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, &buf,
+                       SILC_STR_ADVANCE,
+                       SILC_STR_UI32_STRING(", "),
+                       SILC_STR_UI32_STRING("O="),
+                       SILC_STR_UI32_STRING(org),
+                       SILC_STR_END);
 
   if (country)
-    silc_buffer_format(&buf,
-                      SILC_STR_ADVANCE,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("C="),
-                      SILC_STR_UI32_STRING(country),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, &buf,
+                       SILC_STR_ADVANCE,
+                       SILC_STR_UI32_STRING(", "),
+                       SILC_STR_UI32_STRING("C="),
+                       SILC_STR_UI32_STRING(country),
+                       SILC_STR_END);
 
   if (version) {
     if (strlen(version) > 1 || !isdigit(version[0])) {
-      silc_buffer_purge(&buf);
+      silc_buffer_spurge(stack, &buf);
+      SILC_LOG_ERROR(("Public key identifier has invalid version (V)"));
       return NULL;
     }
-    silc_buffer_format(&buf,
-                      SILC_STR_ADVANCE,
-                      SILC_STR_UI32_STRING(", "),
-                      SILC_STR_UI32_STRING("V="),
-                      SILC_STR_UI32_STRING(version),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, &buf,
+                       SILC_STR_ADVANCE,
+                       SILC_STR_UI32_STRING(", "),
+                       SILC_STR_UI32_STRING("V="),
+                       SILC_STR_UI32_STRING(version),
+                       SILC_STR_END);
   }
 
-  silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
+  silc_buffer_sformat(stack, &buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
 
   identifier = silc_buffer_steal(&buf, NULL);
   return identifier;
@@ -299,7 +305,7 @@ int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
 
 /* Returns PKCS algorithm context */
 
-const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
+SILC_PKCS_GET_ALGORITHM(silc_pkcs_silc_get_algorithm)
 {
   SilcSILCPublicKey silc_pubkey = public_key;
   return silc_pubkey->pkcs;
@@ -307,10 +313,7 @@ const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key)
 
 /* 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)
+SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_import_public_key_file)
 {
   SilcUInt32 i, len;
   unsigned char *data = NULL;
@@ -324,12 +327,12 @@ SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
   /* 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)) {
-    SILC_LOG_ERROR(("Malformed SILC public key header"));
+    SILC_LOG_DEBUG(("Malformed SILC public key header"));
     return FALSE;
   }
   for (i = 0; i < len; i++) {
     if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
-      SILC_LOG_ERROR(("Malformed SILC public key header"));
+      SILC_LOG_DEBUG(("Malformed SILC public key header"));
       return FALSE;
     }
     filedata++;
@@ -342,17 +345,15 @@ SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
     break;
 
   case SILC_PKCS_FILE_BASE64:
-    data = silc_base64_decode(filedata, filedata_len, &filedata_len);
-    if (!data) {
-      SILC_LOG_ERROR(("Malformed SILC public key encoding"));
+    data = silc_base64_decode(NULL, 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);
+  ret = silc_pkcs_silc_import_public_key(pkcs, NULL, filedata, filedata_len,
+                                        ret_public_key, ret_alg);
   silc_free(data);
 
   return ret ? TRUE : FALSE;
@@ -360,11 +361,8 @@ SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata,
 
 /* Imports SILC protocol style public key */
 
-int silc_pkcs_silc_import_public_key(unsigned char *key,
-                                    SilcUInt32 key_len,
-                                    void **ret_public_key)
+SILC_PKCS_IMPORT_PUBLIC_KEY(silc_pkcs_silc_import_public_key)
 {
-  const SilcPKCSAlgorithm *pkcs;
   SilcBufferStruct buf, alg_key;
   SilcSILCPublicKey silc_pubkey = NULL;
   SilcAsn1 asn1 = NULL;
@@ -426,7 +424,7 @@ int silc_pkcs_silc_import_public_key(unsigned char *key,
   if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier))
     goto err;
 
-  asn1 = silc_asn1_alloc();
+  asn1 = silc_asn1_alloc(NULL);
   if (!asn1)
     goto err;
 
@@ -444,16 +442,16 @@ int silc_pkcs_silc_import_public_key(unsigned char *key,
     if (!silc_pubkey->identifier.version ||
        atoi(silc_pubkey->identifier.version) <= 1) {
       /* Version 1 */
-      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+      alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
     } else {
       /* Version 2 and newer */
-      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
+      alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
     }
-    if (!pkcs) {
+    if (!alg) {
       SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa"));
       goto err;
     }
-    silc_pubkey->pkcs = pkcs;
+    silc_pubkey->pkcs = alg;
 
     if (keydata_len < 4)
       goto err;
@@ -499,8 +497,8 @@ int silc_pkcs_silc_import_public_key(unsigned char *key,
   }
 
   /* Import PKCS algorithm public key */
-  if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key),
-                              &silc_pubkey->public_key))
+  if (!alg->import_public_key(alg, alg_key.data, silc_buffer_len(&alg_key),
+                             &silc_pubkey->public_key))
     goto err;
 
   silc_free(pkcs_name);
@@ -508,6 +506,7 @@ int silc_pkcs_silc_import_public_key(unsigned char *key,
   silc_asn1_free(asn1);
 
   *ret_public_key = silc_pubkey;
+  *ret_alg = alg;
 
   return key_len;
 
@@ -517,16 +516,12 @@ int silc_pkcs_silc_import_public_key(unsigned char *key,
   silc_free(silc_pubkey);
   if (asn1)
     silc_asn1_free(asn1);
-  SILC_LOG_ERROR(("Malformed SILC public key"));
   return 0;
 }
 
 /* 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)
+SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_export_public_key_file)
 {
   SilcBuffer buf;
   unsigned char *key, *data;
@@ -535,7 +530,7 @@ silc_pkcs_silc_export_public_key_file(void *public_key,
   SILC_LOG_DEBUG(("Encoding SILC public key file"));
 
   /* Export key */
-  key = silc_pkcs_silc_export_public_key(public_key, &key_len);
+  key = silc_pkcs_silc_export_public_key(pkcs, stack, public_key, &key_len);
   if (!key)
     return NULL;
 
@@ -544,48 +539,47 @@ silc_pkcs_silc_export_public_key_file(void *public_key,
     break;
 
   case SILC_PKCS_FILE_BASE64:
-    data = silc_base64_encode_file(key, key_len);
+    data = silc_base64_encode_file(stack, key, key_len);
     if (!data)
       return NULL;
-    silc_free(key);
+    silc_sfree(stack, 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)));
+  buf = silc_buffer_salloc_size(stack, key_len +
+                               (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
+                                strlen(SILC_PKCS_PUBLIC_KEYFILE_END)));
   if (!buf) {
-    silc_free(key);
+    silc_sfree(stack, 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);
+  if (silc_buffer_sformat(stack, 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_sfree(stack, buf);
+    silc_sfree(stack, key);
     return NULL;
   }
 
-  silc_free(key);
+  silc_sfree(stack, key);
   key = silc_buffer_steal(buf, ret_len);
-  silc_buffer_free(buf);
+  silc_buffer_sfree(stack, 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)
+SILC_PKCS_EXPORT_PUBLIC_KEY(silc_pkcs_silc_export_public_key)
 {
   SilcSILCPublicKey silc_pubkey = public_key;
-  const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs;
+  const SilcPKCSAlgorithm *alg = silc_pubkey->pkcs;
   SilcBufferStruct alg_key;
   SilcBuffer buf = NULL;
   SilcAsn1 asn1 = NULL;
@@ -596,29 +590,34 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
   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)
+  if (alg->export_public_key)
+    pk = alg->export_public_key(alg, stack, silc_pubkey->public_key, &pk_len);
+  if (!pk) {
+    SILC_LOG_ERROR(("Error exporting PKCS algorithm key"));
     return NULL;
+  }
   silc_buffer_set(&alg_key, pk, pk_len);
 
   /* Encode identifier */
   identifier =
-    silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username,
+    silc_pkcs_silc_encode_identifier(stack,
+                                    silc_pubkey->identifier.username,
                                     silc_pubkey->identifier.host,
                                     silc_pubkey->identifier.realname,
                                     silc_pubkey->identifier.email,
                                     silc_pubkey->identifier.org,
                                     silc_pubkey->identifier.country,
                                     silc_pubkey->identifier.version);
-  if (!identifier)
+  if (!identifier) {
+    SILC_LOG_ERROR(("Error encoding SILC public key identifier"));
     goto err;
+  }
 
-  asn1 = silc_asn1_alloc();
+  asn1 = silc_asn1_alloc(stack);
   if (!asn1)
     goto err;
 
-  if (!strcmp(pkcs->name, "rsa")) {
+  if (!strcmp(alg->name, "rsa")) {
     /* Parse the PKCS #1 public key */
     SilcMPInt n, e;
     SilcUInt32 n_len, e_len;
@@ -641,7 +640,7 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
     if (!nb)
       goto err;
     key_len = e_len + 4 + n_len + 4;
-    key = silc_calloc(key_len, sizeof(*key));
+    key = silc_scalloc(stack, key_len, sizeof(*key));
     if (!key)
       goto err;
 
@@ -656,45 +655,44 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
     silc_free(nb);
     silc_free(eb);
 
-  } else if (!strcmp(pkcs->name, "dsa")) {
+  } else if (!strcmp(alg->name, "dsa")) {
     SILC_NOT_IMPLEMENTED("SILC DSA Public Key");
     goto err;
 
   } else {
-    SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+    SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", alg->name));
     goto err;
   }
 
   /* Encode SILC Public Key */
-  totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len;
-  buf = silc_buffer_alloc_size(totlen + 4);
+  totlen = 2 + strlen(alg->name) + 2 + strlen(identifier) + key_len;
+  buf = silc_buffer_salloc_size(stack, 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)
+  if (silc_buffer_sformat(stack, buf,
+                         SILC_STR_UI_INT(totlen),
+                         SILC_STR_UI_SHORT(strlen(alg->name)),
+                         SILC_STR_UI32_STRING(alg->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_buffer_purge(&alg_key);
+  silc_buffer_sfree(stack, buf);
+  silc_sfree(stack, key);
+  silc_sfree(stack, identifier);
+  silc_buffer_spurge(stack, &alg_key);
   silc_asn1_free(asn1);
 
   return ret;
 
  err:
-  silc_free(identifier);
-  silc_free(pk);
-  silc_free(key);
-  if (buf)
-    silc_buffer_free(buf);
+  silc_sfree(stack, identifier);
+  silc_sfree(stack, pk);
+  silc_sfree(stack, key);
+  silc_buffer_sfree(stack, buf);
   if (asn1)
     silc_asn1_free(asn1);
   return NULL;
@@ -702,15 +700,16 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
 
 /* Return key length */
 
-SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key)
+SILC_PKCS_PUBLIC_KEY_BITLEN(silc_pkcs_silc_public_key_bitlen)
 {
   SilcSILCPublicKey silc_pubkey = public_key;
-  return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key);
+  return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->pkcs,
+                                             silc_pubkey->public_key);
 }
 
 /* Copy public key */
 
-void *silc_pkcs_silc_public_key_copy(void *public_key)
+SILC_PKCS_PUBLIC_KEY_COPY(silc_pkcs_silc_public_key_copy)
 {
   SilcSILCPublicKey silc_pubkey = public_key, new_pubkey;
   SilcPublicKeyIdentifier ident = &silc_pubkey->identifier;
@@ -721,7 +720,8 @@ void *silc_pkcs_silc_public_key_copy(void *public_key)
   new_pubkey->pkcs = silc_pubkey->pkcs;
 
   new_pubkey->public_key =
-    silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key);
+    silc_pubkey->pkcs->public_key_copy(silc_pubkey->pkcs,
+                                      silc_pubkey->public_key);
   if (!new_pubkey->public_key) {
     silc_free(new_pubkey);
     return NULL;
@@ -754,7 +754,7 @@ void *silc_pkcs_silc_public_key_copy(void *public_key)
 
 /* Compares public keys */
 
-SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
+SILC_PKCS_PUBLIC_KEY_COMPARE(silc_pkcs_silc_public_key_compare)
 {
   SilcSILCPublicKey k1 = key1, k2 = key2;
 
@@ -803,16 +803,17 @@ SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
        strcmp(k1->identifier.version, k2->identifier.version)))
     return FALSE;
 
-  return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
+  return k1->pkcs->public_key_compare(k1->pkcs, k1->public_key, k2->public_key);
 }
 
 /* Frees public key */
 
-void silc_pkcs_silc_public_key_free(void *public_key)
+SILC_PKCS_PUBLIC_KEY_FREE(silc_pkcs_silc_public_key_free)
 {
   SilcSILCPublicKey silc_pubkey = public_key;
 
-  silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key);
+  silc_pubkey->pkcs->public_key_free(silc_pubkey->pkcs,
+                                    silc_pubkey->public_key);
 
   silc_free(silc_pubkey->identifier.username);
   silc_free(silc_pubkey->identifier.host);
@@ -832,12 +833,7 @@ void silc_pkcs_silc_public_key_free(void *public_key)
 
 /* 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)
+SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_import_private_key_file)
 {
   SilcCipher aes;
   SilcHash sha1;
@@ -852,12 +848,12 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
   /* 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)) {
-    SILC_LOG_ERROR(("Malformed SILC private key header"));
+    SILC_LOG_DEBUG(("Malformed SILC private key header"));
     return FALSE;
   }
   for (i = 0; i < len; i++) {
     if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
-      SILC_LOG_ERROR(("Malformed SILC private key header"));
+      SILC_LOG_DEBUG(("Malformed SILC private key header"));
       return FALSE;
     }
     filedata++;
@@ -871,11 +867,9 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
     break;
 
   case SILC_PKCS_FILE_BASE64:
-    data = silc_base64_decode(filedata, filedata_len, &len);
-    if (!data) {
-      SILC_LOG_ERROR(("Malformed SILC private key encoding"));
+    data = silc_base64_decode(NULL, filedata, filedata_len, &len);
+    if (!data)
       return FALSE;
-    }
     filedata = data;
     break;
   }
@@ -971,7 +965,8 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
   silc_cipher_free(aes);
 
   /* Import the private key */
-  ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key);
+  ret = silc_pkcs_silc_import_private_key(pkcs, NULL, filedata,
+                                         len, ret_private_key, ret_alg);
 
   silc_free(data);
 
@@ -984,12 +979,9 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
 
 /* Imports SILC implementation style private key */
 
-int silc_pkcs_silc_import_private_key(unsigned char *key,
-                                     SilcUInt32 key_len,
-                                     void **ret_private_key)
+SILC_PKCS_IMPORT_PRIVATE_KEY(silc_pkcs_silc_import_private_key)
 {
   SilcBufferStruct buf;
-  const SilcPKCSAlgorithm *pkcs;
   SilcBufferStruct alg_key;
   SilcSILCPrivateKey silc_privkey = NULL;
   SilcAsn1 asn1 = NULL;
@@ -1003,7 +995,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
   if (!ret_private_key)
     return 0;
 
-  silc_buffer_set(&buf, key, key_len);
+  silc_buffer_set(&buf, (unsigned char *)key, key_len);
 
   /* Get algorithm name and identifier */
   ret =
@@ -1034,7 +1026,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
   if (!silc_privkey)
     goto err;
 
-  asn1 = silc_asn1_alloc();
+  asn1 = silc_asn1_alloc(NULL);
   if (!asn1)
     goto err;
 
@@ -1073,16 +1065,16 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
        versions. */
     if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
       /* Version 0 and 1 */
-      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+      alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
     } else {
       /* Version 2 and newer */
-      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
+      alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
     }
-    if (!pkcs) {
+    if (!alg) {
       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
       goto err;
     }
-    silc_privkey->pkcs = pkcs;
+    silc_privkey->pkcs = alg;
 
     SILC_LOG_DEBUG(("Private key version %s",
                    (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
@@ -1264,14 +1256,15 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
   }
 
   /* Import PKCS algorithm private key */
-  if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key),
-                               &silc_privkey->private_key))
+  if (!alg->import_private_key(alg, 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;
+  *ret_alg = alg;
 
   return key_len;
 
@@ -1286,13 +1279,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
 
 /* 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)
+SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_export_private_key_file)
 {
   SilcCipher aes;
   SilcHash sha1;
@@ -1306,7 +1293,7 @@ silc_pkcs_silc_export_private_key_file(void *private_key,
   SILC_LOG_DEBUG(("Encoding SILC private key file"));
 
   /* Export the private key */
-  key = silc_pkcs_silc_export_private_key(private_key, &key_len);
+  key = silc_pkcs_silc_export_private_key(pkcs, stack, private_key, &key_len);
   if (!key)
     return NULL;
 
@@ -1316,19 +1303,20 @@ silc_pkcs_silc_export_private_key_file(void *private_key,
   /* 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);
+    silc_sfree(stack, key);
     return NULL;
   }
   blocklen = silc_cipher_get_block_len(aes);
   if (blocklen * 2 > sizeof(tmp)) {
     silc_cipher_free(aes);
-    silc_free(key);
+    silc_sfree(stack, key);
     return NULL;
   }
 
   /* Allocate SHA1 hash */
   if (!silc_hash_alloc("sha1", &sha1)) {
     SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered"));
+    silc_sfree(stack, key);
     silc_cipher_free(aes);
     return NULL;
   }
@@ -1336,6 +1324,7 @@ silc_pkcs_silc_export_private_key_file(void *private_key,
   /* Allocate HMAC */
   if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
     SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
+    silc_sfree(stack, key);
     silc_hash_free(sha1);
     silc_cipher_free(aes);
     return NULL;
@@ -1362,8 +1351,9 @@ silc_pkcs_silc_export_private_key_file(void *private_key,
   /* 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);
+  enc = silc_buffer_salloc_size(stack, 4 + 4 + key_len + padlen + len);
   if (!enc) {
+    silc_sfree(stack, key);
     silc_hmac_free(sha1hmac);
     silc_hash_free(sha1);
     silc_cipher_free(aes);
@@ -1379,12 +1369,12 @@ silc_pkcs_silc_export_private_key_file(void *private_key,
   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);
+  silc_buffer_sformat(stack, enc,
+                     SILC_STR_UI_INT(key_len),
+                     SILC_STR_UI_XNSTRING(key, key_len),
+                     SILC_STR_UI_XNSTRING(tmp, padlen),
+                     SILC_STR_END);
+  silc_sfree(stack, key);
 
   /* Encrypt. */
   silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len,
@@ -1413,13 +1403,13 @@ silc_pkcs_silc_export_private_key_file(void *private_key,
     break;
 
   case SILC_PKCS_FILE_BASE64:
-    data = silc_base64_encode_file(enc->data, silc_buffer_len(enc));
+    data = silc_base64_encode_file(stack, enc->data, silc_buffer_len(enc));
     if (!data) {
       silc_buffer_clear(enc);
-      silc_buffer_free(enc);
+      silc_buffer_sfree(stack, enc);
       return NULL;
     }
-    silc_free(silc_buffer_steal(enc, NULL));
+    silc_sfree(stack, silc_buffer_steal(enc, NULL));
     silc_buffer_set(enc, data, strlen(data));
     break;
   }
@@ -1430,31 +1420,30 @@ silc_pkcs_silc_export_private_key_file(void *private_key,
   /* 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);
+  buf = silc_buffer_salloc_size(stack, len);
   if (!buf) {
-    silc_buffer_free(enc);
+    silc_buffer_sfree(stack, 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_sformat(stack, 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);
+  silc_buffer_sfree(stack, enc);
   data = silc_buffer_steal(buf, ret_len);
-  silc_buffer_free(buf);
+  silc_buffer_sfree(stack, 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)
+SILC_PKCS_EXPORT_PRIVATE_KEY(silc_pkcs_silc_export_private_key)
 {
   SilcSILCPrivateKey silc_privkey = private_key;
-  const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs;
+  const SilcPKCSAlgorithm *alg = silc_privkey->pkcs;
   SilcBufferStruct alg_key;
   SilcBuffer buf = NULL;
   SilcAsn1 asn1 = NULL;
@@ -1464,17 +1453,18 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
   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 (alg->export_private_key)
+    prv = alg->export_private_key(alg, stack,
+                                 silc_privkey->private_key, &prv_len);
   if (!prv)
     return NULL;
   silc_buffer_set(&alg_key, prv, prv_len);
 
-  asn1 = silc_asn1_alloc();
+  asn1 = silc_asn1_alloc(stack);
   if (!asn1)
     goto err;
 
-  if (!strcmp(pkcs->name, "rsa")) {
+  if (!strcmp(alg->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,
@@ -1507,32 +1497,32 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
     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);
+    buf = silc_buffer_salloc_size(stack, 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)
+    if (silc_buffer_sformat(stack, 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_buffer_sfree(stack, buf);
     silc_free(nb);
     silc_free(eb);
     silc_free(db);
@@ -1542,7 +1532,7 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
     silc_free(pb);
     silc_free(qb);
 
-  } else if (!strcmp(pkcs->name, "dsa")) {
+  } else if (!strcmp(alg->name, "dsa")) {
     SILC_NOT_IMPLEMENTED("SILC DSA Private Key");
     goto err;
 
@@ -1552,49 +1542,49 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key,
   }
 
   /* Encode SILC private key */
-  totlen = 2 + strlen(pkcs->name) + key_len;
-  buf = silc_buffer_alloc_size(totlen);
+  totlen = 2 + strlen(alg->name) + key_len;
+  buf = silc_buffer_salloc_size(stack, 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)
+  if (silc_buffer_sformat(stack, buf,
+                         SILC_STR_UI_SHORT(strlen(alg->name)),
+                         SILC_STR_UI32_STRING(alg->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_buffer_sfree(stack, buf);
+  silc_sfree(stack, prv);
+  silc_sfree(stack, key);
   silc_asn1_free(asn1);
 
   return ret;
 
  err:
-  silc_free(prv);
-  silc_free(key);
-  if (buf)
-    silc_buffer_free(buf);
+  silc_sfree(stack, prv);
+  silc_sfree(stack, key);
+  silc_buffer_sfree(stack, buf);
   return NULL;
 }
 
 /* Return key length */
 
-SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key)
+SILC_PKCS_PRIVATE_KEY_BITLEN(silc_pkcs_silc_private_key_bitlen)
 {
   SilcSILCPrivateKey silc_privkey = private_key;
-  return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key);
+  return silc_privkey->pkcs->private_key_bitlen(silc_privkey->pkcs,
+                                               silc_privkey->private_key);
 }
 
 /* Frees private key */
 
-void silc_pkcs_silc_private_key_free(void *private_key)
+SILC_PKCS_PRIVATE_KEY_FREE(silc_pkcs_silc_private_key_free)
 {
   SilcSILCPrivateKey silc_privkey = private_key;
 
-  silc_privkey->pkcs->private_key_free(silc_privkey->private_key);
-
+  silc_privkey->pkcs->private_key_free(silc_privkey->pkcs,
+                                      silc_privkey->private_key);
   silc_free(silc_privkey);
 }
 
@@ -1603,80 +1593,68 @@ void silc_pkcs_silc_private_key_free(void *private_key)
 
 /* 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,
-                               SilcRng rng)
+SILC_PKCS_ENCRYPT(silc_pkcs_silc_encrypt)
 {
   SilcSILCPublicKey silc_pubkey = public_key;
 
-  if (!silc_pubkey->pkcs->encrypt)
-    return FALSE;
+  if (!silc_pubkey->pkcs->encrypt) {
+    encrypt_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
 
-  return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key,
-                                   src, src_len,
-                                   dst, dst_size, ret_dst_len, rng);
+  return silc_pubkey->pkcs->encrypt(silc_pubkey->pkcs,
+                                   silc_pubkey->public_key,
+                                   src, src_len, rng, encrypt_cb, context);
 }
 
 /* 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)
+SILC_PKCS_DECRYPT(silc_pkcs_silc_decrypt)
 {
   SilcSILCPrivateKey silc_privkey = private_key;
 
-  if (!silc_privkey->pkcs->decrypt)
-    return FALSE;
+  if (!silc_privkey->pkcs->decrypt) {
+    decrypt_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
 
-  return silc_privkey->pkcs->decrypt(silc_privkey->private_key,
-                                    src, src_len,
-                                    dst, dst_size, ret_dst_len);
+  return silc_privkey->pkcs->decrypt(silc_privkey->pkcs,
+                                    silc_privkey->private_key,
+                                    src, src_len, decrypt_cb, context);
 }
 
 /* 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,
-                            SilcBool compute_hash,
-                            SilcHash hash)
+SILC_PKCS_SIGN(silc_pkcs_silc_sign)
 {
   SilcSILCPrivateKey silc_privkey = private_key;
 
-  if (!silc_privkey->pkcs->sign)
-    return FALSE;
+  if (!silc_privkey->pkcs->sign) {
+    sign_cb(FALSE, NULL, 0, context);
+    return NULL;
+  }
 
-  return silc_privkey->pkcs->sign(silc_privkey->private_key,
+  return silc_privkey->pkcs->sign(silc_privkey->pkcs,
+                                 silc_privkey->private_key,
                                  src, src_len,
-                                 signature, signature_size,
-                                 ret_signature_len, compute_hash, hash);
+                                 compute_hash, hash, rng,
+                                 sign_cb, context);
 }
 
 /* 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)
+SILC_PKCS_VERIFY(silc_pkcs_silc_verify)
 {
   SilcSILCPublicKey silc_pubkey = public_key;
 
-  if (!silc_pubkey->pkcs->verify)
-    return FALSE;
+  if (!silc_pubkey->pkcs->verify) {
+    verify_cb(FALSE, context);
+    return NULL;
+  }
 
-  return silc_pubkey->pkcs->verify(silc_pubkey->public_key,
+  return silc_pubkey->pkcs->verify(silc_pubkey->pkcs,
+                                  silc_pubkey->public_key,
                                   signature, signature_len,
-                                  data, data_len, hash);
+                                  data, data_len, hash, rng,
+                                  verify_cb, context);
 }