Added SILC_SKE_STATUS_SIGNATURE_ERROR and OUT_OF_MEMORY and
[silc.git] / lib / silccrypt / silcpkcs.c
index 4e7cdcfe6e76a55c5b997415dc8d4a2361e93c97..cbc8c762416cf51937fc2f590e35d0f38ec79799 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  silcpkcs.c
+  silcpkcs.c 
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2002 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; either version 2 of the License, or
-  (at your option) any later version.
-  
+  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
 #include "rsa.h"
 #include "pkcs1.h"
 
+/* The main SILC PKCS structure. */
+struct SilcPKCSStruct {
+  void *context;               /* Algorithm internal context */
+  SilcPKCSObject *pkcs;                /* Algorithm implementation */
+  SilcUInt32 key_len;          /* Key length in bits */
+};
+
 #ifndef SILC_EPOC
 /* Dynamically registered list of PKCS. */
 SilcDList silc_pkcs_list = NULL;
@@ -65,6 +71,16 @@ bool silc_pkcs_register(const SilcPKCSObject *pkcs)
 
   SILC_LOG_DEBUG(("Registering new PKCS `%s'", pkcs->name));
 
+  /* 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))
+        return FALSE;
+    }
+  }
+
   new = silc_calloc(1, sizeof(*new));
   new->name = strdup(pkcs->name);
   new->init = pkcs->init;
@@ -104,6 +120,8 @@ bool 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) {
        silc_dlist_uninit(silc_pkcs_list);
@@ -134,6 +152,24 @@ bool silc_pkcs_register_default(void)
   return TRUE;
 }
 
+bool silc_pkcs_unregister_all(void)
+{
+#ifndef SILC_EPOC
+  SilcPKCSObject *entry;
+
+  if (!silc_pkcs_list)
+    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;
+  }
+#endif /* SILC_EPOC */
+  return TRUE;
+}
+
 /* Allocates a new SilcPKCS object. The new allocated object is returned
    to the 'new_pkcs' argument. */
 
@@ -168,7 +204,6 @@ bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
     *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
     (*new_pkcs)->pkcs = entry;
     (*new_pkcs)->context = silc_calloc(1, entry->context_len());
-    (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
     return TRUE;
   }
 
@@ -268,6 +303,11 @@ SilcUInt32 silc_pkcs_get_key_len(SilcPKCS pkcs)
   return pkcs->key_len;
 }
 
+const char *silc_pkcs_get_name(SilcPKCS pkcs)
+{
+  return pkcs->pkcs->name;
+}
+
 /* Returns SILC style public key */
 
 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, SilcUInt32 *len)
@@ -302,18 +342,26 @@ SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
 
 /* Sets private key from SilcPrivateKey. */
 
-int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
+SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
 {
-  return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
-                                    private_key->prv_len);
+  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;
 }
 
 /* Sets private key from data. */
 
-int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
-                                  SilcUInt32 prv_len)
+SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
+                                         SilcUInt32 prv_len)
 {
-  return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
+  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;
 }
 
 /* Encrypts */
@@ -361,7 +409,7 @@ int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
   int ret;
 
   silc_hash_make(hash, src, src_len, hashr);
-  hash_len = hash->hash->hash_len;
+  hash_len = silc_hash_len(hash);
 
   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
 
@@ -385,7 +433,7 @@ int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
   int ret;
 
   silc_hash_make(hash, data, data_len, hashr);
-  hash_len = hash->hash->hash_len;
+  hash_len = silc_hash_len(hash);
 
   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
 
@@ -560,20 +608,31 @@ void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
 /* Allocates SILC style public key formed from sent arguments. All data
    is duplicated. */
 
-SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
-                                        unsigned char *pk, 
+SilcPublicKey silc_pkcs_public_key_alloc(const char *name, 
+                                        const char *identifier,
+                                        const unsigned char *pk, 
                                         SilcUInt32 pk_len)
 {
   SilcPublicKey public_key;
+  char *tmp = NULL;
 
   public_key = silc_calloc(1, sizeof(*public_key));
-  public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
   public_key->name = strdup(name);
-  public_key->identifier = strdup(identifier);
   public_key->pk_len = pk_len;
   public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
   memcpy(public_key->pk, pk, pk_len);
 
+  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 = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
+  silc_free(tmp);
+
   return public_key;
 }
 
@@ -592,7 +651,8 @@ void silc_pkcs_public_key_free(SilcPublicKey public_key)
 /* Allocates SILC private key formed from sent arguments. All data is
    duplicated. */
 
-SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
+SilcPrivateKey silc_pkcs_private_key_alloc(const char *name,
+                                          const unsigned char *prv,
                                           SilcUInt32 prv_len)
 {
   SilcPrivateKey private_key;
@@ -801,6 +861,25 @@ bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2)
   return FALSE;
 }
 
+/* Copies the public key indicated by `public_key' and returns new allocated
+   public key which is indentical to the `public_key'. */
+
+SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
+{
+  SilcPublicKey key = silc_calloc(1, sizeof(*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;
+
+  return key;
+}
+
 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
 
 unsigned char *
@@ -945,7 +1024,7 @@ static int silc_pkcs_save_public_key_internal(char *filename,
   case SILC_PKCS_FILE_BIN:
     break;
   case SILC_PKCS_FILE_PEM:
-    data = silc_encode_pem_file(data, data_len);
+    data = silc_pem_encode_file(data, data_len);
     data_len = strlen(data);
     break;
   }
@@ -1008,7 +1087,7 @@ static int silc_pkcs_save_private_key_internal(char *filename,
   case SILC_PKCS_FILE_BIN:
     break;
   case SILC_PKCS_FILE_PEM:
-    data = silc_encode_pem_file(data, data_len);
+    data = silc_pem_encode_file(data, data_len);
     data_len = strlen(data);
     break;
   }
@@ -1097,7 +1176,7 @@ int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
     case SILC_PKCS_FILE_BIN:
       break;
     case SILC_PKCS_FILE_PEM:
-      data = silc_decode_pem(data, len, &len);
+      data = silc_pem_decode(data, len, &len);
       memset(old, 0, data_len);
       silc_free(old);
       old = data; 
@@ -1154,7 +1233,7 @@ int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
     case SILC_PKCS_FILE_BIN:
       break;
     case SILC_PKCS_FILE_PEM:
-      data = silc_decode_pem(data, len, &len);
+      data = silc_pem_decode(data, len, &len);
       break;
     }