]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added gnutls_x509_privkey_verify_params() which verifies the parameters of a private...
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 11 Nov 2011 12:20:20 +0000 (13:20 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 11 Nov 2011 12:27:24 +0000 (13:27 +0100)
12 files changed:
lib/crypto-backend.h
lib/gnutls_errors.c
lib/gnutls_pk.c
lib/gnutls_pk.h
lib/includes/gnutls/gnutls.h.in
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/nettle/pk.c
lib/x509/privkey.c
src/certtool.c
tests/Makefile.am
tests/keygen.c [new file with mode: 0644]

index 389e025c67019968188319486376cf423193929d..ed89deb39d8ebb12cc47ea92abf4fbe60d32e981 100644 (file)
 #define ECC_Y 7
 #define ECC_K 8
 
+#define DSA_P 0
+#define DSA_Q 1
+#define DSA_G 2
+#define DSA_Y 3
+#define DSA_X 4
+
+#define RSA_MODULUS 0
+#define RSA_PUB 1
+#define RSA_PRIV 2
+#define RSA_PRIME1 3
+#define RSA_PRIME2 4
+#define RSA_COEF 5
+#define RSA_E1 6
+#define RSA_E2 7
+
 /**
  * gnutls_direction_t:
  * @GNUTLS_IMPORT: Import direction.
     int (*verify) (gnutls_pk_algorithm_t, const gnutls_datum_t * data,
                    const gnutls_datum_t * signature,
                    const gnutls_pk_params_st * pub);
+    int (*verify_params) (gnutls_pk_algorithm_t, 
+                          const gnutls_pk_params_st * pub);
     int (*generate) (gnutls_pk_algorithm_t, unsigned int nbits,
                      gnutls_pk_params_st *);
     /* this function should convert params to ones suitable
index 0084a88da8b429cf73db6fd835a018495e96ca0a..b978d1d247fa2c369c881b5989e20f5b7c2b3c99 100644 (file)
@@ -176,6 +176,8 @@ static const gnutls_error_entry error_algorithms[] = {
   ERROR_ENTRY (N_("The cookie was bad."), GNUTLS_E_BAD_COOKIE, 1),
   ERROR_ENTRY (N_("An illegal parameter has been received."),
                GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1),
+  ERROR_ENTRY (N_("An illegal parameter was found."),
+               GNUTLS_E_ILLEGAL_PARAMETER, 1),
   ERROR_ENTRY (N_("Error while reading file."), GNUTLS_E_FILE_ERROR, 1),
 
   ERROR_ENTRY (N_("ASN1 parser: Element was not found."),
index e80c38092af2822f0f4e6fff5ea27572e376d2e1..59eb9478c564cf7ac5c8a25c6220e55b86670cd5 100644 (file)
@@ -488,41 +488,6 @@ gnutls_pk_params_release (gnutls_pk_params_st * p)
   p->params_nr = 0;
 }
 
-int
-_gnutls_calc_rsa_exp (gnutls_pk_params_st* params)
-{
-  bigint_t tmp = _gnutls_mpi_alloc_like (params->params[0]);
-
-  if (params->params_nr < RSA_PRIVATE_PARAMS - 2)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  if (tmp == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  /* [6] = d % p-1, [7] = d % q-1 */
-  _gnutls_mpi_sub_ui (tmp, params->params[3], 1);
-  params->params[6] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
-
-  _gnutls_mpi_sub_ui (tmp, params->params[4], 1);
-  params->params[7] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
-
-  _gnutls_mpi_release (&tmp);
-
-  if (params->params[7] == NULL || params->params[6] == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  return 0;
-}
-
 int
 _gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk, 
                                gnutls_pk_params_st* params,
index 6c192da471aeda26343c7a2f551bafbd7ca6fc27..26a91acc30d412bac432bc4abbc1203c71bfd056 100644 (file)
@@ -30,6 +30,7 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops;
 #define _gnutls_pk_decrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.decrypt( algo, ciphertext, plaintext, params)
 #define _gnutls_pk_sign( algo, sig, data, params) _gnutls_pk_ops.sign( algo, sig, data, params)
 #define _gnutls_pk_verify( algo, data, sig, params) _gnutls_pk_ops.verify( algo, data, sig, params)
+#define _gnutls_pk_verify_params( algo, params) _gnutls_pk_ops.verify_params( algo, params)
 #define _gnutls_pk_derive( algo, out, pub, priv) _gnutls_pk_ops.derive( algo, out, pub, priv)
 #define _gnutls_pk_generate( algo, bits, priv) _gnutls_pk_ops.generate( algo, bits, priv)
 
@@ -65,8 +66,6 @@ int
 _gnutls_decode_ber_rs (const gnutls_datum_t * sig_value, bigint_t * r,
                        bigint_t * s);
 
-int _gnutls_calc_rsa_exp (gnutls_pk_params_st*);
-
 int _gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk,
                                    gnutls_pk_params_st*,
                                    gnutls_digest_algorithm_t * dig,
index 77dd47ef0840e8cb7b6782c76b21c824d2ea6e01..f6395e203e19308a775f6dba1bf3473e57d2f819 100644 (file)
@@ -1793,6 +1793,7 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session);
 #define GNUTLS_E_ECC_UNSUPPORTED_CURVE -322
 #define GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE -323
 #define GNUTLS_E_CERTIFICATE_LIST_UNSORTED -324
