diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-02-09 16:00:23 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-02-09 16:00:23 +0900 |
commit | 5ce840383da7cf82ffa7dfaeda187f3fe3d591a7 (patch) | |
tree | f93fb33cde2a62aa414b61dca085f3fd0613aaca /sm | |
parent | d9f0d99e31569835e295b990029c6dd19554299c (diff) | |
download | gpg2-5ce840383da7cf82ffa7dfaeda187f3fe3d591a7.tar.gz gpg2-5ce840383da7cf82ffa7dfaeda187f3fe3d591a7.tar.bz2 gpg2-5ce840383da7cf82ffa7dfaeda187f3fe3d591a7.zip |
Imported Upstream version 2.1.22upstream/2.1.22
Diffstat (limited to 'sm')
-rw-r--r-- | sm/call-agent.c | 19 | ||||
-rw-r--r-- | sm/decrypt.c | 53 | ||||
-rw-r--r-- | sm/encrypt.c | 54 | ||||
-rw-r--r-- | sm/gpgsm.c | 56 | ||||
-rw-r--r-- | sm/gpgsm.h | 2 | ||||
-rw-r--r-- | sm/keylist.c | 5 | ||||
-rw-r--r-- | sm/sign.c | 40 | ||||
-rw-r--r-- | sm/verify.c | 42 |
8 files changed, 260 insertions, 11 deletions
diff --git a/sm/call-agent.c b/sm/call-agent.c index 0e47c14..ba8fb12 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -171,6 +171,25 @@ start_agent (ctrl_t ctrl) str_pinentry_mode (opt.pinentry_mode), gpg_strerror (rc)); } + + /* In DE_VS mode under Windows we require that the JENT RNG + * is active. */ +#ifdef HAVE_W32_SYSTEM + if (!rc && opt.compliance == CO_DE_VS) + { + if (assuan_transact (agent_ctx, "GETINFO jent_active", + NULL, NULL, NULL, NULL, NULL, NULL)) + { + rc = gpg_error (GPG_ERR_FORBIDDEN); + log_error (_("%s is not compliant with %s mode\n"), + GPG_AGENT_NAME, + gnupg_compliance_option_string (opt.compliance)); + gpgsm_status_with_error (ctrl, STATUS_ERROR, + "random-compliance", rc); + } + } +#endif /*HAVE_W32_SYSTEM*/ + } } diff --git a/sm/decrypt.c b/sm/decrypt.c index 976bd12..cdce1d4 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -32,6 +32,7 @@ #include "keydb.h" #include "../common/i18n.h" +#include "../common/compliance.h" struct decrypt_filter_parm_s { @@ -41,7 +42,7 @@ struct decrypt_filter_parm_s gcry_cipher_hd_t hd; char iv[16]; size_t ivlen; - int any_data; /* dod we push anything through the filter at all? */ + int any_data; /* did we push anything through the filter at all? */ unsigned char lastblock[16]; /* to strip the padding we have to keep this one */ char helpblock[16]; /* needed because there is no block buffering in @@ -325,6 +326,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) int algo, mode; const char *algoid; int any_key = 0; + int is_de_vs; /* Computed compliance with CO_DE_VS. */ audit_log (ctrl->audit, AUDIT_GOT_DATA); @@ -356,6 +358,20 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) goto leave; } + /* Check compliance. */ + if (! gnupg_cipher_is_allowed (opt.compliance, 0, algo, mode)) + { + log_error (_("cipher algorithm '%s'" + " may not be used in %s mode\n"), + gcry_cipher_algo_name (algo), + gnupg_compliance_option_string (opt.compliance)); + rc = gpg_error (GPG_ERR_CIPHER_ALGO); + goto leave; + } + + /* For CMS, CO_DE_VS demands CBC mode. */ + is_de_vs = gnupg_cipher_is_compliant (CO_DE_VS, algo, mode); + audit_log_i (ctrl->audit, AUDIT_DATA_CIPHER_ALGO, algo); dfparm.algo = algo; dfparm.mode = mode; @@ -460,7 +476,37 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) hexkeygrip = gpgsm_get_keygrip_hexstring (cert); desc = gpgsm_format_keydesc (cert); + { + unsigned int nbits; + int pk_algo = gpgsm_get_key_algo_info (cert, &nbits); + + /* Print compliance warning. */ + if (! gnupg_pk_is_compliant (opt.compliance, + pk_algo, NULL, nbits, NULL)) + { + char kidstr[10+1]; + + snprintf (kidstr, sizeof kidstr, "0x%08lX", + gpgsm_get_short_fingerprint (cert, NULL)); + log_info + (_("Note: key %s is not suitable for encryption" + " in %s mode\n"), + kidstr, + gnupg_compliance_option_string (opt.compliance)); + } + + /* Check that all certs are compliant with CO_DE_VS. */ + is_de_vs = + (is_de_vs + && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, + nbits, NULL)); + } + oops: + if (rc) + /* We cannot check compliance of certs that we + * don't have. */ + is_de_vs = 0; xfree (issuer); xfree (serial); ksba_cert_release (cert); @@ -489,6 +535,11 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) ksba_writer_set_filter (writer, decrypt_filter, &dfparm); + + if (is_de_vs) + gpgsm_status (ctrl, STATUS_DECRYPTION_COMPLIANCE_MODE, + gnupg_status_compliance_flag (CO_DE_VS)); + } audit_log_ok (ctrl->audit, AUDIT_RECP_RESULT, rc); } diff --git a/sm/encrypt.c b/sm/encrypt.c index c43a9e6..6213a66 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -33,6 +33,7 @@ #include "keydb.h" #include "../common/i18n.h" +#include "../common/compliance.h" struct dek_s { @@ -312,6 +313,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) estream_t data_fp = NULL; certlist_t cl; int count; + int compliant; memset (&encparm, 0, sizeof encparm); @@ -405,6 +407,29 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) goto leave; } + /* Check compliance. */ + if (!gnupg_cipher_is_allowed + (opt.compliance, 1, gcry_cipher_map_name (opt.def_cipher_algoid), + gcry_cipher_mode_from_oid (opt.def_cipher_algoid))) + { + log_error (_("cipher algorithm '%s' may not be used in %s mode\n"), + opt.def_cipher_algoid, + gnupg_compliance_option_string (opt.compliance)); + rc = gpg_error (GPG_ERR_CIPHER_ALGO); + goto leave; + } + + if (!gnupg_rng_is_compliant (opt.compliance)) + { + rc = gpg_error (GPG_ERR_FORBIDDEN); + log_error (_("%s is not compliant with %s mode\n"), + "RNG", + gnupg_compliance_option_string (opt.compliance)); + gpgsm_status_with_error (ctrl, STATUS_ERROR, + "random-compliance", rc); + goto leave; + } + /* Create a session key */ dek = xtrycalloc_secure (1, sizeof *dek); if (!dek) @@ -442,11 +467,36 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) audit_log_s (ctrl->audit, AUDIT_SESSION_KEY, dek->algoid); + compliant = gnupg_cipher_is_compliant (CO_DE_VS, dek->algo, + GCRY_CIPHER_MODE_CBC); + /* Gather certificates of recipients, encrypt the session key for each and store them in the CMS object */ for (recpno = 0, cl = recplist; cl; recpno++, cl = cl->next) { unsigned char *encval; + unsigned int nbits; + int pk_algo; + + /* Check compliance. */ + pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits); + if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, NULL, nbits, NULL)) + { + char kidstr[10+1]; + + snprintf (kidstr, sizeof kidstr, "0x%08lX", + gpgsm_get_short_fingerprint (cl->cert, NULL)); + log_info (_("WARNING: key %s is not suitable for encryption" + " in %s mode\n"), + kidstr, + gnupg_compliance_option_string (opt.compliance)); + } + + /* Fixme: When adding ECC we need to provide the curvename and + * the key to gnupg_pk_is_compliant. */ + if (compliant + && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)) + compliant = 0; rc = encrypt_dek (dek, cl->cert, &encval); if (rc) @@ -480,6 +530,10 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) } } + if (compliant) + gpgsm_status (ctrl, STATUS_ENCRYPTION_COMPLIANCE_MODE, + gnupg_status_compliance_flag (CO_DE_VS)); + /* Main control loop for encryption. */ recpno = 0; do @@ -41,6 +41,7 @@ #include "../common/gc-opt-flags.h" #include "../common/asshelp.h" #include "../common/init.h" +#include "../common/compliance.h" #ifndef O_BINARY @@ -946,6 +947,9 @@ main ( int argc, char **argv) dotlock_create (NULL, 0); /* Register lockfile cleanup. */ + /* Tell the compliance module who we are. */ + gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPGSM); + opt.autostart = 1; opt.session_env = session_env_new (); if (!opt.session_env) @@ -1443,7 +1447,19 @@ main ( int argc, char **argv) case oNoAutostart: opt.autostart = 0; break; case oCompliance: - /* Dummy option for now. */ + { + struct gnupg_compliance_option compliance_options[] = + { + { "de-vs", CO_DE_VS } + }; + int compliance = gnupg_parse_compliance_option (pargs.r.ret_str, + compliance_options, + DIM (compliance_options), + opt.quiet); + if (compliance < 0) + gpgsm_exit (1); + opt.compliance = compliance; + } break; default: @@ -1598,6 +1614,44 @@ main ( int argc, char **argv) } } + /* Check our chosen algorithms against the list of allowed + * algorithms in the current compliance mode, and fail hard if it is + * not. This is us being nice to the user informing her early that + * the chosen algorithms are not available. We also check and + * enforce this right before the actual operation. */ + if (! gnupg_cipher_is_allowed (opt.compliance, + cmd == aEncr || cmd == aSignEncr, + gcry_cipher_map_name (opt.def_cipher_algoid), + GCRY_CIPHER_MODE_NONE) + && ! gnupg_cipher_is_allowed (opt.compliance, + cmd == aEncr || cmd == aSignEncr, + gcry_cipher_mode_from_oid + (opt.def_cipher_algoid), + GCRY_CIPHER_MODE_NONE)) + log_error (_("cipher algorithm '%s' may not be used in %s mode\n"), + opt.def_cipher_algoid, + gnupg_compliance_option_string (opt.compliance)); + + if (forced_digest_algo + && ! gnupg_digest_is_allowed (opt.compliance, + cmd == aSign + || cmd == aSignEncr + || cmd == aClearsign, + opt.forced_digest_algo)) + log_error (_("digest algorithm '%s' may not be used in %s mode\n"), + forced_digest_algo, + gnupg_compliance_option_string (opt.compliance)); + + if (extra_digest_algo + && ! gnupg_digest_is_allowed (opt.compliance, + cmd == aSign + || cmd == aSignEncr + || cmd == aClearsign, + opt.extra_digest_algo)) + log_error (_("digest algorithm '%s' may not be used in %s mode\n"), + forced_digest_algo, + gnupg_compliance_option_string (opt.compliance)); + if (log_get_errorcount(0)) gpgsm_exit(2); @@ -34,6 +34,7 @@ #include "../common/audit.h" #include "../common/session-env.h" #include "../common/ksba-io-support.h" +#include "../common/compliance.h" #define MAX_DIGEST_LEN 64 @@ -144,6 +145,7 @@ struct OID per string. */ strlist_t ignored_cert_extensions; + enum gnupg_compliance_mode compliance; } opt; /* Debug values and macros. */ diff --git a/sm/keylist.c b/sm/keylist.c index 13de45d..abec049 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); } @@ -339,6 +339,17 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } + if (!gnupg_rng_is_compliant (opt.compliance)) + { + rc = gpg_error (GPG_ERR_FORBIDDEN); + log_error (_("%s is not compliant with %s mode\n"), + "RNG", + gnupg_compliance_option_string (opt.compliance)); + gpgsm_status_with_error (ctrl, STATUS_ERROR, + "random-compliance", rc); + goto leave; + } + ctrl->pem_name = "SIGNED MESSAGE"; rc = gnupg_ksba_create_writer (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0) @@ -460,6 +471,35 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, break; } cl->hash_algo_oid = oid; + + /* Check compliance. */ + if (! gnupg_digest_is_allowed (opt.compliance, 1, cl->hash_algo)) + { + log_error (_("digest algorithm '%s' may not be used in %s mode\n"), + gcry_md_algo_name (cl->hash_algo), + gnupg_compliance_option_string (opt.compliance)); + err = gpg_error (GPG_ERR_DIGEST_ALGO); + goto leave; + } + + { + unsigned int nbits; + int pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits); + + if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, + NULL, nbits, NULL)) + { + char kidstr[10+1]; + + snprintf (kidstr, sizeof kidstr, "0x%08lX", + gpgsm_get_short_fingerprint (cl->cert, NULL)); + log_error (_("key %s may not be used for signing in %s mode\n"), + kidstr, + gnupg_compliance_option_string (opt.compliance)); + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto leave; + } + } } if (opt.verbose) diff --git a/sm/verify.c b/sm/verify.c index 6c034e6..10b3f43 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -33,6 +33,7 @@ #include "keydb.h" #include "../common/i18n.h" +#include "../common/compliance.h" static char * strtimestamp_r (ksba_isotime_t atime) @@ -341,16 +342,11 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) &msgdigest, &msgdigestlen); if (!rc) { - size_t is_enabled; - algoid = ksba_cms_get_digest_algo (cms, signer); algo = gcry_md_map_name (algoid); if (DBG_X509) log_debug ("signer %d - digest algo: %d\n", signer, algo); - is_enabled = sizeof algo; - if ( gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED, - &algo, &is_enabled) - || !is_enabled) + if (! gcry_md_is_enabled (data_md, algo)) { log_error ("digest algo %d (%s) has not been enabled\n", algo, algoid?algoid:""); @@ -454,6 +450,39 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) goto next_signer; } + /* Check compliance. */ + { + unsigned int nbits; + int pk_algo = gpgsm_get_key_algo_info (cert, &nbits); + + if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION, + pk_algo, NULL, nbits, NULL)) + { + char kidstr[10+1]; + + snprintf (kidstr, sizeof kidstr, "0x%08lX", + gpgsm_get_short_fingerprint (cert, NULL)); + log_error (_("key %s may not be used for signing in %s mode\n"), + kidstr, + gnupg_compliance_option_string (opt.compliance)); + goto next_signer; + } + + if (! gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo)) + { + log_error (_("digest algorithm '%s' may not be used in %s mode\n"), + gcry_md_algo_name (sigval_hash_algo), + gnupg_compliance_option_string (opt.compliance)); + goto next_signer; + } + + /* Check compliance with CO_DE_VS. */ + if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL) + && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo)) + gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE, + gnupg_status_compliance_flag (CO_DE_VS)); + } + log_info (_("Signature made ")); if (*sigtime) dump_isotime (sigtime); @@ -636,7 +665,6 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)? "0 chain": "0 shell"); - next_signer: rc = 0; xfree (issuer); |