Added SILC Public Key version 2 support (V= identifier support).
authorPekka Riikonen <priikone@silcnet.org>
Tue, 23 Jan 2007 14:50:19 +0000 (14:50 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 23 Jan 2007 14:50:19 +0000 (14:50 +0000)
Added PKCS #1 with hash OID support.

lib/silccrypt/silchash.c
lib/silccrypt/silchash.h
lib/silccrypt/silcpk.c
lib/silccrypt/silcpk.h
lib/silccrypt/silcpk_i.h
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs.h
lib/silccrypt/silcpkcs1.c
lib/silccrypt/silcpkcs1_i.h

index bf8cde8f632b38aa5864af57aad6e2dc7787c553..a9729c934e6b5665898601ed4cb47644089c97f4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2007 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
@@ -38,14 +38,17 @@ SilcDList silc_hash_list = NULL;
 /* Default hash functions for silc_hash_register_default(). */
 const SilcHashObject silc_default_hash[] =
 {
-  { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
+  { "sha256", "2.16.840.1.101.3.4.2.1",
+    32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
     silc_sha256_transform, silc_sha256_context_len },
-  { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
+  { "sha1", "1.3.14.3.2.26",
+    20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
     silc_sha1_transform, silc_sha1_context_len },
-  { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
+  { "md5", "1.2.840.113549.2.5",
+    16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
     silc_md5_transform, silc_md5_context_len },
 
-  { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+  { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
 };
 
 /* Registers a new hash function into the SILC. This function is used at
@@ -76,6 +79,11 @@ SilcBool silc_hash_register(const SilcHashObject *hash)
     silc_free(new);
     return FALSE;
   }
+  new->oid = strdup(hash->oid);
+  if (!new->oid) {
+    silc_free(new);
+    return FALSE;
+  }
   new->hash_len = hash->hash_len;
   new->block_len = hash->block_len;
   new->init = hash->init;
@@ -166,7 +174,7 @@ SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
 {
   SilcHashObject *entry = NULL;
 
-  SILC_LOG_DEBUG(("Allocating new hash object"));
+  SILC_LOG_DEBUG(("Allocating new hash %s", name));
 
 #ifndef SILC_SYMBIAN
   if (silc_hash_list) {
@@ -205,6 +213,51 @@ SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
   return FALSE;
 }
 
+/* Allocate hash by OID string */
+
+SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
+{
+  SilcHashObject *entry = NULL;
+
+  SILC_LOG_DEBUG(("Allocating new hash %s", oid));
+
+#ifndef SILC_SYMBIAN
+  if (silc_hash_list) {
+    silc_dlist_start(silc_hash_list);
+    while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
+      if (!strcmp(entry->oid, oid))
+       break;
+    }
+  }
+#else
+  {
+    /* On EPOC which don't have globals we check our constant hash list. */
+    int i;
+    for (i = 0; silc_default_hash[i].oid; i++) {
+      if (!strcmp(silc_default_hash[i].oid, oid)) {
+       entry = (SilcHashObject *)&(silc_default_hash[i]);
+       break;
+      }
+    }
+  }
+#endif /* SILC_SYMBIAN */
+
+  if (entry) {
+    *new_hash = silc_calloc(1, sizeof(**new_hash));
+    if (!(*new_hash))
+      return FALSE;
+    (*new_hash)->hash = entry;
+    (*new_hash)->context = silc_calloc(1, entry->context_len());
+    if (!(*new_hash)->context) {
+      silc_free(*new_hash);
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
 /* Free's the SilcHash object */
 
 void silc_hash_free(SilcHash hash)
@@ -236,6 +289,13 @@ const char *silc_hash_get_name(SilcHash hash)
   return hash->hash->name;
 }
 
+/* Returns hash OID string */
+
+const char *silc_hash_get_oid(SilcHash hash)
+{
+  return hash->hash->oid;
+}
+
 /* Returns TRUE if hash algorithm `name' is supported. */
 
 SilcBool silc_hash_is_supported(const unsigned char *name)
index 698ce15a579cd2b5f6f924116760ed527b86e7e6..dee139efdc6fa760b757c6db38ec4884a069ad3d 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2007 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
@@ -65,8 +65,9 @@ typedef struct SilcHashStruct *SilcHash;
  ***/
 typedef struct {
   char *name;
-  SilcUInt32 hash_len;
-  SilcUInt32 block_len;
+  char *oid;
+  SilcUInt16 hash_len;
+  SilcUInt16 block_len;
 
   void (*init)(void *);
   void (*update)(void *, const unsigned char *, SilcUInt32);
@@ -197,6 +198,21 @@ SilcBool silc_hash_unregister_all(void);
  ***/
 SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
 
+/****f* silccrypt/SilcHashAPI/silc_hash_alloc_by_oid
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash);
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_hash_alloc but allocates the hash algorithm by the
+ *    hash algorithm OID string indicated by `oid'. Returns FALSE if such
+ *    hash function does not exist.
+ *
+ ***/
+SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash);
+
 /****f* silccrypt/SilcHashAPI/silc_hash_free
  *
  * SYNOPSIS
@@ -278,6 +294,20 @@ SilcUInt32 silc_hash_block_len(SilcHash hash);
  ***/
 const char *silc_hash_get_name(SilcHash hash);
 
+/****f* silccrypt/SilcHashAPI/silc_hash_get_oid
+ *
+ * SYNOPSIS
+ *
+ *    const char *silc_hash_get_name(SilcHash hash);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the hash OID string.  Returns NULL if the hash doesn't have
+ *    OID string.  Use strlen() to get the OID string length.
+ *
+ ***/
+const char *silc_hash_get_oid(SilcHash hash);
+
 /****f* silccrypt/SilcHashAPI/silc_hash_make
  *
  * SYNOPSIS
index b934bdc89297362743319fbab47ca7b71f02fc50..e012e3709732aed9e9eaf7f6d2c1efe3ddf98931 100644 (file)
@@ -25,7 +25,6 @@
 /* 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,
@@ -36,6 +35,7 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
   SilcSILCPrivateKey privkey;
   const SilcPKCSAlgorithm *alg;
   const SilcPKCSObject *pkcs;
+  SilcUInt32 version;
 
   SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits",
                  algorithm, bits_key_len));
@@ -47,21 +47,28 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
   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)) {
+  if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier))
+    return FALSE;
+
+  if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2)
+    version = 2;
+  else
+    version = 1;
+
+  /* Allocate algorithm */
+  alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" :
+                                            "pkcs1"));
+  if (!alg) {
     silc_free(pubkey);
     return FALSE;
   }
+  pubkey->pkcs = alg;
 
   /* Allocate SILC private key */
   privkey = silc_calloc(1, sizeof(*privkey));
@@ -169,6 +176,8 @@ SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
       ident->org = strdup(item + strcspn(cp, "=") + 1);
     else if (strstr(item, "C="))
       ident->country = strdup(item + strcspn(cp, "=") + 1);
+    else if (strstr(item, "V="))
+      ident->version = strdup(item + strcspn(cp, "=") + 1);
 
     cp += len;
     if (strlen(cp) < 1)
@@ -189,100 +198,102 @@ SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
 
 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
                                       char *realname, char *email,
-                                      char *org, char *country)
+                                      char *org, char *country,
+                                      char *version)
 {
-  SilcBuffer buf;
+  SilcBufferStruct 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)
+  if (strlen(username) < 3 || strlen(host) < 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);
+  memset(&buf, 0, sizeof(buf));
 
-  if (username) {
-    silc_buffer_format(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_pull(buf, 3 + strlen(username));
-    tlen = 3 + strlen(username);
-  }
 
-  if (host) {
-    silc_buffer_format(buf,
+  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_pull(buf, 5 + strlen(host));
-    tlen += 5 + strlen(host);
-  }
 
-  if (realname) {
-    silc_buffer_format(buf,
+  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_pull(buf, 5 + strlen(realname));
-    tlen += 5 + strlen(realname);
-  }
 
-  if (email) {
-    silc_buffer_format(buf,
+  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_pull(buf, 4 + strlen(email));
-    tlen += 4 + strlen(email);
-  }
 
-  if (org) {
-    silc_buffer_format(buf,
+  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_pull(buf, 4 + strlen(org));
-    tlen += 4 + strlen(org);
-  }
 
-  if (country) {
-    silc_buffer_format(buf,
+  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_pull(buf, 4 + strlen(country));
-    tlen += 4 + strlen(country);
+
+  if (version) {
+    if (strlen(version) > 1 || !isdigit(version[0])) {
+      silc_buffer_purge(&buf);
+      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_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);
+  silc_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
 
+  identifier = silc_buffer_steal(&buf, NULL);
   return identifier;
 }
 
+/* Return SILC public key version */
+
+int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
+{
+  SilcSILCPublicKey silc_pubkey;
+
+  if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
+    return -1;
+
+  silc_pubkey = public_key->public_key;
+
+  /* If version identifire is not present it is version 1. */
+  if (!silc_pubkey->identifier.version)
+    return 1;
+
+  return atoi(silc_pubkey->identifier.version);
+}
 
 /*************************** Public key routines *****************************/
 
@@ -413,13 +424,25 @@ int silc_pkcs_silc_import_public_key(unsigned char *key,
   if (!asn1)
     goto err;
 
+  SILC_LOG_DEBUG(("Public key version %s",
+                 (!silc_pubkey->identifier.version ? " 1" :
+                  silc_pubkey->identifier.version)));
+
   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");
+    /* Get PKCS object.  Different PKCS #1 scheme is used with different
+       versions. */
+    if (!silc_pubkey->identifier.version ||
+       atoi(silc_pubkey->identifier.version) <= 1) {
+      /* Version 1 */
+      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+    } else {
+      /* Version 2 and newer */
+      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
+    }
     if (!pkcs) {
       SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
       goto err;
@@ -579,7 +602,8 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key,
                                     silc_pubkey->identifier.realname,
                                     silc_pubkey->identifier.email,
                                     silc_pubkey->identifier.org,
-                                    silc_pubkey->identifier.country);
+                                    silc_pubkey->identifier.country,
+                                    silc_pubkey->identifier.version);
   if (!identifier)
     goto err;
 
@@ -742,6 +766,12 @@ SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2)
        strcmp(k1->identifier.country, k2->identifier.country)))
     return FALSE;
 
+  if ((k1->identifier.version && !k2->identifier.version) ||
+      (!k1->identifier.version && k2->identifier.version) ||
+      (k1->identifier.version && k2->identifier.version &&
+       strcmp(k1->identifier.version, k2->identifier.version)))
+    return FALSE;
+
   return k1->pkcs->public_key_compare(k1->public_key, k2->public_key);
 }
 
@@ -759,6 +789,7 @@ void silc_pkcs_silc_public_key_free(void *public_key)
   silc_free(silc_pubkey->identifier.email);
   silc_free(silc_pubkey->identifier.org);
   silc_free(silc_pubkey->identifier.country);
+  silc_free(silc_pubkey->identifier.version);
   silc_free(silc_pubkey);
 }
 
@@ -912,6 +943,7 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata,
 
 /* Private key version */
 #define SILC_PRIVATE_KEY_VERSION_1 0x82171273
+#define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
 
 /* Imports SILC implementation style private key */
 
@@ -976,17 +1008,8 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
     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
@@ -997,8 +1020,10 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       goto err;
     silc_buffer_pull(&k, 4);
 
-    if (ver != SILC_PRIVATE_KEY_VERSION_1) {
+    if (ver != SILC_PRIVATE_KEY_VERSION_1 &&
+       ver != SILC_PRIVATE_KEY_VERSION_2) {
       len = ver;
+      ver = 0;
     } else {
       if (silc_buffer_unformat(&k,
                               SILC_STR_UI_INT(&len),
@@ -1007,9 +1032,28 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       silc_buffer_pull(&k, 4);
     }
 
+    /* Get PKCS object.  Different PKCS #1 scheme is used with different
+       versions. */
+    if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) {
+      /* Version 0 and 1 */
+      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+    } else {
+      /* Version 2 and newer */
+      pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
+    }
+    if (!pkcs) {
+      SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+      goto err;
+    }
+    silc_privkey->pkcs = pkcs;
+
+    SILC_LOG_DEBUG(("Private key version %s",
+                   (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" :
+                    ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0")));
+
     /* Get e */
     if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_DATA(&tmp, len),
                             SILC_STR_END) < 0)
       goto err;
     silc_mp_init(&e);
@@ -1023,7 +1067,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       goto err;
     silc_buffer_pull(&k, 4);
     if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_DATA(&tmp, len),
                             SILC_STR_END) < 0)
       goto err;
     silc_mp_init(&n);
@@ -1037,7 +1081,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       goto err;
     silc_buffer_pull(&k, 4);
     if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_DATA(&tmp, len),
                             SILC_STR_END) < 0)
       goto err;
     silc_mp_init(&d);
@@ -1051,7 +1095,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       goto err;
     silc_buffer_pull(&k, 4);
     if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_DATA(&tmp, len),
                             SILC_STR_END) < 0)
       goto err;
     silc_mp_init(&dp);
@@ -1065,14 +1109,14 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       goto err;
     silc_buffer_pull(&k, 4);
     if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_DATA(&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) {
+    if (ver == 0) {
       /* Old version */
 
       /* Get pQ len */
@@ -1104,7 +1148,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
        goto err;
       silc_buffer_pull(&k, 4);
       if (silc_buffer_unformat(&k,
-                              SILC_STR_UI_XNSTRING(&tmp, len),
+                              SILC_STR_DATA(&tmp, len),
                               SILC_STR_END) < 0)
        goto err;
       silc_mp_init(&qp);
@@ -1119,7 +1163,7 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       goto err;
     silc_buffer_pull(&k, 4);
     if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_DATA(&tmp, len),
                             SILC_STR_END) < 0)
       goto err;
     silc_mp_init(&p);
@@ -1133,14 +1177,14 @@ int silc_pkcs_silc_import_private_key(unsigned char *key,
       goto err;
     silc_buffer_pull(&k, 4);
     if (silc_buffer_unformat(&k,
-                            SILC_STR_UI_XNSTRING(&tmp, len),
+                            SILC_STR_DATA(&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) {
+    if (ver == 0) {
       /* Old version.  Compute to new version */
       SILC_LOG_DEBUG(("Old version private key"));
       silc_mp_init(&qp);
@@ -1566,6 +1610,7 @@ SilcBool silc_pkcs_silc_sign(void *private_key,
                             unsigned char *signature,
                             SilcUInt32 signature_size,
                             SilcUInt32 *ret_signature_len,
+                            SilcBool compute_hash,
                             SilcHash hash)
 {
   SilcSILCPrivateKey silc_privkey = private_key;
@@ -1576,7 +1621,7 @@ SilcBool silc_pkcs_silc_sign(void *private_key,
   return silc_privkey->pkcs->sign(silc_privkey->private_key,
                                  src, src_len,
                                  signature, signature_size,
-                                 ret_signature_len, hash);
+                                 ret_signature_len, compute_hash, hash);
 }
 
 /* Verifies as specified in SILC protocol specification */
index d704b7ddf3aae6bbac343166f8f14c96553136c3..3e1e464c9bced16c306029c10e9e328c31c667f5 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2007 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
@@ -50,6 +50,7 @@ typedef struct {
   char *email;
   char *org;
   char *country;
+  char *version;
 } *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct;
 /***/
 
@@ -99,7 +100,6 @@ typedef struct {
  * SYNOPSIS
  *
  *    SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
- *                                         const char *scheme,
  *                                         SilcUInt32 bits_key_len,
  *                                         const char *identifier,
  *                                         SilcRng rng,
@@ -116,12 +116,10 @@ typedef struct {
  *
  *    // 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);
+ *    silc_pkcs_silc_generate_key("rsa", 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,
@@ -134,7 +132,8 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
  *
  *    char *silc_pkcs_silc_encode_identifier(char *username, char *host,
  *                                           char *realname, char *email,
- *                                           char *org, char *country)
+ *                                           char *org, char *country,
+ *                                           char *version);
  *
  * DESCRIPTION
  *
@@ -146,7 +145,8 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
  ***/
 char *silc_pkcs_silc_encode_identifier(char *username, char *host,
                                       char *realname, char *email,
-                                      char *org, char *country);
+                                      char *org, char *country,
+                                      char *version);
 
 /****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_decode_identifier
  *
@@ -165,4 +165,19 @@ char *silc_pkcs_silc_encode_identifier(char *username, char *host,
 SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
                                          SilcPublicKeyIdentifier ident);
 
+/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_public_key_version
+ *
+ * SYNOPSIS
+ *
+ *    int silc_pkcs_silc_public_key_version(SilcPublicKey public_key);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the verison of the SILC Public Key indicated by `public_key'.
+ *    Returns -1 if the `public_key' is not a SILC Public Key and the
+ *    version number otherwise.
+ *
+ ***/
+int silc_pkcs_silc_public_key_version(SilcPublicKey public_key);
+
 #endif /* SILCPK_H */
index 9f6aa76e266be6f74dcbe27bacfb0049b33d0f1d..e027561001d0604825e47c4fe46f45c08ac1ddc1 100644 (file)
@@ -83,6 +83,7 @@ SilcBool silc_pkcs_silc_sign(void *private_key,
                             unsigned char *signature,
                             SilcUInt32 signature_size,
                             SilcUInt32 *ret_signature_len,
+                            SilcBool compute_hash,
                             SilcHash hash);
 SilcBool silc_pkcs_silc_verify(void *public_key,
                               unsigned char *signature,
index 457deb806cdcfca81a6f9c9818ee756844882e61..6bd2eaacf020c32d897d29781ae7e1667072c325 100644 (file)
@@ -593,10 +593,11 @@ SilcBool silc_pkcs_decrypt(SilcPrivateKey private_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)
+                       SilcUInt32 *dst_len, SilcBool compute_hash,
+                       SilcHash hash)
 {
   return private_key->pkcs->sign(private_key->private_key, src, src_len,
-                                dst, dst_size, dst_len, hash);
+                                dst, dst_size, dst_len, compute_hash, hash);
 }
 
 /* Verifies signature */
index dab35b3003e2eeb60ae434e7a2d01afe309a0a51..857824f440f37828849041148980137effbf6830 100644 (file)
@@ -170,6 +170,7 @@ typedef struct {
                   unsigned char *signature,
                   SilcUInt32 signature_size,
                   SilcUInt32 *ret_signature_len,
+                  SilcBool compute_hash,
                   SilcHash hash);
   SilcBool (*verify)(void *public_key,
                     unsigned char *signature,
@@ -278,6 +279,7 @@ struct SilcPKCSObjectStruct {
                   unsigned char *signature,
                   SilcUInt32 signature_size,
                   SilcUInt32 *ret_signature_len,
+                  SilcBool compute_hash,
                   SilcHash hash);
   SilcBool (*verify)(void *public_key,
                     unsigned char *signature,
@@ -687,18 +689,21 @@ SilcBool silc_pkcs_decrypt(SilcPrivateKey private_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);
+ *                            SilcUInt32 *dst_len, SilcBool compute_hash,
+ *                            SilcHash hash);
  *
  * DESCRIPTION
  *
  *    Generates signature with the private key.  Returns FALSE on error.
- *    If `hash' is non-NULL the `src' will be hashed before signing.
+ *    If `compute_hash' is TRUE the `hash' will be used to compute a
+ *    digest over the `src'.  The `hash' must always be valid.
  *
  ***/
 SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
                        unsigned char *src, SilcUInt32 src_len,
                        unsigned char *dst, SilcUInt32 dst_size,
-                       SilcUInt32 *dst_len, SilcHash hash);
+                       SilcUInt32 *dst_len, SilcBool compute_hash,
+                       SilcHash hash);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify
  *
index a438ef3ceccf5fd3d2b8661e6a22bdf5434d6474..283f1ab38747f060aade42d1126c187430cfa860 100644 (file)
@@ -247,7 +247,7 @@ int silc_pkcs1_import_public_key(unsigned char *key,
     goto err;
 
   /* Set key length */
-  pubkey->bits = silc_mp_sizeinbase(&pubkey->n, 2);
+  pubkey->bits = ((silc_mp_sizeinbase(&pubkey->n, 2) + 7) / 8) * 8;
 
   silc_asn1_free(asn1);
 
@@ -392,7 +392,7 @@ int silc_pkcs1_import_private_key(unsigned char *key,
     goto err;
 
   /* Set key length */
-  privkey->bits = silc_mp_sizeinbase(&privkey->n, 2);
+  privkey->bits = ((silc_mp_sizeinbase(&privkey->n, 2) + 7) / 8) * 8;
 
   silc_asn1_free(asn1);
 
@@ -574,9 +574,84 @@ SilcBool silc_pkcs1_sign(void *private_key,
                         unsigned char *signature,
                         SilcUInt32 signature_size,
                         SilcUInt32 *ret_signature_len,
+                        SilcBool compute_hash,
                         SilcHash hash)
 {
-  return FALSE;
+  RsaPrivateKey *key = private_key;
+  unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
+  SilcMPInt mp_tmp;
+  SilcMPInt mp_dst;
+  SilcBufferStruct di;
+  SilcUInt32 len = (key->bits + 7) / 8;
+  const char *oid;
+  SilcAsn1 asn1;
+
+  SILC_LOG_DEBUG(("Sign"));
+
+  if (sizeof(padded) < len)
+    return FALSE;
+  if (signature_size < len)
+    return FALSE;
+
+  oid = silc_hash_get_oid(hash);
+  if (!oid)
+    return FALSE;
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    return FALSE;
+
+  /* Compute hash */
+  if (compute_hash) {
+    silc_hash_make(hash, src, src_len, hashr);
+    src = hashr;
+    src_len = silc_hash_len(hash);
+  }
+
+  /* Encode digest info */
+  memset(&di, 0, sizeof(di));
+  if (!silc_asn1_encode(asn1, &di,
+                       SILC_ASN1_SEQUENCE,
+                         SILC_ASN1_SEQUENCE,
+                           SILC_ASN1_OID(oid),
+                           SILC_ASN1_NULL,
+                         SILC_ASN1_END,
+                         SILC_ASN1_OCTET_STRING(src, src_len),
+                       SILC_ASN1_END, SILC_ASN1_END)) {
+    silc_asn1_free(asn1);
+    return FALSE;
+  }
+  SILC_LOG_HEXDUMP(("DigestInfo"), silc_buffer_data(&di),
+                  silc_buffer_len(&di));
+
+  /* Pad data */
+  if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, silc_buffer_data(&di),
+                        silc_buffer_len(&di), padded, len, NULL)) {
+    silc_asn1_free(asn1);
+    return FALSE;
+  }
+
+  silc_mp_init(&mp_tmp);
+  silc_mp_init(&mp_dst);
+
+  /* Data to MP */
+  silc_mp_bin2mp(padded, len, &mp_tmp);
+
+  /* Sign */
+  silc_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 (compute_hash)
+    memset(hashr, 0, sizeof(hashr));
+  silc_asn1_free(asn1);
+
+  return TRUE;
 }
 
 /* PKCS #1 verification with appendix. */
@@ -588,6 +663,111 @@ SilcBool silc_pkcs1_verify(void *public_key,
                           SilcUInt32 data_len,
                           SilcHash hash)
 {
+  RsaPublicKey *key = public_key;
+  SilcBool ret = FALSE;
+  SilcMPInt mp_tmp2;
+  SilcMPInt mp_dst;
+  unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
+  SilcUInt32 verify_len, len = (key->bits + 7) / 8;
+  SilcBufferStruct di, ldi;
+  SilcHash ihash = NULL;
+  SilcAsn1 asn1 = NULL;
+  char *oid;
+
+  SILC_LOG_DEBUG(("Verify signature"));
+
+  asn1 = silc_asn1_alloc();
+  if (!asn1)
+    return FALSE;
+
+  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 */
+  silc_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))
+    goto err;
+  silc_buffer_set(&di, unpadded, len);
+
+  /* If hash isn't given, allocate the one given in digest info */
+  if (!hash) {
+    /* Decode digest info */
+    if (!silc_asn1_decode(asn1, &di,
+                         SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
+                         SILC_ASN1_SEQUENCE,
+                           SILC_ASN1_SEQUENCE,
+                             SILC_ASN1_OID(&oid),
+                           SILC_ASN1_END,
+                         SILC_ASN1_END, SILC_ASN1_END))
+      goto err;
+
+    if (!silc_hash_alloc_by_oid(oid, &ihash)) {
+      SILC_LOG_DEBUG(("Unknown OID %s", oid));
+      goto err;
+    }
+    hash = ihash;
+  }
+
+  /* Hash the data */
+  silc_hash_make(hash, data, data_len, hashr);
+  data = hashr;
+  data_len = silc_hash_len(hash);
+  oid = (char *)silc_hash_get_oid(hash);
+
+  /* Encode digest info for comparison */
+  memset(&ldi, 0, sizeof(ldi));
+  if (!silc_asn1_encode(asn1, &ldi,
+                       SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
+                       SILC_ASN1_SEQUENCE,
+                         SILC_ASN1_SEQUENCE,
+                           SILC_ASN1_OID(oid),
+                           SILC_ASN1_NULL,
+                         SILC_ASN1_END,
+                         SILC_ASN1_OCTET_STRING(data, data_len),
+                       SILC_ASN1_END, SILC_ASN1_END))
+    goto err;
+
+  SILC_LOG_HEXDUMP(("DigestInfo remote"), silc_buffer_data(&di),
+                  silc_buffer_len(&di));
+  SILC_LOG_HEXDUMP(("DigestInfo local"), silc_buffer_data(&ldi),
+                  silc_buffer_len(&ldi));
+
+  /* Compare */
+  if (silc_buffer_len(&di) == silc_buffer_len(&ldi) &&
+      !memcmp(silc_buffer_data(&di), silc_buffer_data(&ldi),
+             silc_buffer_len(&ldi)))
+    ret = TRUE;
+
+  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));
+  if (ihash)
+    silc_hash_free(ihash);
+  silc_asn1_free(asn1);
+
+  return ret;
+
+ err:
+  memset(verify, 0, verify_len);
+  silc_free(verify);
+  silc_mp_uninit(&mp_tmp2);
+  silc_mp_uninit(&mp_dst);
+  if (ihash)
+    silc_hash_free(ihash);
+  silc_asn1_free(asn1);
   return FALSE;
 }
 
@@ -599,6 +779,7 @@ SilcBool silc_pkcs1_sign_no_oid(void *private_key,
                                unsigned char *signature,
                                SilcUInt32 signature_size,
                                SilcUInt32 *ret_signature_len,
+                               SilcBool compute_hash,
                                SilcHash hash)
 {
   RsaPrivateKey *key = private_key;
@@ -607,13 +788,15 @@ SilcBool silc_pkcs1_sign_no_oid(void *private_key,
   unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
   SilcUInt32 len = (key->bits + 7) / 8;
 
+  SILC_LOG_DEBUG(("Sign"));
+
   if (sizeof(padded) < len)
     return FALSE;
   if (signature_size < len)
     return FALSE;
 
   /* Compute hash if requested */
-  if (hash) {
+  if (compute_hash) {
     silc_hash_make(hash, src, src_len, hashr);
     src = hashr;
     src_len = silc_hash_len(hash);
@@ -640,7 +823,7 @@ SilcBool silc_pkcs1_sign_no_oid(void *private_key,
   memset(padded, 0, sizeof(padded));
   silc_mp_uninit(&mp_tmp);
   silc_mp_uninit(&mp_dst);
-  if (hash)
+  if (compute_hash)
     memset(hashr, 0, sizeof(hashr));
 
   return TRUE;
@@ -656,12 +839,14 @@ SilcBool silc_pkcs1_verify_no_oid(void *public_key,
                                  SilcHash hash)
 {
   RsaPublicKey *key = public_key;
-  int ret = TRUE;
+  SilcBool ret = FALSE;
   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_LOG_DEBUG(("Verify signature"));
+
   silc_mp_init(&mp_tmp2);
   silc_mp_init(&mp_dst);
 
@@ -692,10 +877,8 @@ SilcBool silc_pkcs1_verify_no_oid(void *public_key,
   }
 
   /* Compare */
-  if (len != data_len)
-    ret = FALSE;
-  else if (memcmp(data, unpadded, len))
-    ret = FALSE;
+  if (len == data_len && !memcmp(data, unpadded, len))
+    ret = TRUE;
 
   memset(verify, 0, verify_len);
   memset(unpadded, 0, sizeof(unpadded));
index d23b65b80a3b3f364a0f7ddc8ef2d14c6f07fc72..fd5ecb4fd91822c115d23cbe406938441b555420 100644 (file)
@@ -59,6 +59,7 @@ SilcBool silc_pkcs1_sign(void *private_key,
                         unsigned char *signature,
                         SilcUInt32 signature_size,
                         SilcUInt32 *ret_signature_len,
+                        SilcBool compute_hash,
                         SilcHash hash);
 SilcBool silc_pkcs1_verify(void *public_key,
                           unsigned char *signature,
@@ -72,6 +73,7 @@ SilcBool silc_pkcs1_sign_no_oid(void *private_key,
                                unsigned char *signature,
                                SilcUInt32 signature_size,
                                SilcUInt32 *ret_signature_len,
+                               SilcBool compute_hash,
                                SilcHash hash);
 SilcBool silc_pkcs1_verify_no_oid(void *public_key,
                                  unsigned char *signature,