+#define GNUTLS_E_ILLEGAL_PARAMETER -325
 
 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250
 
index 55fdd317c9981b449eadb81cc716bdd6b5a0adcd..2ade033d95c1585c97fb8f4b67d3b50a5700e9ec 100644 (file)
@@ -735,6 +735,7 @@ extern "C"
   int gnutls_x509_privkey_generate (gnutls_x509_privkey_t key,
                                     gnutls_pk_algorithm_t algo,
                                     unsigned int bits, unsigned int flags);
+  int gnutls_x509_privkey_verify_params (gnutls_x509_privkey_t key);
 
   int gnutls_x509_privkey_export (gnutls_x509_privkey_t key,
                                   gnutls_x509_crt_fmt_t format,
index 813a3cda8e78b5fb71e718f3dca4b6c476701c9f..807c94ec6c8bd06150e37604d3f77474abe914d3 100644 (file)
@@ -724,6 +724,7 @@ GNUTLS_3_0_0 {
        gnutls_srp_3072_group_prime;
        gnutls_srp_4096_group_generator;
        gnutls_srp_4096_group_prime;
+       gnutls_x509_privkey_verify_params;
 } GNUTLS_2_12;
 
 GNUTLS_PRIVATE {
index c56288ed17d1227534e6be1405bc0c3f5574e141..5221aa66f089110419e2c337b739a6a26d976c9b 100644 (file)
@@ -136,7 +136,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, gnutls_datum_t * o
         out->data = NULL;
 
         if (is_supported_curve(curve) == 0)
-          return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
+          return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
 
         _ecc_params_to_pubkey(pub, &ecc_pub);
         _ecc_params_to_privkey(priv, &ecc_priv);
@@ -792,7 +792,7 @@ rsa_fail:
 
         st = _gnutls_ecc_curve_get_params(level);
         if (st == NULL)
-          return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
+          return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
         
         tls_ecc_set.size = st->size;
         tls_ecc_set.prime = st->prime;
@@ -855,6 +855,194 @@ fail:
   return ret;
 }
 
+static int
+wrap_nettle_pk_verify_params (gnutls_pk_algorithm_t algo,
+                              const gnutls_pk_params_st * params)
+{
+  int ret;
+
+  switch (algo)
+    {
+    case GNUTLS_PK_RSA:
+      {
+        bigint_t t1 = NULL, t2 = NULL;
+
+        if (params->params_nr != RSA_PRIVATE_PARAMS)
+          return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+        
+        t1 = _gnutls_mpi_new (256);
+        if (t1 == NULL)
+          return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+        _gnutls_mpi_mulm (t1, params->params[RSA_PRIME1], params->params[RSA_PRIME2], params->params[RSA_MODULUS]);
+        if (_gnutls_mpi_cmp_ui(t1, 0) != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto rsa_cleanup;
+          }
+
+        mpz_invert (TOMPZ(t1), TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1]));
+        if (_gnutls_mpi_cmp(t1, params->params[RSA_COEF]) != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto rsa_cleanup;
+          }
+
+        /* [RSA_PRIME1] = d % p-1, [RSA_PRIME2] = d % q-1 */
+        _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME1], 1);
+        t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1);
+        if (t2 == NULL)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+            goto rsa_cleanup;
+          }
+  
+        if (_gnutls_mpi_cmp(params->params[RSA_E1], t2) != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto rsa_cleanup;
+          }
+        
+        _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME2], 1);
+        _gnutls_mpi_release(&t2);
+
+        t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1);
+        if (t2 == NULL)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+            goto rsa_cleanup;
+          }
+  
+        if (_gnutls_mpi_cmp(params->params[RSA_E2], t2) != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto rsa_cleanup;
+          }
+        
+        ret = 0;
+
+rsa_cleanup:
+        _gnutls_mpi_release(&t1);
+        _gnutls_mpi_release(&t2);
+      }
+
+      break;
+    case GNUTLS_PK_DSA:
+      {
+        bigint_t t1 = NULL;
+
+        if (params->params_nr != DSA_PRIVATE_PARAMS)
+          return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+        
+        t1 = _gnutls_mpi_new (256);
+        if (t1 == NULL)
+          return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+        _gnutls_mpi_powm (t1, params->params[DSA_G], params->params[DSA_X], params->params[DSA_P]);
+
+        if (_gnutls_mpi_cmp(t1, params->params[DSA_Y]) != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto dsa_cleanup;
+          }
+
+        ret = 0;
+
+dsa_cleanup:
+        _gnutls_mpi_release(&t1);
+      }
+
+      break;
+    case GNUTLS_PK_ECC:
+      {
+        int curve = params->flags;
+        ecc_key ecc_priv;
+        ecc_point *R;
+        ecc_point zero;
+
+        if (params->params_nr != ECC_PRIVATE_PARAMS)
+          return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+        if (is_supported_curve(curve) == 0)
+          return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+        _ecc_params_to_privkey(params, &ecc_priv);
+        R = ecc_new_point();
+
+        /* verify that x,y lie on the curve */
+        ret = ecc_projective_check_point(&ecc_priv.pubkey, TOMPZ(params->params[ECC_B]), params->params[ECC_PRIME]);
+        if (ret != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto ecc_cleanup;
+          }
+
+        memcpy(&zero.x, ecc_priv.Gx, sizeof(mpz_t));
+        memcpy(&zero.y, ecc_priv.Gy, sizeof(mpz_t));
+        memcpy(&zero.z, ecc_priv.pubkey.z, sizeof(mpz_t)); /* z = 1 */
+
+        /* verify that k*(Gx,Gy)=(x,y) */
+        ret = ecc_mulmod(ecc_priv.k, &zero, R, TOMPZ(params->params[ECC_A]), TOMPZ(params->params[ECC_PRIME]), 1);
+        if (ret != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto ecc_cleanup;
+          }
+
+        if (mpz_cmp(ecc_priv.pubkey.x, R->x) != 0 || mpz_cmp(ecc_priv.pubkey.y, R->y) != 0)
+          {
+            ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+            goto ecc_cleanup;
+          }
+        
+        ret = 0;
+
+ecc_cleanup:
+        _ecc_params_clear(&ecc_priv);
+        ecc_del_point(R);
+      }  
+      break;
+    default:
+      ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+    }
+
+  return ret;
+}
+
+static int calc_rsa_exp (gnutls_pk_params_st* params)
+{
+  bigint_t tmp = _gnutls_mpi_alloc_like (params->params[0]);
+
+  if (params->params_nr < RSA_PRIVATE_PARAMS - 2)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  if (tmp == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  /* [6] = d % p-1, [7] = d % q-1 */
+  _gnutls_mpi_sub_ui (tmp, params->params[3], 1);
+  params->params[6] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
+
+  _gnutls_mpi_sub_ui (tmp, params->params[4], 1);
+  params->params[7] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
+
+  _gnutls_mpi_release (&tmp);
+
+  if (params->params[7] == NULL || params->params[6] == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  return 0;
+}
+
 
 static int
 wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo,
@@ -870,14 +1058,14 @@ wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo,
        * old but it seemed some of the shipped example private
        * keys were as old.
        */
-      mpz_invert (TOMPZ (params->params[5]),
-                  TOMPZ (params->params[4]), TOMPZ (params->params[3]));
+      mpz_invert (TOMPZ (params->params[RSA_COEF]),
+                  TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1]));
 
       /* calculate exp1 [6] and exp2 [7] */
