- fix
[oweals/gnunet.git] / src / util / crypto_ecc.c
index 7f88c3e5faf96cb88e920bb958861887dd5357f5..a3c92a335865ac559c8fd810b63b9c385b4124ea 100644 (file)
@@ -28,9 +28,9 @@
 #include "gnunet_common.h"
 #include "gnunet_util_lib.h"
 
-#define EXTRA_CHECKS ALLOW_EXTRA_CHECKS || 1
+#define EXTRA_CHECKS ALLOW_EXTRA_CHECKS 
 
-#define CURVE "NIST P-521"
+#define CURVE "NIST P-256"
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
@@ -170,7 +170,7 @@ GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv
  * @return string representing  'pub'
  */
 char *
-GNUNET_CRYPTO_ecc_public_key_to_string (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
+GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
 {
   char *pubkeybuf;
   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8;
@@ -325,11 +325,15 @@ GNUNET_CRYPTO_ecc_encode_key (const struct GNUNET_CRYPTO_EccPrivateKey *key)
  *
  * @param buf the buffer where the private key data is stored
  * @param len the length of the data in 'buffer'
+ * @param validate GNUNET_YES to validate that the key is well-formed,
+ *                 GNUNET_NO if the key comes from a totally trusted source 
+ *                 and validation is considered too expensive
  * @return NULL on error
  */
 struct GNUNET_CRYPTO_EccPrivateKey *
 GNUNET_CRYPTO_ecc_decode_key (const char *buf, 
-                             size_t len)
+                             size_t len,
+                             int validate)
 {
   struct GNUNET_CRYPTO_EccPrivateKey *ret;
   uint16_t be;
@@ -340,8 +344,9 @@ GNUNET_CRYPTO_ecc_decode_key (const char *buf,
   if (len < sizeof (uint16_t)) 
     return NULL;
   memcpy (&be, buf, sizeof (be));
-  if (len != ntohs (be))
+  if (len < ntohs (be))
     return NULL;
+  len = ntohs (be);
   if (0 != (rc = gcry_sexp_sscan (&sexp,
                                  &erroff,
                                  &buf[2],
@@ -349,8 +354,9 @@ GNUNET_CRYPTO_ecc_decode_key (const char *buf,
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_scan", rc);
     return NULL;
-  }
-  if (0 != (rc = gcry_pk_testkey (sexp)))
+  }  
+  if ( (GNUNET_YES == validate) &&
+       (0 != (rc = gcry_pk_testkey (sexp))) )
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
     return NULL;
@@ -450,7 +456,7 @@ try_read_key (const char *filename)
     char enc[fs];
 
     GNUNET_break (fs == GNUNET_DISK_file_read (fd, enc, fs));
-    if (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, fs)))
+    if (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, fs, GNUNET_YES)))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
           _("File `%s' does not contain a valid private key (failed decode, %llu bytes).  Deleting it.\n"),
@@ -644,8 +650,8 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
   GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs));
   len = ntohs (enc->size);
   ret = NULL;
-  if ((len != fs) ||
-      (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len))))
+  if ((len > fs) ||
+      (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len, GNUNET_YES))))
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
          _("File `%s' does not contain a valid private key.  Deleting it.\n"),
