-fixes
[oweals/gnunet.git] / src / util / crypto_rsa.c
index 418fe833ba238b1f6d6e84dd74241d4c14cb77d5..ee7e5e9f8238acdac54b7836feba200367dacfe2 100644 (file)
@@ -36,6 +36,7 @@
 #include "gnunet_common.h"
 #include "gnunet_crypto_lib.h"
 #include "gnunet_disk_lib.h"
+#include "gnunet_strings_lib.h"
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
@@ -53,32 +54,6 @@ struct GNUNET_CRYPTO_RsaPrivateKey
 };
 
 
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * GNUnet mandates a certain format for the encoding
- * of private RSA key information that is provided
- * by the RSA implementations.  This format is used
- * to serialize a private RSA key (typically when
- * writing it to disk).
- */
-struct RsaPrivateKeyBinaryEncoded
-{
-  /**
-   * Total size of the structure, in bytes, in big-endian!
-   */
-  uint16_t len GNUNET_PACKED;
-  uint16_t sizen GNUNET_PACKED; /*  in big-endian! */
-  uint16_t sizee GNUNET_PACKED; /*  in big-endian! */
-  uint16_t sized GNUNET_PACKED; /*  in big-endian! */
-  uint16_t sizep GNUNET_PACKED; /*  in big-endian! */
-  uint16_t sizeq GNUNET_PACKED; /*  in big-endian! */
-  uint16_t sizedmp1 GNUNET_PACKED;      /*  in big-endian! */
-  uint16_t sizedmq1 GNUNET_PACKED;      /*  in big-endian! */
-  /* followed by the actual values */
-};
-GNUNET_NETWORK_STRUCT_END
-
 #define HOSTKEY_LEN 2048
 
 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS
@@ -107,7 +82,9 @@ adjust (unsigned char *buf, size_t size, size_t target)
 }
 
 /**
- * This HostKey implementation uses RSA.
+ * Create a new private key. Caller must free return value.
+ *
+ * @return fresh private key
  */
 struct GNUNET_CRYPTO_RsaPrivateKey *
 GNUNET_CRYPTO_rsa_key_create ()
@@ -132,6 +109,7 @@ GNUNET_CRYPTO_rsa_key_create ()
 
 /**
  * Free memory occupied by hostkey
+ * @param hostkey pointer to the memory to free
  */
 void
 GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
@@ -237,6 +215,70 @@ GNUNET_CRYPTO_rsa_key_get_public (const struct GNUNET_CRYPTO_RsaPrivateKey
 }
 
 
+/**
+ * Convert a public key to a string.
+ *
+ * @param pub key to convert
+ * @return string representing  'pub'
+ */
+char *
+GNUNET_CRYPTO_rsa_public_key_to_string (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub)
+{
+  char *pubkeybuf;
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) * 8;
+  char *end;
+
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  pubkeybuf = GNUNET_malloc (keylen + 1);
+  end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, 
+                                      sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
+                                      pubkeybuf, 
+                                      keylen);
+  if (NULL == end)
+  {
+    GNUNET_free (pubkeybuf);
+    return NULL;
+  }
+  *end = '\0';
+  return pubkeybuf;
+}
+
+
+/**
+ * Convert a string representing a public key to a public key.
+ *
+ * @param enc encoded public key
+ * @param enclen number of bytes in enc (without 0-terminator)
+ * @param pub where to store the public key
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_rsa_public_key_from_string (const char *enc, 
+                                         size_t enclen,
+                                         struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub)
+{
+  size_t keylen = (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) * 8;
+
+  if (keylen % 5 > 0)
+    keylen += 5 - keylen % 5;
+  keylen /= 5;
+  if (enclen != keylen)
+    return GNUNET_SYSERR;
+
+  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
+                                                (unsigned char*) pub,
+                                                sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
+    return GNUNET_SYSERR;
+  if ( (ntohs (pub->len) != sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) ||
+       (ntohs (pub->padding) != 0) ||
+       (ntohs (pub->sizen) != GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH) )
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+
 /**
  * Internal: publicKey => RSA-Key.
  *
@@ -301,10 +343,10 @@ public2PrivateKey (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
  * @returns encoding of the private key.
  *    The first 4 bytes give the size of the array, as usual.
  */
-static struct RsaPrivateKeyBinaryEncoded *
-rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
+struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *
+GNUNET_CRYPTO_rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
 {
-  struct RsaPrivateKeyBinaryEncoded *retval;
+  struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *retval;
   gcry_mpi_t pkv[6];
   void *pbu[6];
   size_t sizes[6];
@@ -333,7 +375,7 @@ rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
   if (rc)
     rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned");
   GNUNET_assert (0 == rc);
-  size = sizeof (struct RsaPrivateKeyBinaryEncoded);
+  size = sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded);
   for (i = 0; i < 6; i++)
   {
     if (pkv[i] != NULL)
@@ -383,6 +425,7 @@ rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
   return retval;
 }
 
