aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sm/ChangeLog21
-rw-r--r--sm/certchain.c39
-rw-r--r--sm/certpath.c39
-rw-r--r--sm/gpgsm.c11
-rw-r--r--sm/server.c1
-rw-r--r--sm/sign.c104
-rw-r--r--sm/verify.c31
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;
diff --git a/sm/sign.c b/sm/sign.c
index 46fa170ba..4cce9f926 100644
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -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;
}