diff options
-rw-r--r-- | TODO | 6 | ||||
-rw-r--r-- | cipher/ChangeLog | 9 | ||||
-rw-r--r-- | cipher/ecc.c | 108 | ||||
-rw-r--r-- | cipher/pubkey.c | 62 | ||||
-rw-r--r-- | cipher/rsa.c | 41 | ||||
-rw-r--r-- | doc/gcrypt.texi | 8 | ||||
-rw-r--r-- | mpi/mpicoder.c | 4 | ||||
-rw-r--r-- | src/ChangeLog | 8 | ||||
-rw-r--r-- | src/cipher-proto.h | 5 | ||||
-rw-r--r-- | src/fips.c | 7 | ||||
-rw-r--r-- | tests/ChangeLog | 4 | ||||
-rw-r--r-- | tests/keygrip.c | 70 |
12 files changed, 277 insertions, 55 deletions
@@ -12,10 +12,6 @@ What's left to do -*- outline -*- This requires the introduction of a parameter names (say) U which is calculated according to OpenSSL/PKCS#1 rules. -* Add a warning to the manual, to check that libgcrypt actually has - been compiled with thread support when used by a threaded - application. - * linker script test Write an autoconf test to check whether the linker supports a version script. @@ -97,5 +93,3 @@ What's left to do -*- outline -*- ** C++ tests We have some code to allow using libgcrypt from C++, so we also should have a test case. - -* The prime generator always uses very-strong-random. diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 28fdf072..a026bad6 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,12 @@ +2008-08-29 Werner Koch <wk@g10code.com> + + * pubkey.c (gcry_pk_get_keygrip): Remove the special case for RSA + and check whether a custom computation function has been setup. + * rsa.c (compute_keygrip): New. + (_gcry_pubkey_extraspec_rsa): Setup this function. + * ecc.c (compute_keygrip): New. + (_gcry_pubkey_extraspec_ecdsa): Setup this function. + 2008-08-28 Werner Koch <wk@g10code.com> * cipher.c (cipher_decrypt, cipher_encrypt): Return an error if diff --git a/cipher/ecc.c b/cipher/ecc.c index c75fd4ef..5d5c322e 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1182,6 +1182,110 @@ ecc_get_nbits (int algo, gcry_mpi_t *pkey) } + +/* See rsa.c for a description of this function. */ +static gpg_err_code_t +compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) +{ + gpg_err_code_t ec = 0; + gcry_sexp_t l1; + static const char const names[] = "pabgnq"; + gcry_mpi_t values[6]; + int idx; + + /* Clear the values for easier error cleanup. */ + for (idx=0; idx < 6; idx++) + values[idx] = NULL; + + /* Fill values with all available parameters. */ + for (idx=0; idx < 6; idx++) + { + l1 = gcry_sexp_find_token (keyparam, names+idx, 1); + if (l1) + { + values[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l1); + if (!values[idx]) + { + ec = GPG_ERR_INV_OBJ; + goto leave; + } + } + } + + /* Check whether a curve parameter is available and use that to fill + in missing values. */ + l1 = gcry_sexp_find_token (keyparam, "curve", 5); + if (l1) + { + char *curve; + gcry_mpi_t tmpvalues[6]; + + for (idx = 0; idx < 6; idx++) + tmpvalues[idx] = NULL; + + curve = _gcry_sexp_nth_string (l1, 1); + if (!curve) + { + ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ + goto leave; + } + ec = _gcry_ecc_get_param (curve, tmpvalues); + gcry_free (curve); + if (ec) + goto leave; + + for (idx = 0; idx < 6; idx++) + { + if (!values[idx]) + values[idx] = tmpvalues[idx]; + else + mpi_free (tmpvalues[idx]); + } + } + + /* Check that all parameters are known and normalize all MPIs (that + should not be required but we use an internal fucntion later and + thus we better make 100% sure that they are normalized). */ + for (idx = 0; idx < 6; idx++) + if (!values[idx]) + { + ec = GPG_ERR_NO_OBJ; + goto leave; + } + else + _gcry_mpi_normalize (values[idx]); + + /* Hash them all. */ + for (idx = 0; idx < 6; idx++) + { + char buf[30]; + unsigned char *rawmpi; + unsigned int rawmpilen; + + rawmpi = _gcry_mpi_get_buffer (values[idx], &rawmpilen, NULL); + if (!rawmpi) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen); + gcry_md_write (md, buf, strlen (buf)); + gcry_md_write (md, rawmpi, rawmpilen); + gcry_md_write (md, ")", 1); + gcry_free (rawmpi); + } + + leave: + for (idx = 0; idx < 6; idx++) + _gcry_mpi_release (values[idx]); + + return ec; +} + + + + /* Self-test section. @@ -1254,6 +1358,8 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecdsa = }; pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa = { - run_selftests + run_selftests, + NULL, + compute_keygrip }; diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 8c35390d..74a40cc5 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -878,7 +878,7 @@ sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names, const char *name; gcry_sexp_t list; - /* Clear the array for easir error cleanup. */ + /* Clear the array for easier error cleanup. */ for (name = element_names, idx = 0; *name; name++, idx++) elements[idx] = NULL; gcry_assert (idx >= 6); /* We know that ECC has at least 6 elements. */ @@ -2432,10 +2432,10 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) gcry_sexp_t list = NULL, l2 = NULL; gcry_pk_spec_t *pubkey = NULL; gcry_module_t module = NULL; + pk_extra_spec_t *extraspec; const char *s; char *name = NULL; int idx; - int is_rsa; const char *elems; gcry_md_hd_t md = NULL; @@ -2469,53 +2469,45 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) goto fail; /* Unknown algorithm. */ pubkey = (gcry_pk_spec_t *) module->spec; + extraspec = module->extraspec; - /* FIXME, special handling should be implemented by the algorithms, - not by the libgcrypt core. */ - is_rsa = module->mod_id == GCRY_PK_RSA; elems = pubkey->elements_grip; - if (! elems) + if (!elems) goto fail; /* No grip parameter. */ if (gcry_md_open (&md, GCRY_MD_SHA1, 0)) goto fail; -#if USE_ECC -# ifdef __GNUC__ -# warning needs to be fixed for ECC. -# endif -#endif - - for (idx = 0, s = elems; *s; s++, idx++) + if (extraspec && extraspec->comp_keygrip) { - const char *data; - size_t datalen; - - l2 = gcry_sexp_find_token (list, s, 1); - if (! l2) - goto fail; - data = gcry_sexp_nth_data (l2, 1, &datalen); - if (! data) + /* Module specific method to compute a keygrip. */ + if (extraspec->comp_keygrip (md, list)) goto fail; - if (!is_rsa) + } + else + { + /* Generic method to compute a keygrip. */ + for (idx = 0, s = elems; *s; s++, idx++) { + const char *data; + size_t datalen; char buf[30]; - - sprintf (buf, "(1:%c%u:", *s, (unsigned int)datalen); + + l2 = gcry_sexp_find_token (list, s, 1); + if (! l2) + goto fail; + data = gcry_sexp_nth_data (l2, 1, &datalen); + if (! data) + goto fail; + + snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen); gcry_md_write (md, buf, strlen (buf)); + gcry_md_write (md, data, datalen); + gcry_sexp_release (l2); + gcry_md_write (md, ")", 1); } - - /* PKCS-15 says that for RSA only the modulus should be hashed - - however, it is not clear wether this is meant to use the raw - bytes (assuming this is an unsigned integer) or whether the DER - required 0 should be prefixed. We hash the raw bytes. For - non-RSA we hash S-expressions. */ - gcry_md_write (md, data, datalen); - gcry_sexp_release (l2); - if (!is_rsa) - gcry_md_write (md, ")", 1); } - + if (!array) { array = gcry_malloc (20); diff --git a/cipher/rsa.c b/cipher/rsa.c index 8ca8f314..9a7b94df 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -686,6 +686,44 @@ _gcry_rsa_get_nbits (int algo, gcry_mpi_t *pkey) } +/* Compute a keygrip. MD is the hash context which we are going to + update. KEYPARAM is an S-expression with the key parameters, this + is usually a public key but may also be a secret key. An example + of such an S-expression is: + + (rsa + (n #00B...#) + (e #010001#)) + + PKCS-15 says that for RSA only the modulus should be hashed - + however, it is not clear wether this is meant to use the raw bytes + (assuming this is an unsigned integer) or whether the DER required + 0 should be prefixed. We hash the raw bytes. */ +static gpg_err_code_t +compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) +{ + gcry_sexp_t l1; + const char *data; + size_t datalen; + + l1 = gcry_sexp_find_token (keyparam, "n", 1); + if (!l1) + return GPG_ERR_NO_OBJ; + + data = gcry_sexp_nth_data (l1, 1, &datalen); + if (!data) + { + gcry_sexp_release (l1); + return GPG_ERR_NO_OBJ; + } + + gcry_md_write (md, data, datalen); + gcry_sexp_release (l1); + + return 0; +} + + /* @@ -761,6 +799,7 @@ gcry_pk_spec_t _gcry_pubkey_spec_rsa = pk_extra_spec_t _gcry_pubkey_extraspec_rsa = { run_selftests, - rsa_generate + rsa_generate, + compute_keygrip }; diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index b3daa07e..55fae683 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -529,10 +529,10 @@ Libgcrypt into this mode: @itemize @item -If the file @file{/proc/fips140} exists and contains the string value -@code{1}, Libgcrypt is put into FIPS mode at initialization time. -Obviously this works only on systems with a @code{proc} file system -(ie.e GNU/Linux). +If the file @file{/proc/sys/crypto/fips_enabled} exists and contains a +numeric value other than @code{0}, Libgcrypt is put into FIPS mode at +initialization time. Obviously this works only on systems with a +@code{proc} file system (ie.e GNU/Linux). @item If the file @file{/etc/gcrypt/fips140.force} exists, Libgcrypt is put diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c index 0c19941b..d8f860ce 100644 --- a/mpi/mpicoder.c +++ b/mpi/mpicoder.c @@ -247,8 +247,8 @@ do_get_buffer( gcry_mpi_t a, unsigned *nbytes, int *sign, int force_secure ) #endif } - /* this is sub-optimal but we need to do the shift oepration because - * the caller has to free the returned buffer */ + /* This is sub-optimal but we need to do the shift operation + because the caller has to free the returned buffer */ for(p=buffer; !*p && *nbytes; p++, --*nbytes ) ; if( p != buffer ) diff --git a/src/ChangeLog b/src/ChangeLog index d72ef544..be3cc2ea 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2008-08-29 Werner Koch <wk@g10code.com> + + * fips.c (_gcry_initialize_fips_mode): Changed /proc file to test + for FIPS mode. + + * cipher-proto.h (pk_compute_keygrip_t): New. + (pk_extra_spec): Add field comp_keygrip. + 2008-08-28 Werner Koch <wk@g10code.com> * hwfeatures.c (_gcry_detect_hw_features): Disable hardware diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 4ca76b55..39a91012 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -48,6 +48,10 @@ typedef gcry_err_code_t (*pk_ext_generate_t) gcry_mpi_t *skey, gcry_mpi_t **retfactors); +/* The type is used to compute the keygrip. */ +typedef gpg_err_code_t (*pk_comp_keygrip_t) + (gcry_md_hd_t md, gcry_sexp_t keyparm); + /* Extra module specification structures. These are used for internal modules which provide more functions than available through the @@ -66,6 +70,7 @@ typedef struct pk_extra_spec { selftest_func_t selftest; pk_ext_generate_t ext_generate; + pk_comp_keygrip_t comp_keygrip; } pk_extra_spec_t; @@ -115,13 +115,14 @@ _gcry_initialize_fips_mode (int force) { FILE *fp; int saved_errno; + static const char const procfname[] = "/proc/sys/crypto/fips_enabled"; - fp = fopen ("/proc/fips140", "r"); + fp = fopen (procfname, "r"); if (fp) { char line[256]; - if (fgets (line, sizeof line, fp) && atoi (line) == 1) + if (fgets (line, sizeof line, fp) && atoi (line)) { /* System is in fips mode. */ fclose (fp); @@ -136,7 +137,7 @@ _gcry_initialize_fips_mode (int force) /* Problem reading the fips file despite that we have the proc file system. We better stop right away. */ log_info ("FATAL: error reading `%s' in libgcrypt: %s\n", - "/proc/fips140", strerror (saved_errno)); + procfname, strerror (saved_errno)); abort (); } } diff --git a/tests/ChangeLog b/tests/ChangeLog index c08d544c..7d91d096 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2008-08-29 Werner Koch <wk@g10code.com> + + * keygrip.c: Update to also check ECDSA. + 2008-08-28 Werner Koch <wk@g10code.com> * rsa-16k.key: New sample key. diff --git a/tests/keygrip.c b/tests/keygrip.c index 351139f1..e1908ba3 100644 --- a/tests/keygrip.c +++ b/tests/keygrip.c @@ -45,15 +45,29 @@ die (const char *format, ...) exit (1); } +static void +print_hex (const char *text, const void *buf, size_t n) +{ + const unsigned char *p = buf; + + fputs (text, stdout); + for (; n; n--, p++) + printf ("%02X", *p); + putchar ('\n'); +} + + static struct { + int algo; const char *key; const unsigned char grip[20]; } key_grips[] = { { + GCRY_PK_RSA, "(private-key" " (rsa" " (n #00B6B509596A9ECABC939212F891E656A626BA07DA8521A9CAD4C08E640C04052FBB87F424EF1A0275A48A9299AC9DB69ABE3D0124E6C756B1F7DFB9B842D6251AEA6EE85390495CADA73D671537FCE5850A932F32BAB60AB1AC1F852C1F83C625E7A7D70CDA9EF16D5C8E47739D77DF59261ABE8454807FF441E143FBD37F8545#)" @@ -65,6 +79,7 @@ static struct "\x32\xCF\xFA\x85\xB1\x79\x1F\xBB\x26\x14\xE9\x1A\xFD\xF3\xAF\xE3\x32\x08\x2E\x25" }, { + GCRY_PK_DSA, " (public-key" " (dsa" " (p #0084E4C626E16005770BD9509ABF7354492E85B8C0060EFAAAEC617F725B592FAA59DF5460575F41022776A9718CE62EDD542AB73C7720869EBDBC834D174ADCD7136827DF51E2613545A25CA573BC502A61B809000B6E35F5EB7FD6F18C35678C23EA1C3638FB9CFDBA2800EE1B62F41A4479DE824F2834666FBF8DC5B53C2617#)" @@ -75,6 +90,7 @@ static struct }, { + GCRY_PK_DSA, "(private-key" " (dsa" " (p #0084E4C626E16005770BD9509ABF7354492E85B8C0060EFAAAEC617F725B592FAA59DF5460575F41022776A9718CE62EDD542AB73C7720869EBDBC834D174ADCD7136827DF51E2613545A25CA573BC502A61B809000B6E35F5EB7FD6F18C35678C23EA1C3638FB9CFDBA2800EE1B62F41A4479DE824F2834666FBF8DC5B53C2617#)" @@ -83,7 +99,40 @@ static struct " (y #3D5DD14AFA2BF24A791E285B90232213D0E3BA74AB1109E768AED19639A322F84BB7D959E2BA92EF73DE4C7F381AA9F4053CFA3CD4527EF9043E304E5B95ED0A3A5A9D590AA641C13DB2B6E32B9B964A6A2C730DD3EA7C8E13F7A140AFF1A91CE375E9B9B960384779DC4EA180FA1F827C52288F366C0770A220F50D6D8FD6F6#)" " (x #0087F9E91BFBCC1163DE71ED86D557708E32F8ADDE#)))", "\x04\xA3\x4F\xA0\x2B\x03\x94\xD7\x32\xAD\xD5\x9B\x50\xAF\xDB\x5D\x57\x22\xA6\x10" + }, + { + GCRY_PK_ECDSA, + "(public-key" + " (ecdsa" + " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" + " (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)" + " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)" + " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)" + " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)" + " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", + "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" + }, + { + GCRY_PK_ECDSA, + "(public-key" + " (ecdsa" + " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" + " (curve \"NIST P-256\")" + " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)" + " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)" + " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)" + " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", + "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" + }, + { + GCRY_PK_ECDSA, + "(public-key" + " (ecdsa" + " (curve secp256r1)" + " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", + "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" } + }; static void @@ -97,12 +146,27 @@ check (void) for (i = 0; i < (sizeof (key_grips) / sizeof (*key_grips)); i++) { + if (gcry_pk_test_algo (key_grips[i].algo)) + { + if (verbose) + fprintf (stderr, "algo %d not available; test skipped\n", + key_grips[i].algo); + continue; + } err = gcry_sexp_sscan (&sexp, NULL, key_grips[i].key, strlen (key_grips[i].key)); - assert (! err); + if (err) + die ("scanning data %d failed: %s\n", i, gpg_strerror (err)); ret = gcry_pk_get_keygrip (sexp, buf); - assert (ret); - assert (! memcmp (key_grips[i].grip, buf, sizeof (buf))); + if (!ret) + die ("gcry_pk_get_keygrip failed for %d\n", i); + + if ( memcmp (key_grips[i].grip, buf, sizeof (buf)) ) + { + print_hex ("keygrip: ", buf, sizeof buf); + die ("keygrip for %d does not match\n", i); + } + gcry_sexp_release (sexp); } } |