diff options
-rw-r--r-- | sm/ChangeLog | 21 | ||||
-rw-r--r-- | sm/certchain.c | 39 | ||||
-rw-r--r-- | sm/certpath.c | 39 | ||||
-rw-r--r-- | sm/gpgsm.c | 11 | ||||
-rw-r--r-- | sm/server.c | 1 | ||||
-rw-r--r-- | sm/sign.c | 104 | ||||
-rw-r--r-- | sm/verify.c | 31 |
7 files changed, 212 insertions, 34 deletions
diff --git a/sm/ChangeLog b/sm/ChangeLog index d5ae4f679..8e217eecd 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,24 @@ +2002-06-12 Werner Koch <[email protected]> + + * sign.c (hash_and_copy_data): New. + (gpgsm_sign): Implemented normal (non-detached) signatures. + * gpgsm.c (main): Ditto. + + * certpath.c (gpgsm_validate_path): Special error handling for + no policy match. + +2002-06-10 Werner Koch <[email protected]> + + * server.c (get_status_string): Add STATUS_ERROR. + + * certpath.c (gpgsm_validate_path): Tweaked the error checking to + return error codes in a more sensitive way. + * verify.c (gpgsm_verify): Send status TRUST_NEVER also for a bad + CA certificate and when the certificate has been revoked. Issue + TRUST_FULLY even when the cert has expired. Append an error token + to these status lines. Issue the new generic error status when a + cert was not found and when leaving the function. + 2002-06-04 Werner Koch <[email protected]> * gpgsm.c (main): New command --list-sigs diff --git a/sm/certchain.c b/sm/certchain.c index 28c0be52f..0b2d8b4fc 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -317,6 +317,11 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) KsbaCert subject_cert = NULL, issuer_cert = NULL; time_t current_time = gnupg_get_time (); time_t exptime = 0; + int any_expired = 0; + int any_revoked = 0; + int any_no_crl = 0; + int any_crl_too_old = 0; + int any_no_policy_match = 0; if (r_exptime) *r_exptime = 0; @@ -376,7 +381,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) if (not_before && current_time < not_before) { - log_error ("certificate to young; valid from "); + log_error ("certificate too young; valid from "); gpgsm_dump_time (not_before); log_printf ("\n"); rc = GNUPG_Certificate_Too_Young; @@ -387,8 +392,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) log_error ("certificate has expired at "); gpgsm_dump_time (not_after); log_printf ("\n"); - rc = GNUPG_Certificate_Expired; - goto leave; + any_expired = 1; } } @@ -399,7 +403,12 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) if (!opt.no_policy_check) { rc = check_cert_policy (subject_cert); - if (rc) + if (rc == GNUPG_No_Policy_Match) + { + any_no_policy_match = 1; + rc = 1; + } + else if (rc) goto leave; } @@ -412,21 +421,24 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) { case GNUPG_Certificate_Revoked: log_error (_("the certificate has been revoked\n")); + any_revoked = 1; break; case GNUPG_No_CRL_Known: log_error (_("no CRL found for certificate\n")); + any_no_crl = 1; break; case GNUPG_CRL_Too_Old: log_error (_("the available CRL is too old\n")); log_info (_("please make sure that the " "\"dirmngr\" is properly installed\n")); + any_crl_too_old = 1; break; default: log_error (_("checking the CRL failed: %s\n"), gnupg_strerror (rc)); - break; + goto leave; } - goto leave; + rc = 0; } } @@ -551,6 +563,21 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) log_info ("policies not checked due to --disable-policy-checks option\n"); if (opt.no_crl_check) log_info ("CRLs not checked due to --disable-crl-checks option\n"); + + if (!rc) + { /* If we encountered an error somewhere during the checks, set + the error code to the most critical one */ + if (any_revoked) + rc = GNUPG_Certificate_Revoked; + else if (any_no_crl) + rc = GNUPG_No_CRL_Known; + else if (any_crl_too_old) + rc = GNUPG_CRL_Too_Old; + else if (any_no_policy_match) + rc = GNUPG_No_Policy_Match; + else if (any_expired) + rc = GNUPG_Certificate_Expired; + } leave: if (r_exptime) diff --git a/sm/certpath.c b/sm/certpath.c index 28c0be52f..0b2d8b4fc 100644 --- a/sm/certpath.c +++ b/sm/certpath.c @@ -317,6 +317,11 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) KsbaCert subject_cert = NULL, issuer_cert = NULL; time_t current_time = gnupg_get_time (); time_t exptime = 0; + int any_expired = 0; + int any_revoked = 0; + int any_no_crl = 0; + int any_crl_too_old = 0; + int any_no_policy_match = 0; if (r_exptime) *r_exptime = 0; @@ -376,7 +381,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) if (not_before && current_time < not_before) { - log_error ("certificate to young; valid from "); + log_error ("certificate too young; valid from "); gpgsm_dump_time (not_before); log_printf ("\n"); rc = GNUPG_Certificate_Too_Young; @@ -387,8 +392,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) log_error ("certificate has expired at "); gpgsm_dump_time (not_after); log_printf ("\n"); - rc = GNUPG_Certificate_Expired; - goto leave; + any_expired = 1; } } @@ -399,7 +403,12 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) if (!opt.no_policy_check) { rc = check_cert_policy (subject_cert); - if (rc) + if (rc == GNUPG_No_Policy_Match) + { + any_no_policy_match = 1; + rc = 1; + } + else if (rc) goto leave; } @@ -412,21 +421,24 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) { case GNUPG_Certificate_Revoked: log_error (_("the certificate has been revoked\n")); + any_revoked = 1; break; case GNUPG_No_CRL_Known: log_error (_("no CRL found for certificate\n")); + any_no_crl = 1; break; case GNUPG_CRL_Too_Old: log_error (_("the available CRL is too old\n")); log_info (_("please make sure that the " "\"dirmngr\" is properly installed\n")); + any_crl_too_old = 1; break; default: log_error (_("checking the CRL failed: %s\n"), gnupg_strerror (rc)); - break; + goto leave; } - goto leave; + rc = 0; } } @@ -551,6 +563,21 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime) log_info ("policies not checked due to --disable-policy-checks option\n"); if (opt.no_crl_check) log_info ("CRLs not checked due to --disable-crl-checks option\n"); + + if (!rc) + { /* If we encountered an error somewhere during the checks, set + the error code to the most critical one */ + if (any_revoked) + rc = GNUPG_Certificate_Revoked; + else if (any_no_crl) + rc = GNUPG_No_CRL_Known; + else if (any_crl_too_old) + rc = GNUPG_CRL_Too_Old; + else if (any_no_policy_match) + rc = GNUPG_No_Policy_Match; + else if (any_expired) + rc = GNUPG_Certificate_Expired; + } leave: if (r_exptime) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 3aeddd845..f01ffc709 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1080,13 +1080,14 @@ main ( int argc, char **argv) break; case aSign: /* sign the given file */ - /* FIXME: we can only do detached sigs for now and we don't - handle --output yet. We should also allow to concatenate - multiple files for signing because that is what gpg does.*/ + /* FIXME: W we don't handle --output yet. We should also allow + to concatenate multiple files for signing because that is + what gpg does.*/ if (!argc) - gpgsm_sign (&ctrl, 0, 1, stdout); /* create from stdin */ + gpgsm_sign (&ctrl, 0, detached_sig, stdout); /* create from stdin */ else if (argc == 1) - gpgsm_sign (&ctrl, open_read (*argv), 1, stdout); /* from file */ + gpgsm_sign (&ctrl, open_read (*argv), + detached_sig, stdout); /* from file */ else wrong_args (_("--sign [datafile]")); break; diff --git a/sm/server.c b/sm/server.c index 763084c73..69abe7adb 100644 --- a/sm/server.c +++ b/sm/server.c @@ -789,6 +789,7 @@ get_status_string ( int no ) case STATUS_EXPSIG : s = "EXPSIG"; break; case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break; case STATUS_TRUNCATED : s = "TRUNCATED"; break; + case STATUS_ERROR : s = "ERROR"; break; default: s = "?"; break; } return s; @@ -60,6 +60,67 @@ hash_data (int fd, GCRY_MD_HD md) fclose (fp); } +static int +hash_and_copy_data (int fd, GCRY_MD_HD md, KsbaWriter writer) +{ + KsbaError err; + FILE *fp; + char buffer[4096]; + int nread; + int rc = 0; + int any = 0; + + fp = fdopen ( dup (fd), "rb"); + if (!fp) + { + log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno)); + return GNUPG_File_Open_Error; + } + + do + { + nread = fread (buffer, 1, DIM(buffer), fp); + if (nread) + { + any = 1; + gcry_md_write (md, buffer, nread); + err = ksba_writer_write_octet_string (writer, buffer, nread, 0); + if (err) + { + log_error ("write failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + } + } + } + while (nread && !rc); + if (ferror (fp)) + { + log_error ("read error on fd %d: %s\n", fd, strerror (errno)); + rc = GNUPG_Read_Error; + } + fclose (fp); + if (!any) + { + /* We can't allow to sign an empty message becuase it does not + make mnuch sense and more seriously, ksba-cms_build has + already written the tag for data and now expects an octet + string but an octet string of zeize 0 is illegal. */ + log_error ("cannot sign an empty message\n"); + rc = GNUPG_No_Data; + } + if (!rc) + { + err = ksba_writer_write_octet_string (writer, NULL, 0, 1); + if (err) + { + log_error ("write failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + } + } + + return rc; +} + /* Get the default certificate which is defined as the first one our keyDB retruns and has a secret key available */ @@ -227,10 +288,10 @@ add_certificate_list (CTRL ctrl, KsbaCMS cms, KsbaCert cert) /* Perform a sign operation. - Sign the data received on DATA-FD in embedded mode or in deatched - mode when DETACHED is true. Write the signature to OUT_FP The key - used to sign is the default - we will extend the fucntion to take a - list of fingerprints in the future. */ + Sign the data received on DATA-FD in embedded mode or in detached + mode when DETACHED is true. Write the signature to OUT_FP. The + key used to sign is the default one - we will extend the function + to take a list of fingerprints in the future. */ int gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) { @@ -248,13 +309,6 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) int algo; time_t signed_at; - if (!detached) - { - rc = seterr (Not_Implemented); - goto leave; - } - - kh = keydb_new (0); if (!kh) { @@ -415,7 +469,35 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) if (stopreason == KSBA_SR_BEGIN_DATA) { /* hash the data and store the message digest */ + unsigned char *digest; + size_t digest_len; + assert (!detached); + /* Fixme do this for all signers and get the algo to use from + the signer's certificate - does not make mich sense, bu we + should do this consistent as we have already done it above. + Code is mostly duplicated above. */ + + algo = GCRY_MD_SHA1; + rc = hash_and_copy_data (data_fd, data_md, writer); + if (rc) + goto leave; + digest = gcry_md_read (data_md, algo); + digest_len = gcry_md_get_algo_dlen (algo); + if ( !digest || !digest_len) + { + log_error ("problem getting the hash of the data\n"); + rc = GNUPG_Bug; + goto leave; + } + err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); + if (err) + { + log_error ("ksba_cms_set_message_digest failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } } else if (stopreason == KSBA_SR_NEED_SIG) { /* calculate the signature for all signers */ diff --git a/sm/verify.c b/sm/verify.c index 5549470c2..394939eb0 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -317,8 +317,18 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) rc = keydb_search_issuer_sn (kh, issuer, serial); if (rc) { - log_error ("failed to find the certificate: %s\n", - gnupg_strerror(rc)); + if (rc == -1) + { + log_error ("certificate not found\n"); + rc = GNUPG_No_Public_Key; + } + else + log_error ("failed to find the certificate: %s\n", + gnupg_strerror(rc)); + gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey", + gnupg_error_token (rc), NULL); + /* fixme: we might want to append the issuer and serial + using our standard notation */ goto next_signer; } @@ -384,7 +394,10 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) log_debug ("signature okay - checking certs\n"); rc = gpgsm_validate_path (cert, &keyexptime); if (rc == GNUPG_Certificate_Expired) - gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL); + { + gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL); + rc = 0; + } else gpgsm_status (ctrl, STATUS_GOODSIG, NULL); @@ -406,10 +419,12 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) { log_error ("invalid certification path: %s\n", gnupg_strerror (rc)); if (rc == GNUPG_Bad_Certificate_Path - || rc == GNUPG_Bad_Certificate) - gpgsm_status (ctrl, STATUS_TRUST_NEVER, NULL); + || rc == GNUPG_Bad_Certificate + || rc == GNUPG_Bad_CA_Certificate + || rc == GNUPG_Certificate_Revoked) + gpgsm_status (ctrl, STATUS_TRUST_NEVER, gnupg_error_token (rc)); else - gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, NULL); + gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, gnupg_error_token (rc)); goto next_signer; } log_info ("signature is good\n"); @@ -442,6 +457,10 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) gcry_md_close (data_md); if (fp) fclose (fp); + + if (rc) + gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave", + gnupg_error_token (rc), NULL); return rc; } |