From 6f8fa678c1f4672165cd82ddb43ec3546d9552a9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 21 Mar 2016 01:45:53 +0100 Subject: implementing #3987 --- doc/taler-auditor-sign.1 | 5 +- src/exchange-lib/exchange_api_handle.c | 12 +++- src/exchange-tools/taler-auditor-sign.c | 31 +++++++--- src/exchange/taler-exchange-httpd_keystate.c | 10 ++- src/exchangedb/exchangedb_keyio.c | 92 +++++++++++++++++++++------- src/include/taler_exchange_service.h | 20 +++--- src/include/taler_exchangedb_lib.h | 51 +++++++-------- src/include/taler_signatures.h | 7 ++- 8 files changed, 159 insertions(+), 69 deletions(-) diff --git a/doc/taler-auditor-sign.1 b/doc/taler-auditor-sign.1 index 177d0df04..f0f90a5b8 100644 --- a/doc/taler-auditor-sign.1 +++ b/doc/taler-auditor-sign.1 @@ -1,4 +1,4 @@ -.TH TALER\-AUDITOR\-SIGN 1 "Sep 15, 2015" "GNU Taler" +.TH TALER\-AUDITOR\-SIGN 1 "Mar 15, 2016" "GNU Taler" .SH NAME taler\-auditor\-sign \- Sign exchange denomination as auditor. @@ -22,6 +22,9 @@ Print short help on options. .IP "\-m KEY, \-\-exchange-key=KEY" Public key of the exchange in Crockford base32 encoding, for example as generated by gnunet\-ecc \-p. .B +.IP "\-u URL, \-\-auditor-url=URL" +URL of the auditor. Provides informative link for the user to learn more about the auditor. +.B .IP "\-r FILE, \-\-exchange-request=FILE" File with the exchange's denomination key signing request as generated by taler\-exchange\-keyup \-o. .B diff --git a/src/exchange-lib/exchange_api_handle.c b/src/exchange-lib/exchange_api_handle.c index aaca8bac1..26f5e7e15 100644 --- a/src/exchange-lib/exchange_api_handle.c +++ b/src/exchange-lib/exchange_api_handle.c @@ -360,16 +360,18 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, unsigned int len; unsigned int off; unsigned int i; + const char *auditor_url; struct TALER_ExchangeKeyValidityPS kv; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("auditor_pub", - &auditor->auditor_pub), + &auditor->auditor_pub), + GNUNET_JSON_spec_string ("auditor_url", + &auditor_url), GNUNET_JSON_spec_json ("denomination_keys", - &keys), + &keys), GNUNET_JSON_spec_end() }; - auditor->auditor_url = NULL; /* #3987 */ if (GNUNET_OK != GNUNET_JSON_parse (auditor_obj, spec, @@ -378,8 +380,12 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, GNUNET_break_op (0); return GNUNET_SYSERR; } + auditor->auditor_url = GNUNET_strdup (auditor_url); kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS); kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS)); + GNUNET_CRYPTO_hash (auditor_url, + strlen (auditor_url) + 1, + &kv.auditor_url_hash); kv.master = key_data->master_pub; len = json_array_size (keys); auditor->denom_keys = GNUNET_new_array (len, diff --git a/src/exchange-tools/taler-auditor-sign.c b/src/exchange-tools/taler-auditor-sign.c index e4821f411..bde34b2a3 100644 --- a/src/exchange-tools/taler-auditor-sign.c +++ b/src/exchange-tools/taler-auditor-sign.c @@ -49,6 +49,11 @@ static char *exchange_request_file; */ static char *output_file; +/** + * URL of the auditor (informative for the user). + */ +static char *auditor_url; + /** * Master public key of the exchange. */ @@ -134,6 +139,10 @@ main (int argc, {'m', "exchange-key", "KEY", "public key of the exchange (Crockford base32 encoded)", 1, &GNUNET_GETOPT_set_filename, &exchange_public_key}, + {'u', "auditor-url", "URL", + "URL of the auditor (informative link for the user)", 1, + &GNUNET_GETOPT_set_string, &auditor_url}, + TALER_GETOPT_OPTION_HELP ("Private key of the auditor to use for signing"), {'r', "exchange-request", "FILE", "set of keys the exchange requested the auditor to sign", 1, &GNUNET_GETOPT_set_string, &exchange_request_file}, @@ -168,6 +177,12 @@ main (int argc, "Auditor key file not given\n"); return 1; } + if (NULL == auditor_url) + { + fprintf (stderr, + "Auditor URL not given\n"); + return 1; + } eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (auditor_key_file); if (NULL == eddsa_priv) { @@ -240,6 +255,9 @@ main (int argc, dks_len = in_size / sizeof (struct TALER_DenominationKeyValidityPS); kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS); kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS)); + GNUNET_CRYPTO_hash (auditor_url, + strlen (auditor_url) + 1, + &kv.auditor_url_hash); kv.master = master_public_key; dks = GNUNET_new_array (dks_len, struct TALER_DenominationKeyValidityPS); @@ -281,8 +299,6 @@ main (int argc, GNUNET_CRYPTO_eddsa_sign (eddsa_priv, &kv.purpose, &sigs[i].eddsa_sig); - - } if (NULL == output_file) @@ -298,11 +314,12 @@ main (int argc, /* write result to disk */ if (GNUNET_OK != TALER_EXCHANGEDB_auditor_write (output_file, - &apub, - sigs, - &master_public_key, - dks_len, - dks)) + &apub, + auditor_url, + sigs, + &master_public_key, + dks_len, + dks)) { fprintf (stderr, "Failed to write to file `%s': %s\n", diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c index bf91b8183..dbb72fab2 100644 --- a/src/exchange/taler-exchange-httpd_keystate.c +++ b/src/exchange/taler-exchange-httpd_keystate.c @@ -419,6 +419,7 @@ reload_keys_sign_iter (void *cls, * Convert information from an auditor to a JSON object. * * @param apub the auditor's public key + * @param auditor_url URL of the auditor * @param dki_len length of @a dki and @a asigs arrays * @param asigs the auditor's signatures * @param dki array of denomination coin data signed by the auditor @@ -426,6 +427,7 @@ reload_keys_sign_iter (void *cls, */ static json_t * auditor_to_json (const struct TALER_AuditorPublicKeyP *apub, + const char *auditor_url, unsigned int dki_len, const struct TALER_AuditorSignatureP **asigs, const struct TALER_DenominationKeyValidityPS **dki) @@ -442,10 +444,11 @@ auditor_to_json (const struct TALER_AuditorPublicKeyP *apub, sizeof (struct GNUNET_HashCode)), "auditor_sig", GNUNET_JSON_from_data (asigs[i], - sizeof (struct TALER_AuditorSignatureP)))); + sizeof (struct TALER_AuditorSignatureP)))); return - json_pack ("{s:o, s:o}", + json_pack ("{s:o, s:s, s:o}", "denomination_keys", ja, + "auditor_url", auditor_url, "auditor_pub", GNUNET_JSON_from_data (apub, sizeof (struct TALER_AuditorPublicKeyP))); @@ -460,6 +463,7 @@ auditor_to_json (const struct TALER_AuditorPublicKeyP *apub, * * @param cls closure with the `struct TMH_KS_StateHandle *` * @param apub the auditor's public key + * @param auditor_url URL of the auditor * @param mpub the exchange's public key (as expected by the auditor) * @param dki_len length of @a dki and @a asigs * @param asigs array with the auditor's signatures, of length @a dki_len @@ -471,6 +475,7 @@ auditor_to_json (const struct TALER_AuditorPublicKeyP *apub, static int reload_auditor_iter (void *cls, const struct TALER_AuditorPublicKeyP *apub, + const char *auditor_url, const struct TALER_MasterPublicKeyP *mpub, unsigned int dki_len, const struct TALER_AuditorSignatureP *asigs, @@ -508,6 +513,7 @@ reload_auditor_iter (void *cls, /* add auditor information to our /keys response */ json_array_append_new (ctx->auditors_array, auditor_to_json (apub, + auditor_url, keep, kept_asigs, kept_dkis)); diff --git a/src/exchangedb/exchangedb_keyio.c b/src/exchangedb/exchangedb_keyio.c index 6b8ca24e3..e560e8d6b 100644 --- a/src/exchangedb/exchangedb_keyio.c +++ b/src/exchangedb/exchangedb_keyio.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. + Copyright (C) 2014, 2015, 2016 Inria & GNUnet e.V. TALER 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 @@ -93,8 +93,8 @@ signkeys_iterate_dir_iter (void *cls, */ int TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir, - TALER_EXCHANGEDB_SigningKeyIterator it, - void *it_cls) + TALER_EXCHANGEDB_SigningKeyIterator it, + void *it_cls) { char *signkey_dir; struct SignkeysIterateContext skc; @@ -123,7 +123,7 @@ TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir, */ int TALER_EXCHANGEDB_denomination_key_read (const char *filename, - struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) { uint64_t size; size_t offset; @@ -186,7 +186,7 @@ TALER_EXCHANGEDB_denomination_key_read (const char *filename, */ int TALER_EXCHANGEDB_denomination_key_write (const char *filename, - const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) { char *priv_enc; size_t priv_enc_size; @@ -331,8 +331,8 @@ denomkeys_iterate_topdir_iter (void *cls, */ int TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, - TALER_EXCHANGEDB_DenominationKeyIterator it, - void *it_cls) + TALER_EXCHANGEDB_DenominationKeyIterator it, + void *it_cls) { char *dir; struct DenomkeysIterateContext dic; @@ -388,6 +388,11 @@ struct AuditorFileHeaderP */ struct TALER_MasterPublicKeyP mpub; + /** + * Number of signatures and DKI entries in this file. + */ + uint32_t dki_len; + }; GNUNET_NETWORK_STRUCT_END @@ -412,7 +417,9 @@ auditor_iter (void *cls, struct AuditorFileHeaderP *af; const struct TALER_AuditorSignatureP *sigs; const struct TALER_DenominationKeyValidityPS *dki; - unsigned int len; + const char *auditor_url; + unsigned int dki_len; + size_t url_len; int ret; if (GNUNET_OK != GNUNET_DISK_file_size (filename, @@ -425,10 +432,7 @@ auditor_iter (void *cls, filename); return GNUNET_SYSERR; } - if ( (size < sizeof (struct AuditorFileHeaderP)) || - (0 != (len = ((size - sizeof (struct AuditorFileHeaderP)) % - (sizeof (struct TALER_DenominationKeyValidityPS) + - sizeof (struct TALER_AuditorSignatureP))))) ) + if (size < sizeof (struct AuditorFileHeaderP)) { GNUNET_break (0); return GNUNET_SYSERR; @@ -445,12 +449,49 @@ auditor_iter (void *cls, GNUNET_free (af); return GNUNET_SYSERR; } + dki_len = ntohl (af->dki_len); + if (0 == dki_len) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No signed keys in %s\n", + filename); + GNUNET_free (af); + return GNUNET_SYSERR; + } + if ( (size - sizeof (struct AuditorFileHeaderP)) / dki_len < + (sizeof (struct TALER_DenominationKeyValidityPS) + + sizeof (struct TALER_AuditorSignatureP)) ) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Malformed key file %s\n", + filename); + GNUNET_free (af); + return GNUNET_SYSERR; + } + url_len = size + - sizeof (struct AuditorFileHeaderP) + - dki_len * (sizeof (struct TALER_DenominationKeyValidityPS) + + sizeof (struct TALER_AuditorSignatureP)); sigs = (const struct TALER_AuditorSignatureP *) &af[1]; - dki = (const struct TALER_DenominationKeyValidityPS *) &sigs[len]; + dki = (const struct TALER_DenominationKeyValidityPS *) &sigs[dki_len]; + auditor_url = (const char *) &dki[dki_len]; + if ( (0 == url_len) || + ('\0' != auditor_url[url_len - 1]) ) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Malformed key file %s\n", + filename); + GNUNET_free (af); + return GNUNET_SYSERR; + } ret = aic->it (aic->it_cls, &af->apub, + auditor_url, &af->mpub, - len, + dki_len, sigs, dki); GNUNET_free (af); @@ -473,8 +514,8 @@ auditor_iter (void *cls, */ int TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, - TALER_EXCHANGEDB_AuditorIterator it, - void *it_cls) + TALER_EXCHANGEDB_AuditorIterator it, + void *it_cls) { char *dir; struct AuditorIterateContext aic; @@ -498,6 +539,7 @@ TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, * * @param filename the file where to write the auditor information to * @param apub the auditor's public key + * @param auditor_url the URL of the auditor * @param asigs the auditor's signatures, array of length @a dki_len * @param mpub the exchange's public key (as expected by the auditor) * @param dki_len length of @a dki @@ -506,11 +548,12 @@ TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, */ int TALER_EXCHANGEDB_auditor_write (const char *filename, - const struct TALER_AuditorPublicKeyP *apub, - const struct TALER_AuditorSignatureP *asigs, - const struct TALER_MasterPublicKeyP *mpub, - unsigned int dki_len, - const struct TALER_DenominationKeyValidityPS *dki) + const struct TALER_AuditorPublicKeyP *apub, + const char *auditor_url, + const struct TALER_AuditorSignatureP *asigs, + const struct TALER_MasterPublicKeyP *mpub, + unsigned int dki_len, + const struct TALER_DenominationKeyValidityPS *dki) { struct AuditorFileHeaderP af; struct GNUNET_DISK_FileHandle *fh; @@ -521,6 +564,7 @@ TALER_EXCHANGEDB_auditor_write (const char *filename, af.apub = *apub; af.mpub = *mpub; + af.dki_len = htonl ((uint32_t) dki_len); ret = GNUNET_SYSERR; if (NULL == (fh = GNUNET_DISK_file_open (filename, @@ -546,6 +590,12 @@ TALER_EXCHANGEDB_auditor_write (const char *filename, dki, wsize)) ret = GNUNET_OK; + wsize = strlen (auditor_url) + 1; + if (wsize == + GNUNET_DISK_file_write (fh, + auditor_url, + wsize)) + ret = GNUNET_OK; cleanup: eno = errno; if (NULL != fh) diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index c3ecba968..cb1bd12aa 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -208,19 +208,19 @@ struct TALER_EXCHANGE_DenomPublicKey struct TALER_EXCHANGE_AuditorInformation { /** - * Public key of the auditing institution. + * Public key of the auditing institution. Wallets and merchants + * are expected to be configured with a set of public keys of + * auditors that they deem acceptable. These public keys are + * the roots of the Taler PKI. */ struct TALER_AuditorPublicKeyP auditor_pub; /** - * URL of the auditing institution. The application must check that - * this is an acceptable auditor for its purpose and also verify - * that the @a auditor_pub matches the auditor's public key given at - * that website. We expect that in practice software is going to - * often ship with an initial list of accepted auditors, just like - * browsers ship with a CA root store. - * - * This field may be NULL. (#3987). + * URL of the auditing institution. Signed by the auditor's public + * key, this URL is a place where applications can direct users for + * additional information about the auditor. In the future, there + * should also be an auditor API for automated submission about + * claims of misbehaving exchange providers. */ const char *auditor_url; @@ -230,7 +230,7 @@ struct TALER_EXCHANGE_AuditorInformation unsigned int num_denom_keys; /** - * Array of length @a denom_keys with the denomination + * Array of length @a num_denom_keys with the denomination * keys audited by this auditor. Note that the array * elements point to the same locations as the entries * in the key's main `denom_keys` array. diff --git a/src/include/taler_exchangedb_lib.h b/src/include/taler_exchangedb_lib.h index 347ad0650..e13df2d46 100644 --- a/src/include/taler_exchangedb_lib.h +++ b/src/include/taler_exchangedb_lib.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. + Copyright (C) 2014, 2015, 2016 Inria & GNUnet e.V. TALER 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 @@ -125,8 +125,8 @@ struct TALER_EXCHANGEDB_DenominationKeyIssueInformation */ typedef int (*TALER_EXCHANGEDB_SigningKeyIterator)(void *cls, - const char *filename, - const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski); + const char *filename, + const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski); /** @@ -143,8 +143,8 @@ typedef int */ int TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir, - TALER_EXCHANGEDB_SigningKeyIterator it, - void *it_cls); + TALER_EXCHANGEDB_SigningKeyIterator it, + void *it_cls); @@ -160,8 +160,8 @@ TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir, */ typedef int (*TALER_EXCHANGEDB_DenominationKeyIterator)(void *cls, - const char *alias, - const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + const char *alias, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); /** @@ -179,8 +179,8 @@ typedef int */ int TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, - TALER_EXCHANGEDB_DenominationKeyIterator it, - void *it_cls); + TALER_EXCHANGEDB_DenominationKeyIterator it, + void *it_cls); /** @@ -192,7 +192,7 @@ TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, */ int TALER_EXCHANGEDB_denomination_key_write (const char *filename, - const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); /** @@ -204,7 +204,7 @@ TALER_EXCHANGEDB_denomination_key_write (const char *filename, */ int TALER_EXCHANGEDB_denomination_key_read (const char *filename, - struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); /** @@ -212,6 +212,7 @@ TALER_EXCHANGEDB_denomination_key_read (const char *filename, * * @param cls closure * @param apub the auditor's public key + * @param auditor_url URL of the auditor * @param mpub the exchange's public key (as expected by the auditor) * @param dki_len length of @a asig and @a dki arrays * @param asigs array of the auditor's signatures over the @a dks, of length @a dki_len @@ -222,11 +223,12 @@ TALER_EXCHANGEDB_denomination_key_read (const char *filename, */ typedef int (*TALER_EXCHANGEDB_AuditorIterator)(void *cls, - const struct TALER_AuditorPublicKeyP *apub, - const struct TALER_MasterPublicKeyP *mpub, - unsigned int dki_len, - const struct TALER_AuditorSignatureP *asigs, - const struct TALER_DenominationKeyValidityPS *dki); + const struct TALER_AuditorPublicKeyP *apub, + const char *auditor_url, + const struct TALER_MasterPublicKeyP *mpub, + unsigned int dki_len, + const struct TALER_AuditorSignatureP *asigs, + const struct TALER_DenominationKeyValidityPS *dki); /** @@ -244,8 +246,8 @@ typedef int */ int TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, - TALER_EXCHANGEDB_AuditorIterator it, - void *it_cls); + TALER_EXCHANGEDB_AuditorIterator it, + void *it_cls); /** @@ -253,6 +255,7 @@ TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, * * @param filename the file where to write the auditor information to * @param apub the auditor's public key + * @param auditor_url the URL of the auditor * @param asigs the auditor's signatures, array of length @a dki_len * @param mpub the exchange's public key (as expected by the auditor) * @param dki_len length of @a dki and @a asigs arrays @@ -261,11 +264,12 @@ TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, */ int TALER_EXCHANGEDB_auditor_write (const char *filename, - const struct TALER_AuditorPublicKeyP *apub, - const struct TALER_AuditorSignatureP *asigs, - const struct TALER_MasterPublicKeyP *mpub, - unsigned int dki_len, - const struct TALER_DenominationKeyValidityPS *dki); + const struct TALER_AuditorPublicKeyP *apub, + const char *auditor_url, + const struct TALER_AuditorSignatureP *asigs, + const struct TALER_MasterPublicKeyP *mpub, + unsigned int dki_len, + const struct TALER_DenominationKeyValidityPS *dki); /** @@ -287,5 +291,4 @@ void TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin); - #endif diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 729bed262..d958f16ba 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -655,9 +655,14 @@ struct TALER_ExchangeKeyValidityPS */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + /** + * Hash of the auditor's URL. + */ + struct GNUNET_HashCode auditor_url_hash; + /** * The long-term offline master key of the exchange, affirmed by the - * auditor. + * auditor. Hashed string, including 0-terminator. */ struct TALER_MasterPublicKeyP master; -- cgit v1.2.3