+
 /**
  * Decode the private key from the file-format back
  * to the "normal", internal format.
@@ -394,8 +437,8 @@ struct GNUNET_CRYPTO_RsaPrivateKey *
 GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len)
 {
   struct GNUNET_CRYPTO_RsaPrivateKey *ret;
-  const struct RsaPrivateKeyBinaryEncoded *encoding =
-      (const struct RsaPrivateKeyBinaryEncoded *) buf;
+  const struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *encoding =
+      (const struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *) buf;
   gcry_sexp_t res;
   gcry_mpi_t n, e, d, p, q, u;
   int rc;
@@ -483,7 +526,7 @@ GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len)
   pos += ntohs (encoding->sizedmp1);
   pos += ntohs (encoding->sizedmq1);
   size =
-      ntohs (encoding->len) - sizeof (struct RsaPrivateKeyBinaryEncoded) - pos;
+      ntohs (encoding->len) - sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded) - pos;
   if (size > 0)
   {
     rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG,
@@ -567,7 +610,7 @@ struct GNUNET_CRYPTO_RsaPrivateKey *
 GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
 {
   struct GNUNET_CRYPTO_RsaPrivateKey *ret;
-  struct RsaPrivateKeyBinaryEncoded *enc;
+  struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *enc;
   uint16_t len;
   struct GNUNET_DISK_FileHandle *fd;
   unsigned int cnt;
@@ -607,7 +650,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
 
     while (GNUNET_YES !=
            GNUNET_DISK_file_lock (fd, 0,
-                                  sizeof (struct RsaPrivateKeyBinaryEncoded),
+                                  sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded),
                                   GNUNET_YES))
     {
       sleep (1);
@@ -623,7 +666,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
          _("Creating a new private key.  This may take a while.\n"));
     ret = GNUNET_CRYPTO_rsa_key_create ();
     GNUNET_assert (ret != NULL);
-    enc = rsa_encode_key (ret);
+    enc = GNUNET_CRYPTO_rsa_encode_key (ret);
     GNUNET_assert (enc != NULL);
     GNUNET_assert (ntohs (enc->len) ==
                    GNUNET_DISK_file_write (fd, enc, ntohs (enc->len)));
@@ -632,7 +675,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
     GNUNET_DISK_file_sync (fd);
     if (GNUNET_YES !=
         GNUNET_DISK_file_unlock (fd, 0,
-                                 sizeof (struct RsaPrivateKeyBinaryEncoded)))
+                                 sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)))
       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
     GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
     GNUNET_CRYPTO_rsa_key_get_public (ret, &pub);
@@ -655,7 +698,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
   {
     if (GNUNET_YES !=
         GNUNET_DISK_file_lock (fd, 0,
-                               sizeof (struct RsaPrivateKeyBinaryEncoded),
+                               sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded),
                                GNUNET_NO))
     {
       if (0 == ++cnt % 60)
@@ -677,7 +720,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
       if (GNUNET_YES !=
           GNUNET_DISK_file_unlock (fd, 0,
-                                   sizeof (struct RsaPrivateKeyBinaryEncoded)))
+                                   sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)))
         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
       GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
 
@@ -685,13 +728,13 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
     }
     if (GNUNET_YES != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES))
       fs = 0;
-    if (fs < sizeof (struct RsaPrivateKeyBinaryEncoded))
+    if (fs < sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))
     {
       /* maybe we got the read lock before the hostkey generating
        * process had a chance to get the write lock; give it up! */
       if (GNUNET_YES !=
           GNUNET_DISK_file_unlock (fd, 0,
-                                   sizeof (struct RsaPrivateKeyBinaryEncoded)))
+                                   sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)))
         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
       if (0 == ++cnt % 10)
       {
@@ -699,7 +742,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
              _
              ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"),
              filename, (unsigned int) fs,
-             (unsigned int) sizeof (struct RsaPrivateKeyBinaryEncoded));
+             (unsigned int) sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded));
         LOG (GNUNET_ERROR_TYPE_ERROR,
              _
              ("This may be ok if someone is currently generating a hostkey.\n"));
@@ -727,7 +770,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
   GNUNET_free (enc);
   if (GNUNET_YES !=
       GNUNET_DISK_file_unlock (fd, 0,
-                               sizeof (struct RsaPrivateKeyBinaryEncoded)))
+                               sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)))
     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
   if (ret != NULL)
@@ -742,6 +785,35 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
 }
 
 
+/**
+ * Setup a hostkey file for a peer given the name of the
+ * configuration file (!).  This function is used so that
+ * at a later point code can be certain that reading a
+ * hostkey is fast (for example in time-dependent testcases).
+ *
+ * @param cfg_name name of the configuration file to use
+ */
+void
+GNUNET_CRYPTO_setup_hostkey (const char *cfg_name)
+{
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+  struct GNUNET_CRYPTO_RsaPrivateKey *pk;
+  char *fn;
+
+  cfg = GNUNET_CONFIGURATION_create ();
+  (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
+  if (GNUNET_OK == 
+      GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &fn))
+  {
+    pk = GNUNET_CRYPTO_rsa_key_create_from_file (fn);
+    if (NULL != pk)
+      GNUNET_CRYPTO_rsa_key_free (pk);
+    GNUNET_free (fn);
+  }
+  GNUNET_CONFIGURATION_destroy (cfg);
+}
+
+
 /**
  * Encrypt a block with the public key of another host that uses the
  * same cipher.
@@ -793,6 +865,7 @@ GNUNET_CRYPTO_rsa_encrypt (const void *block, size_t size,
   return GNUNET_OK;
 }
 
+
 /**
  * Decrypt a given block with the hostkey.
  *