From 8a012280e0f0a462c094d106355aa436fceb1b76 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Wed, 31 May 2017 14:33:45 +0200 Subject: [PATCH] gpg,common: Move the compliance framework. * common/Makefile.am (common_sources): Add new files. * common/compliance.c: New file. Move 'gnupg_pk_is_compliant' here, and tweak it to not rely on types private to gpg. * common/compliance.h: New file. Move the compliance enum here. * g10/keylist.c (print_compliance_flags): Adapt callsite. * g10/main.h (gnupg_pk_is_compliant): Remove prototype. * g10/misc.c (gnupg_pk_is_compliant): Remove function. * g10/options.h (opt): Use the new compliance enum. * sm/keylist.c (print_compliance_flags): Use the common functions. Signed-off-by: Justus Winter --- common/Makefile.am | 3 +- common/compliance.c | 144 ++++++++++++++++++++++++++++++++++++++++++++ common/compliance.h | 47 +++++++++++++++ g10/keylist.c | 12 +++- g10/main.h | 3 - g10/misc.c | 88 --------------------------- g10/options.h | 7 +-- sm/keylist.c | 5 +- 8 files changed, 207 insertions(+), 102 deletions(-) create mode 100644 common/compliance.c create mode 100644 common/compliance.h diff --git a/common/Makefile.am b/common/Makefile.am index 83d82ac1f..fcbe7ea66 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -93,7 +93,8 @@ common_sources = \ server-help.c server-help.h \ name-value.c name-value.h \ recsel.c recsel.h \ - ksba-io-support.c ksba-io-support.h + ksba-io-support.c ksba-io-support.h \ + compliance.c compliance.h if HAVE_W32_SYSTEM diff --git a/common/compliance.c b/common/compliance.c new file mode 100644 index 000000000..73c7ad724 --- /dev/null +++ b/common/compliance.c @@ -0,0 +1,144 @@ +/* compliance.c - Functions for compliance modi + * Copyright (C) 2017 g10 Code GmbH + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file 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 this program; if not, see . + */ + +#include +#include + +#include "openpgpdefs.h" +#include "logging.h" +#include "util.h" +#include "compliance.h" + +/* Return true if ALGO with a key of KEYLENGTH is compliant to the + * give COMPLIANCE mode. If KEY is not NULL, various bits of + * information will be extracted from it. If CURVENAME is not NULL, it + * is assumed to be the already computed. ALGO may be either an + * OpenPGP-style pubkey_algo_t, or a gcrypt-style enum gcry_pk_algos, + * both are compatible from the point of view of this function. */ +int +gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo, + gcry_mpi_t key[], unsigned int keylength, const char *curvename) +{ + enum { is_rsa, is_pgp5, is_elg_sign, is_ecc } algotype; + int result; + + switch (algo) + { + case PUBKEY_ALGO_RSA: + case PUBKEY_ALGO_RSA_E: + case PUBKEY_ALGO_RSA_S: + algotype = is_rsa; + break; + + case PUBKEY_ALGO_ELGAMAL_E: + case PUBKEY_ALGO_DSA: + algotype = is_pgp5; + break; + + case PUBKEY_ALGO_ECDH: + case PUBKEY_ALGO_ECDSA: + case PUBKEY_ALGO_EDDSA: + algotype = is_ecc; + break; + + case PUBKEY_ALGO_ELGAMAL: + algotype = is_elg_sign; + break; + + default: /* Unknown. */ + return 0; + } + + if (compliance == CO_DE_VS) + { + char *curve = NULL; + + switch (algotype) + { + case is_pgp5: + result = 0; + break; + + case is_rsa: + result = (keylength >= 2048); + break; + + case is_ecc: + if (!curvename && key) + { + curve = openpgp_oid_to_str (key[0]); + curvename = openpgp_oid_to_curve (curve, 0); + if (!curvename) + curvename = curve; + } + + result = (curvename + && algo != PUBKEY_ALGO_EDDSA + && (!strcmp (curvename, "brainpoolP256r1") + || !strcmp (curvename, "brainpoolP384r1") + || !strcmp (curvename, "brainpoolP512r1"))); + break; + + default: + result = 0; + } + xfree (curve); + } + else if (algotype == is_elg_sign) + { + /* An Elgamal signing key is only RFC-2440 compliant. */ + result = (compliance == CO_RFC2440); + } + else + { + result = 1; /* Assume compliance. */ + } + + return result; +} + + +const char * +gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance) +{ + switch (compliance) + { + case CO_GNUPG: + return "8"; + case CO_RFC4880: + case CO_RFC2440: + case CO_PGP6: + case CO_PGP7: + case CO_PGP8: + log_assert (!"no status code assigned for this compliance mode"); + case CO_DE_VS: + return "23"; + } + log_assert (!"invalid compliance mode"); +} diff --git a/common/compliance.h b/common/compliance.h new file mode 100644 index 000000000..123bd1b50 --- /dev/null +++ b/common/compliance.h @@ -0,0 +1,47 @@ +/* compliance.h - Definitions for compliance modi + * Copyright (C) 2017 g10 Code GmbH + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file 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 this program; if not, see . + */ + +#ifndef GNUPG_COMMON_COMPLIANCE_H +#define GNUPG_COMMON_COMPLIANCE_H + +#include +#include "openpgpdefs.h" + +enum gnupg_compliance_mode + { + CO_GNUPG, CO_RFC4880, CO_RFC2440, + CO_PGP6, CO_PGP7, CO_PGP8, CO_DE_VS + }; + +int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo, + gcry_mpi_t key[], unsigned int keylength, + const char *curvename); +const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance); + +#endif /*GNUPG_COMMON_COMPLIANCE_H*/ diff --git a/g10/keylist.c b/g10/keylist.c index e2b8fef05..4848bab64 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -44,6 +44,7 @@ #include "../common/mbox-util.h" #include "../common/zb32.h" #include "tofu.h" +#include "../common/compliance.h" static void list_all (ctrl_t, int, int); @@ -1180,14 +1181,19 @@ print_compliance_flags (PKT_public_key *pk, { int any = 0; + if (!keylength) + keylength = nbits_from_pk (pk); + if (pk->version == 5) { - es_fputs ("8", es_stdout); + es_fputs (gnupg_status_compliance_flag (CO_GNUPG), es_stdout); any++; } - if (gnupg_pk_is_compliant (CO_DE_VS, pk, keylength, curvename)) + if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, + keylength, curvename)) { - es_fputs (any? " 23":"23", es_stdout); + es_fprintf (es_stdout, any ? " %s" : "%s", + gnupg_status_compliance_flag (CO_DE_VS)); any++; } } diff --git a/g10/main.h b/g10/main.h index 129d746ff..c406113df 100644 --- a/g10/main.h +++ b/g10/main.h @@ -126,9 +126,6 @@ int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use); int openpgp_pk_algo_usage ( int algo ); const char *openpgp_pk_algo_name (pubkey_algo_t algo); -int gnupg_pk_is_compliant (int compliance, PKT_public_key *pk, - unsigned int keylength, const char *curvename); - enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo); int openpgp_md_test_algo (digest_algo_t algo); const char *openpgp_md_algo_name (int algo); diff --git a/g10/misc.c b/g10/misc.c index bdd27cf49..d485c9445 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -707,94 +707,6 @@ openpgp_pk_algo_name (pubkey_algo_t algo) } -/* Return true if PK is compliant to the give COMPLIANCE mode. If - * KEYLENGTH and CURVENAME are not 0/NULL the are assumed to be the - * already computed values from PK. */ -int -gnupg_pk_is_compliant (int compliance, PKT_public_key *pk, - unsigned int keylength, const char *curvename) -{ - enum { is_rsa, is_pgp5, is_elg_sign, is_ecc } algotype; - int result; - - switch (pk->pubkey_algo) - { - case PUBKEY_ALGO_RSA: - case PUBKEY_ALGO_RSA_E: - case PUBKEY_ALGO_RSA_S: - algotype = is_rsa; - break; - - case PUBKEY_ALGO_ELGAMAL_E: - case PUBKEY_ALGO_DSA: - algotype = is_pgp5; - break; - - case PUBKEY_ALGO_ECDH: - case PUBKEY_ALGO_ECDSA: - case PUBKEY_ALGO_EDDSA: - algotype = is_ecc; - break; - - case PUBKEY_ALGO_ELGAMAL: - algotype = is_elg_sign; - break; - - default: /* Unknown. */ - return 0; - } - - if (compliance == CO_DE_VS) - { - char *curve = NULL; - - switch (algotype) - { - case is_pgp5: - result = 0; - break; - - case is_rsa: - if (!keylength) - keylength = nbits_from_pk (pk); - result = (keylength >= 2048); - break; - - case is_ecc: - if (!curvename) - { - curve = openpgp_oid_to_str (pk->pkey[0]); - curvename = openpgp_oid_to_curve (curve, 0); - if (!curvename) - curvename = curve; - } - - result = (curvename - && pk->pubkey_algo != PUBKEY_ALGO_EDDSA - && (!strcmp (curvename, "brainpoolP256r1") - || !strcmp (curvename, "brainpoolP384r1") - || !strcmp (curvename, "brainpoolP512r1"))); - break; - - default: - result = 0; - } - xfree (curve); - } - else if (algotype == is_elg_sign) - { - /* An Elgamal signing key is only RFC-2440 compliant. */ - result = (compliance == CO_RFC2440); - } - else - { - result = 1; /* Assume compliance. */ - } - - return result; -} - - /* Explicit mapping of OpenPGP digest algos to Libgcrypt. */ /* FIXME: We do not yes use it everywhere. */ enum gcry_md_algos diff --git a/g10/options.h b/g10/options.h index c634f0ffd..8d1d93e3d 100644 --- a/g10/options.h +++ b/g10/options.h @@ -28,6 +28,7 @@ #include "packet.h" #include "tofu.h" #include "../common/session-env.h" +#include "../common/compliance.h" #ifndef EXTERN_UNLESS_MAIN_MODULE /* Norcraft can't cope with common symbols */ @@ -139,11 +140,7 @@ struct } trust_model; enum tofu_policy tofu_default_policy; int force_ownertrust; - enum - { - CO_GNUPG, CO_RFC4880, CO_RFC2440, - CO_PGP6, CO_PGP7, CO_PGP8, CO_DE_VS - } compliance; + enum gnupg_compliance_mode compliance; enum { KF_DEFAULT, KF_NONE, KF_SHORT, KF_LONG, KF_0xSHORT, KF_0xLONG diff --git a/sm/keylist.c b/sm/keylist.c index 13de45d9c..abec049b7 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -36,6 +36,7 @@ #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */ #include "../common/i18n.h" #include "../common/tlv.h" +#include "../common/compliance.h" struct list_external_parm_s { @@ -351,8 +352,8 @@ email_kludge (const char *name) static void print_compliance_flags (int algo, unsigned int nbits, estream_t fp) { - if (algo == GCRY_PK_RSA && nbits >= 2048) - es_fputs ("23", fp); + if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL)) + es_fputs (gnupg_status_compliance_flag (CO_DE_VS), fp); }