updates.
[silc.git] / lib / silccrypt / silcpkcs.c
index fe3b09c065c8da6381526a3e26065dc1deb823c5..a5ebf6be46a697f26026bce93ec490b30c8f7ad2 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2001 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
 #include "silcincludes.h"
 
 #include "rsa.h"
+#include "pkcs1.h"
 
 /* List of all PKCS's in SILC. PKCS's don't support SIM's thus
    only static declarations are possible. XXX: I hope this to change
    real soon. */
 SilcPKCSObject silc_pkcs_list[] =
 {
+  /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
   { "rsa", &silc_rsa_data_context, 
+    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_rsa_data_context_len, silc_rsa_set_arg,
+    silc_pkcs1_encrypt, silc_pkcs1_decrypt,
+    silc_pkcs1_sign, silc_pkcs1_verify },
+
+  /* Raw RSA operations */
+  { "rsa-raw", &silc_rsa_data_context, 
     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,
@@ -85,6 +96,9 @@ int silc_pkcs_is_supported(const unsigned char *name)
 {
   int i;
 
+  if (!name)
+    return FALSE;
+
   for (i = 0; silc_pkcs_list[i].name; i++) {
     if (!strcmp(silc_pkcs_list[i].name, name))
       return TRUE;
@@ -169,6 +183,86 @@ int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
 }
 
+/* Encrypts */
+
+int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, unsigned int src_len,
+                     unsigned char *dst, unsigned int *dst_len)
+{
+  return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
+}
+
+/* Decrypts */
+
+int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, unsigned int src_len,
+                     unsigned char *dst, unsigned int *dst_len)
+{
+  return pkcs->pkcs->decrypt(pkcs->context, src, src_len, dst, dst_len);
+}
+
+/* Generates signature */
+
+int silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, unsigned int src_len,
+                  unsigned char *dst, unsigned int *dst_len)
+{
+  return pkcs->pkcs->sign(pkcs->context, src, src_len, dst, dst_len);
+}
+
+/* Verifies signature */
+
+int silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
+                    unsigned int signature_len, unsigned char *data, 
+                    unsigned int data_len)
+{
+  return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
+                           data, data_len);
+}
+
+/* Generates signature with hash. The hash is signed. */
+
+int silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
+                            unsigned char *src, unsigned int src_len,
+                            unsigned char *dst, unsigned int *dst_len)
+{
+  unsigned char hashr[32];
+  unsigned int hash_len;
+  int ret;
+
+  silc_hash_make(hash, src, src_len, hashr);
+  hash_len = hash->hash->hash_len;
+
+  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;
+}
+
+/* Verifies signature with hash. The `data' is hashed and verified against
+   the `signature'. */
+
+int silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
+                              unsigned char *signature, 
+                              unsigned int signature_len, 
+                              unsigned char *data, 
+                              unsigned int data_len)
+{
+  unsigned char hashr[32];
+  unsigned int hash_len;
+  int ret;
+
+  silc_hash_make(hash, data, data_len, hashr);
+  hash_len = hash->hash->hash_len;
+
+  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;
+}
+
 /* 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. */
@@ -334,7 +428,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
   unsigned char *ret;
 
   buf = silc_buffer_alloc(public_key->len);
-  silc_buffer_pull_tail(buf, public_key->len);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
 
   silc_buffer_format(buf,
                     SILC_STR_UI_INT(public_key->len),
@@ -368,7 +462,7 @@ silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
 
   totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
   buf = silc_buffer_alloc(totlen);
-  silc_buffer_pull_tail(buf, totlen);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
 
   silc_buffer_format(buf,
                     SILC_STR_UI_INT(totlen),
@@ -399,15 +493,20 @@ int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
   unsigned short pkcs_len, identifier_len;
   unsigned int totlen, key_len;
   unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
+  int ret;
 
   buf = silc_buffer_alloc(data_len);
-  silc_buffer_pull_tail(buf, data_len);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
   silc_buffer_put(buf, data, data_len);
 
   /* Get length */
-  silc_buffer_unformat(buf,
-                      SILC_STR_UI_INT(&totlen),
-                      SILC_STR_END);
+  ret = silc_buffer_unformat(buf,
+                            SILC_STR_UI_INT(&totlen),
+                            SILC_STR_END);
+  if (ret == -1) {
+    silc_buffer_free(buf);
+    return FALSE;
+  }
 
   if (totlen != data_len) {
     silc_buffer_free(buf);
@@ -416,10 +515,13 @@ int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
 
   /* Get algorithm name and identifier */
   silc_buffer_pull(buf, 4);
-  silc_buffer_unformat(buf,
-                      SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
-                      SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
-                      SILC_STR_END);
+  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)
@@ -437,9 +539,11 @@ int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
   /* 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 = buf->len;
-  silc_buffer_unformat(buf,
-                      SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
-                      SILC_STR_END);
+  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. */
@@ -482,7 +586,7 @@ silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
 
   totlen = 2 + strlen(private_key->name) + private_key->prv_len;
   buf = silc_buffer_alloc(totlen);
-  silc_buffer_pull_tail(buf, totlen);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
 
   silc_buffer_format(buf,
                     SILC_STR_UI_SHORT(strlen(private_key->name)),
@@ -540,15 +644,19 @@ int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
   unsigned short pkcs_len;
   unsigned int key_len;
   unsigned char *pkcs_name = NULL, *key_data = NULL;
+  int ret;
 
   buf = silc_buffer_alloc(data_len);
-  silc_buffer_pull_tail(buf, data_len);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
   silc_buffer_put(buf, data, data_len);
 
   /* Get algorithm name and identifier */
-  silc_buffer_unformat(buf,
-                      SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
-                      SILC_STR_END);
+  ret = 
+    silc_buffer_unformat(buf,
+                        SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
+                        SILC_STR_END);
+  if (ret == -1)
+    goto err;
 
   if (pkcs_len < 1 || pkcs_len > buf->truelen)
     goto err;
@@ -560,9 +668,11 @@ int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
   /* Get key data. We assume that rest of the buffer is key data. */
   silc_buffer_pull(buf, 2 + pkcs_len);
   key_len = buf->len;
-  silc_buffer_unformat(buf,
-                      SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
-                      SILC_STR_END);
+  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. */
@@ -612,7 +722,7 @@ static int silc_pkcs_save_public_key_internal(char *filename,
   len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
                    strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
   buf = silc_buffer_alloc(len);
-  silc_buffer_pull_tail(buf, len);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
 
   silc_buffer_format(buf,
                     SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
@@ -675,7 +785,7 @@ static int silc_pkcs_save_private_key_internal(char *filename,
   len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
                    strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
   buf = silc_buffer_alloc(len);
-  silc_buffer_pull_tail(buf, len);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
 
   silc_buffer_format(buf,
                     SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),