@@ -830,7 +836,6 @@ GNUNET_CRYPTO_ecc_key_create_start (const char *filename,
 {
   struct GNUNET_CRYPTO_EccKeyGenerationContext *gc;
   struct GNUNET_CRYPTO_EccPrivateKey *pk;
-  const char *weak_random;
 
   if (NULL != (pk = try_read_key (filename)))
   {
@@ -858,10 +863,6 @@ GNUNET_CRYPTO_ecc_key_create_start (const char *filename,
     GNUNET_free (gc);
     return NULL;
   }
-  weak_random = NULL;
-  if (GNUNET_YES ==
-      GNUNET_CRYPTO_random_is_weak ())
-    weak_random = "-w";
   gc->gnunet_ecc = GNUNET_OS_start_process (GNUNET_NO,
                                            GNUNET_OS_INHERIT_STD_ERR,
                                            NULL, 
@@ -869,7 +870,6 @@ GNUNET_CRYPTO_ecc_key_create_start (const char *filename,
                                            "gnunet-ecc",
                                            "gnunet-ecc",                                           
                                            gc->filename,
-                                           weak_random,
                                            NULL);
   if (NULL == gc->gnunet_ecc)
   {
@@ -936,7 +936,6 @@ data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
 
   GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc);
 #define FORMATSTRING "(4:data(5:flags3:raw)(5:value32:01234567890123456789012345678901))"
-#define FORMATSTRING2 "(4:data(4:hash6:sha25632:01234567890123456789012345678901))"
   bufSize = strlen (FORMATSTRING) + 1;
   {
     char buff[bufSize];
@@ -978,6 +977,8 @@ GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key,
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("ECC signing failed at %s:%d: %s\n"), __FILE__,
          __LINE__, gcry_strerror (rc));
+    gcry_sexp_release (data);
+    return GNUNET_SYSERR;
   }
   gcry_sexp_release (data);
   ssize = gcry_sexp_sprint (result, 
@@ -1065,16 +1066,76 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key,
                         const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub,
                         struct GNUNET_HashCode *key_material)
 { 
-  gcry_sexp_t psexp;
+  size_t size;
+  size_t slen;
+  int rc;
+  gcry_sexp_t data;  
+  unsigned char sdata_buf[2048]; /* big enough to print 'sdata' and 'r_sig' */
 
-  if (! (psexp = decode_public_key (pub)))
-    return GNUNET_SYSERR;
-  
+  /* first, extract the q value from the public key */
+  {
+    gcry_sexp_t psexp;
+    gcry_mpi_t sdata;
+    
+    if (! (psexp = decode_public_key (pub)))
+      return GNUNET_SYSERR;
+    rc = key_from_sexp (&sdata, psexp, "public-key", "q");
+    if (rc)
+      rc = key_from_sexp (&sdata, psexp, "ecc", "q");
+    GNUNET_assert (0 == rc);  
+    gcry_sexp_release (psexp);
+    size = sizeof (sdata_buf);
+    GNUNET_assert (0 ==
+                  gcry_mpi_print (GCRYMPI_FMT_USG, sdata_buf, size, &size,
+                                  sdata));
+    gcry_mpi_release (sdata);
+  }
+  /* convert q value into an S-expression -- whatever format libgcrypt wants,
+     re-using format from sign operation for now... */
+  {
+    char *sexp_string;
+
+#define FORMATPREFIX "(4:data(5:flags3:raw)(5:value%u:"
+#define FORMATPOSTFIX "))"
+    sexp_string = GNUNET_malloc (strlen (FORMATPREFIX) + size + 12 +
+                                 strlen (FORMATPOSTFIX) + 1);
+    GNUNET_snprintf (sexp_string,
+                    strlen (FORMATPREFIX) + 12,
+                    FORMATPREFIX,
+                    size);
+    slen = strlen (sexp_string);
+    memcpy (&sexp_string[slen],
+           sdata_buf, 
+           size);
+    memcpy (&sexp_string[slen + size],
+           FORMATPOSTFIX,
+           strlen (FORMATPOSTFIX) + 1);  
+    GNUNET_assert (0 == gcry_sexp_new (&data, 
+                                      sexp_string, 
+                                      slen + size + strlen (FORMATPOSTFIX), 
+                                      0));
+    GNUNET_free (sexp_string);
+  }
+  /* then call the 'multiply' function, hoping it simply multiplies the points;
+     here we need essentially a WRAPPER around _gcry_mpi_ex_mul_point! - FIXME-WK!*/
+#if WK
+  {
+    gcry_sexp_t result;
+    
+    rc = gcry_ecc_mul_point (&result, data /* scalar */, key->sexp /* point and ctx */);
+    GNUNET_assert (0 == rc);
+    slen = gcry_sexp_sprint (result, GCRYSEXP_FMT_DEFAULT, sdata_buf, sizeof (sdata_buf));
+    GNUNET_assert (0 != slen);
+  }
+#else
+  /* use broken version, insecure! */
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("To be implemented: not secure at the moment, please read README\n"));
+  slen = sprintf ((char*) sdata_buf, "FIXME-this is not key material");
+#endif
+  gcry_sexp_release (data);
 
-  gcry_sexp_release (psexp);
-  GNUNET_break (0); // not implemented
-  /* FIXME: this totally breaks security ... */
-  memset (key_material, 42, sizeof (struct GNUNET_HashCode));
+  /* finally, get a string of the resulting S-expression and hash it to generate the key material */
+  GNUNET_CRYPTO_hash (sdata_buf, slen, key_material);
   return GNUNET_OK;
 }