updates. New data types.
[silc.git] / lib / silccrypt / silcpkcs.c
index e501d2742aed5672d91e738fb2ce12037fb72fd1..33abe8cac276de8bf2ae975fe8fe7fa1a9554a05 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
   GNU General Public License for more details.
 
 */
+/* $Id$ */
 
 #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,
@@ -84,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;
@@ -117,21 +132,21 @@ char *silc_pkcs_get_supported()
 
 /* Returns the length of the key */
 
-unsigned int silc_pkcs_get_key_len(SilcPKCS self)
+uint32 silc_pkcs_get_key_len(SilcPKCS self)
 {
   return self->key_len;
 }
 
 /* Returns SILC style public key */
 
-unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
+unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, uint32 *len)
 {
   return pkcs->pkcs->get_public_key(pkcs->context, len);
 }
 
 /* Returns SILC style private key */
 
-unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
+unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, uint32 *len)
 {
   return pkcs->pkcs->get_private_key(pkcs->context, len);
 }
@@ -147,7 +162,7 @@ int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
 /* Sets public key from data. */
 
 int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
-                                 unsigned int pk_len)
+                                 uint32 pk_len)
 {
   return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
 }
@@ -163,11 +178,91 @@ int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
 /* Sets private key from data. */
 
 int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
-                                  unsigned int prv_len)
+                                  uint32 prv_len)
 {
   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
 }
 
+/* Encrypts */
+
+int silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
+                     unsigned char *dst, uint32 *dst_len)
+{
+  return pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, dst_len);
+}
+
+/* Decrypts */
+
+int silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, uint32 src_len,
+                     unsigned char *dst, uint32 *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, uint32 src_len,
+                  unsigned char *dst, uint32 *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, 
+                    uint32 signature_len, unsigned char *data, 
+                    uint32 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, uint32 src_len,
+                            unsigned char *dst, uint32 *dst_len)
+{
+  unsigned char hashr[32];
+  uint32 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, 
+                              uint32 signature_len, 
+                              unsigned char *data, 
+                              uint32 data_len)
+{
+  unsigned char hashr[32];
+  uint32 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. */
@@ -177,7 +272,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
 {
   SilcBuffer buf;
   char *identifier;
-  unsigned int len, tlen = 0;
+  uint32 len, tlen = 0;
 
   if (!username || !host)
     return NULL;
@@ -256,7 +351,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
   }
 
   silc_buffer_push(buf, buf->data - buf->head);
-  identifier = silc_calloc(tlen, sizeof(*identifier));
+  identifier = silc_calloc(tlen + 1, sizeof(*identifier));
   memcpy(identifier, buf->data, tlen);
   silc_buffer_free(buf);
 
@@ -268,7 +363,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
 
 SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
                                         unsigned char *pk, 
-                                        unsigned int pk_len)
+                                        uint32 pk_len)
 {
   SilcPublicKey public_key;
 
@@ -299,7 +394,7 @@ void silc_pkcs_public_key_free(SilcPublicKey public_key)
    duplicated. */
 
 SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
-                                          unsigned int prv_len)
+                                          uint32 prv_len)
 {
   SilcPrivateKey private_key;
 
@@ -327,13 +422,13 @@ void silc_pkcs_private_key_free(SilcPrivateKey private_key)
    data. */
 
 unsigned char *
-silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
+silc_pkcs_public_key_encode(SilcPublicKey public_key, uint32 *len)
 {
   SilcBuffer buf;
   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),
@@ -342,7 +437,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
                     SILC_STR_UI_SHORT(strlen(public_key->identifier)),
                     SILC_STR_UI32_STRING(public_key->identifier),
                     SILC_STR_UI_XNSTRING(public_key->pk, 
-                                           public_key->pk_len),
+                                         public_key->pk_len),
                     SILC_STR_END);
   if (len)
     *len = public_key->len;
@@ -357,17 +452,17 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
 /* Encodes SILC style public key. Returns the encoded data. */
 
 unsigned char *
-silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
+silc_pkcs_public_key_data_encode(unsigned char *pk, uint32 pk_len,
                                 char *pkcs, char *identifier, 
-                                unsigned int *len)
+                                uint32 *len)
 {
   SilcBuffer buf;
   unsigned char *ret;
-  unsigned int totlen;
+  uint32 totlen;
 
   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),
@@ -390,23 +485,28 @@ silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
 /* Decodes SILC style public key. Returns TRUE if the decoding was
    successful. Allocates new public key as well. */
 
-int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
+int silc_pkcs_public_key_decode(unsigned char *data, uint32 data_len,
                                SilcPublicKey *public_key)
 {
   SilcBuffer buf;
   SilcPKCS alg;
-  unsigned short pkcs_len, identifier_len;
-  unsigned int totlen, key_len;
+  uint16 pkcs_len, identifier_len;
+  uint32 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);
@@ -415,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)
@@ -436,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. */
@@ -473,15 +578,15 @@ int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
 /* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
 
 unsigned char *
-silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
+silc_pkcs_private_key_encode(SilcPrivateKey private_key, uint32 *len)
 {
   SilcBuffer buf;
   unsigned char *ret;
-  unsigned int totlen;
+  uint32 totlen;
 
   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)),
@@ -502,12 +607,12 @@ silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
 /* Encodes SILC private key. Returns the encoded data. */
 
 unsigned char *
-silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
-                                 char *pkcs, unsigned int *len)
+silc_pkcs_private_key_data_encode(unsigned char *prv, uint32 prv_len,
+                                 char *pkcs, uint32 *len)
 {
   SilcBuffer buf;
   unsigned char *ret;
-  unsigned int totlen;
+  uint32 totlen;
 
   totlen = 2 + strlen(pkcs) + prv_len;
   buf = silc_buffer_alloc(totlen);
@@ -531,23 +636,27 @@ silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
 /* Decodes SILC style public key. Returns TRUE if the decoding was
    successful. Allocates new private key as well. */
 
-int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
+int silc_pkcs_private_key_decode(unsigned char *data, uint32 data_len,
                                 SilcPrivateKey *private_key)
 {
   SilcBuffer buf;
   SilcPKCS alg;
-  unsigned short pkcs_len;
-  unsigned int key_len;
+  uint16 pkcs_len;
+  uint32 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;
@@ -559,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. */
@@ -593,11 +704,11 @@ int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
 
 static int silc_pkcs_save_public_key_internal(char *filename,
                                              unsigned char *data,
-                                             unsigned int data_len,
-                                             unsigned int encoding)
+                                             uint32 data_len,
+                                             uint32 encoding)
 {
   SilcBuffer buf;
-  unsigned int len;
+  uint32 len;
 
   switch(encoding) {
   case SILC_PKCS_FILE_BIN:
@@ -611,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),
@@ -632,10 +743,10 @@ static int silc_pkcs_save_public_key_internal(char *filename,
 /* Saves public key into file */
 
 int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
-                             unsigned int encoding)
+                             uint32 encoding)
 {
   unsigned char *data;
-  unsigned int data_len;
+  uint32 data_len;
 
   data = silc_pkcs_public_key_encode(public_key, &data_len);
   return silc_pkcs_save_public_key_internal(filename, data, data_len,
@@ -645,8 +756,8 @@ int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
 /* Saves public key into file */
 
 int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
-                                  unsigned int data_len,
-                                  unsigned int encoding)
+                                  uint32 data_len,
+                                  uint32 encoding)
 {
   return silc_pkcs_save_public_key_internal(filename, data, data_len,
                                            encoding);
@@ -656,11 +767,11 @@ int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
 
 static int silc_pkcs_save_private_key_internal(char *filename,
                                               unsigned char *data,
-                                              unsigned int data_len,
-                                              unsigned int encoding)
+                                              uint32 data_len,
+                                              uint32 encoding)
 {
   SilcBuffer buf;
-  unsigned int len;
+  uint32 len;
 
   switch(encoding) {
   case SILC_PKCS_FILE_BIN:
@@ -674,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),
@@ -697,10 +808,10 @@ static int silc_pkcs_save_private_key_internal(char *filename,
 
 int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
                               unsigned char *passphrase,
-                              unsigned int encoding)
+                              uint32 encoding)
 {
   unsigned char *data;
-  unsigned int data_len;
+  uint32 data_len;
 
   data = silc_pkcs_private_key_encode(private_key, &data_len);
   return silc_pkcs_save_private_key_internal(filename, data, data_len,
@@ -711,9 +822,9 @@ int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
 /* XXX The buffer should be encrypted if passphrase is provided. */
 
 int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
-                                   unsigned int data_len,
+                                   uint32 data_len,
                                    unsigned char *passphrase,
-                                   unsigned int encoding)
+                                   uint32 encoding)
 {
   return silc_pkcs_save_private_key_internal(filename, data, data_len,
                                             encoding);
@@ -723,10 +834,10 @@ int silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
    is loading was successful. */
 
 int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
-                             unsigned int encoding)
+                             uint32 encoding)
 {
   unsigned char *cp, *old, *data, byte;
-  unsigned int i, data_len, len;
+  uint32 i, data_len, len;
 
   old = data = silc_file_read(filename, &data_len);
   if (!data)
@@ -758,7 +869,7 @@ int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
       break;
     }
 
-    if (!silc_pkcs_public_key_decode(data, len, public_key)) {
+    if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
       memset(old, 0, data_len);
       silc_free(old);
       return FALSE;
@@ -775,10 +886,10 @@ int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
 /* XXX Should support encrypted private key files */
 
 int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
-                              unsigned int encoding)
+                              uint32 encoding)
 {
   unsigned char *cp, *old, *data, byte;
-  unsigned int i, data_len, len;
+  uint32 i, data_len, len;
 
   old = data = silc_file_read(filename, &data_len);
   if (!data)
@@ -810,7 +921,7 @@ int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
       break;
     }
 
-    if (!silc_pkcs_private_key_decode(data, len, private_key)) {
+    if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
       memset(old, 0, data_len);
       silc_free(old);
       return FALSE;