-      _gnutls_mpi_release (&params->params[6]);
-      _gnutls_mpi_release (&params->params[7]);
+      _gnutls_mpi_release (&params->params[RSA_E1]);
+      _gnutls_mpi_release (&params->params[RSA_E2]);
 
-      result = _gnutls_calc_rsa_exp (params);
+      result = calc_rsa_exp (params);
       if (result < 0)
         {
           gnutls_assert ();
@@ -896,6 +1084,7 @@ gnutls_crypto_pk_st _gnutls_pk_ops = {
   .decrypt = _wrap_nettle_pk_decrypt,
   .sign = _wrap_nettle_pk_sign,
   .verify = _wrap_nettle_pk_verify,
+  .verify_params = wrap_nettle_pk_verify_params,
   .generate = wrap_nettle_pk_generate_params,
   .pk_fixup_private_params = wrap_nettle_pk_fixup,
   .derive = _wrap_nettle_pk_derive,
index 75e59bd4971b292fd52dcc5b02bd99cf9ef344b3..8e42dd4c172f49ce58ab7c5cddeaa8dbd31995e2 100644 (file)
@@ -1306,12 +1306,10 @@ gnutls_x509_privkey_export_dsa_raw (gnutls_x509_privkey_t key,
   return 0;
 }
 
-
-
 /**
  * gnutls_x509_privkey_generate:
  * @key: should contain a #gnutls_x509_privkey_t structure
- * @algo: is one of RSA or DSA.
+ * @algo: is one of the algorithms in #gnutls_pk_algorithm_t.
  * @bits: the size of the modulus
  * @flags: unused for now.  Must be 0.
  *
@@ -1365,6 +1363,30 @@ cleanup:
   return ret;
 }
 
+/**
+ * gnutls_x509_privkey_verify_params:
+ * @key: should contain a #gnutls_x509_privkey_t structure
+ *
+ * This function will verify the private key parameters.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_privkey_verify_params (gnutls_x509_privkey_t key)
+{
+  int ret;
+
+  ret = _gnutls_pk_verify_params (key->pk_algorithm, &key->params);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  return 0;
+}
+
 /**
  * gnutls_x509_privkey_get_key_id:
  * @key: Holds the key
index d60f5eb7c4794a1bba20528b3ffab01c815482f3..1988aff0a4cd949d58d61d5844229a07508738d2 100644 (file)
@@ -222,6 +222,10 @@ generate_private_key_int (void)
   if (ret < 0)
     error (EXIT_FAILURE, 0, "privkey_generate: %s", gnutls_strerror (ret));
 
+  ret = gnutls_x509_privkey_verify_params (key);
+  if (ret < 0)
+    error (EXIT_FAILURE, 0, "privkey_verify_params: %s", gnutls_strerror (ret));
+
   return key;
 }
 
@@ -1737,9 +1741,12 @@ privkey_info (void)
   if (ret < 0)
     error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret));
 
-
   privkey_info_int (key);
 
+  ret = gnutls_x509_privkey_verify_params (key);
+  if (ret < 0)
+    fprintf (outfile, "\n** Private key parameters validation failed **\n\n");
+
   if (info.fix_key != 0)
     {
       ret = gnutls_x509_privkey_fix (key);
index 13b8f7c87e2d571fa6ecd4e148bd72bdbe089abe..00d17be95dd25e1e0650f33077fc4e370e649795 100644 (file)
@@ -64,7 +64,7 @@ ctests = mini-deflate simple gc set_pkcs12_cred certder certuniqueid  \
         crq_apis init_roundtrip pkcs12_s2k_pem dn2 mini-eagain         \
         nul-in-x509-names x509_altname pkcs12_encode mini-x509         \
         mini-x509-rehandshake rng-fork mini-eagain-dtls cipher-test    \
-        x509cert x509cert-tl infoaccess #gendh
+        x509cert x509cert-tl infoaccess keygen #gendh
 #gendh is out because it is too slow in valgrind
 
 if ENABLE_OPENSSL
diff --git a/tests/keygen.c b/tests/keygen.c
new file mode 100644 (file)
index 0000000..aa6365e
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ *
+ * Author: David Marín Carreño
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GnuTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
+
+#include "utils.h"
+
+static void
+tls_log_func (int level, const char *str)
+{
+    fprintf (stderr, "%s |<%d>| %s", "crq_key_id", level, str);
+}
+
+void
+doit (void)
+{
+    gnutls_x509_privkey_t pkey;
+    int ret, algorithm, i;
+
+    ret = gnutls_global_init ();
+    if (ret < 0)
+        fail ("gnutls_global_init: %d\n", ret);
+
+    gnutls_global_set_log_function (tls_log_func);
+    if (debug)
+        gnutls_global_set_log_level (4711);
+
+    for (i = 0; i < 2; i++)
+      {
+          for (algorithm = GNUTLS_PK_RSA; algorithm <= GNUTLS_PK_ECC;
+               algorithm++)
+            {
+                if (algorithm == GNUTLS_PK_DH)
+                    continue;
+
+                ret = gnutls_x509_privkey_init (&pkey);
+                if (ret < 0)
+                  {
+                      fail ("gnutls_x509_privkey_init: %d\n", ret);
+                  }
+
+                ret =
+                    gnutls_x509_privkey_generate (pkey, algorithm,
+                                                  gnutls_sec_param_to_pk_bits
+                                                  (algorithm,
+                                                   GNUTLS_SEC_PARAM_NORMAL),
+                                                  0);
+                if (ret < 0)
+                  {
+                      fail ("gnutls_x509_privkey_generate (%s): %s (%d)\n",
+                            gnutls_pk_algorithm_get_name (algorithm),
+                            gnutls_strerror (ret), ret);
+                  }
+                else if (debug)
+                  {
+                      success ("Key[%s] generation ok: %d\n",
+                               gnutls_pk_algorithm_get_name (algorithm),
+                               ret);
+                  }
+
+                ret = gnutls_x509_privkey_verify_params (pkey);
+                if (ret < 0)
+                  {
+                      fail ("gnutls_x509_privkey_generate (%s): %s (%d)\n",
+                            gnutls_pk_algorithm_get_name (algorithm),
+                            gnutls_strerror (ret), ret);
+                  }
+
+                gnutls_x509_privkey_deinit (pkey);
+            }
+      }
+
+    gnutls_global_deinit ();
+}