diff --git a/common/errors.h b/common/errors.h index 58508c93f..22c827299 100644 --- a/common/errors.h +++ b/common/errors.h @@ -102,6 +102,7 @@ enum { GNUPG_Bad_PIN_Method = 73, GNUPG_Card_Not_Initialized = 74, GNUPG_Unsupported_Operation = 75, + GNUPG_Wrong_Key_Usage = 76, }; /* Status codes - fixme: should go into another file */ diff --git a/sm/ChangeLog b/sm/ChangeLog index 7793006dd..e28853fdb 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,15 @@ +2002-04-11 Werner Koch + + * certlist.c (cert_usable_p): New. + (gpgsm_cert_use_sign_p,gpgsm_cert_use_encrypt_p): New. + (gpgsm_cert_use_verify_p,gpgsm_cert_use_decrypt_p): New. + (gpgsm_add_to_certlist): Check the key usage. + * sign.c (gpgsm_sign): Ditto. + * verify.c (gpgsm_verify): Print a message wehn an unsuitable + certificate was used. + * decrypt.c (gpgsm_decrypt): Ditto + * keylist.c (print_capabilities): Determine values from the cert. + 2002-03-28 Werner Koch * keylist.c (list_cert_colon): Fixed listing of crt record; the diff --git a/sm/certlist.c b/sm/certlist.c index fe45f1d22..2d52ada30 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -32,6 +32,71 @@ #include "gpgsm.h" #include "keydb.h" +#include "i18n.h" + +/* Return 0 if the cert is usable for encryption. A MODE of 0 checks + for signing a MODE of 1 checks for encryption, a MODE of 2 checks + for verification and a MODE of 3 for decryption (just for + debugging) */ +static int +cert_usage_p (KsbaCert cert, int mode) +{ + KsbaError err; + unsigned int use; + + err = ksba_cert_get_key_usage (cert, &use); + if (err == KSBA_No_Data) + { + if (opt.verbose && mode < 2) + log_info (mode? + _("no key usage specified - accepted for encryption\n"): + _("no key usage specified - accepted for signing\n")); + return 0; + } + if (err) + { + log_error (_("error getting key usage information: %s\n"), + ksba_strerror (err)); + return map_ksba_err (err); + } + + if ((use & ((mode&1)? KSBA_KEYUSAGE_DIGITAL_SIGNATURE + : KSBA_KEYUSAGE_KEY_ENCIPHERMENT))) + return 0; + log_info (mode==3? _("certificate should have not been used for encryption\n"): + mode==2? _("certificate should have not been used for signing\n"): + mode==1? _("certificate is not usable for encryption\n"): + _("certificate is not usable for signing\n")); + return GNUPG_Wrong_Key_Usage; +} + + +/* Return 0 if the cert is usable for signing */ +int +gpgsm_cert_use_sign_p (KsbaCert cert) +{ + return cert_usage_p (cert, 0); +} + + +/* Return 0 if the cert is usable for encryption */ +int +gpgsm_cert_use_encrypt_p (KsbaCert cert) +{ + return cert_usage_p (cert, 1); +} + +int +gpgsm_cert_use_verify_p (KsbaCert cert) +{ + return cert_usage_p (cert, 2); +} + +int +gpgsm_cert_use_decrypt_p (KsbaCert cert) +{ + return cert_usage_p (cert, 3); +} /* add a certificate to a list of certificate and make sure that it is a valid certificate */ @@ -51,17 +116,40 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr) rc = GNUPG_Out_Of_Core; else { + int wrong_usage = 0; + get_next: rc = keydb_search (kh, &desc, 1); if (!rc) rc = keydb_get_cert (kh, &cert); if (!rc) { + rc = gpgsm_cert_use_encrypt_p (cert); + if (rc == GNUPG_Wrong_Key_Usage) + { + /* There might be another certificate with the + correct usage, so we better try again */ + wrong_usage = rc; + ksba_cert_release (cert); + cert = NULL; + goto get_next; + } + } + /* we want the error code from the first match in this case */ + if (wrong_usage) + rc = wrong_usage; + + if (!rc) + { + /* Fixme: If we ever have two certifciates differing + only in the key usage, we should only bail out here + if the certificate differes just in the key usage. + However we need to find some criteria to match the + identities */ rc = keydb_search (kh, &desc, 1); if (rc == -1) rc = 0; else if (!rc) rc = GNUPG_Ambiguous_Name; - } if (!rc) rc = gpgsm_validate_path (cert); diff --git a/sm/decrypt.c b/sm/decrypt.c index 4e513a28b..e3566fd13 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -378,6 +378,10 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp) log_error ("failed to get cert: %s\n", gnupg_strerror (rc)); goto oops; } + /* Just in case there is a problem with the own + certificate we print this message - should never + happen of course */ + gpgsm_cert_use_decrypt_p (cert); hexkeygrip = gpgsm_get_keygrip_hexstring (cert); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index a46627da3..9cba457dd 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -178,6 +178,10 @@ int gpgsm_validate_path (KsbaCert cert); int gpgsm_basic_cert_check (KsbaCert cert); /*-- certlist.c --*/ +int gpgsm_cert_use_sign_p (KsbaCert cert); +int gpgsm_cert_use_encrypt_p (KsbaCert cert); +int gpgsm_cert_use_verify_p (KsbaCert cert); +int gpgsm_cert_use_decrypt_p (KsbaCert cert); int gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr); void gpgsm_release_certlist (CERTLIST list); int gpgsm_find_cert (const char *name, KsbaCert *r_cert); diff --git a/sm/keylist.c b/sm/keylist.c index bccb26b6e..18d570ec8 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -32,7 +32,7 @@ #include "gpgsm.h" #include "keydb.h" - +#include "i18n.h" @@ -56,12 +56,39 @@ print_key_data (KsbaCert cert, FILE *fp) static void print_capabilities (KsbaCert cert, FILE *fp) { - putc ('e', fp); - putc ('s', fp); - putc ('c', fp); - putc ('E', fp); - putc ('S', fp); - putc ('C', fp); + KsbaError err; + unsigned int use; + + err = ksba_cert_get_key_usage (cert, &use); + if (err == KSBA_No_Data) + { + putc ('e', fp); + putc ('s', fp); + putc ('c', fp); + putc ('E', fp); + putc ('S', fp); + putc ('C', fp); + return; + } + if (err) + { + log_error (_("error getting key usage information: %s\n"), + ksba_strerror (err)); + return; + } + + if ((use & KSBA_KEYUSAGE_KEY_ENCIPHERMENT)) + putc ('e', fp); + if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE)) + putc ('s', fp); + if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN)) + putc ('c', fp); + if ((use & KSBA_KEYUSAGE_KEY_ENCIPHERMENT)) + putc ('E', fp); + if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE)) + putc ('S', fp); + if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN)) + putc ('C', fp); } diff --git a/sm/sign.c b/sm/sign.c index b16e840bc..2781baa84 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -310,6 +310,10 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) rc = seterr (General_Error); goto leave; } + rc = gpgsm_cert_use_sign_p (cert); + if (rc) + goto leave; + err = ksba_cms_add_signer (cms, cert); if (err) { diff --git a/sm/verify.c b/sm/verify.c index 69e18ac25..f4d80393a 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -370,6 +370,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) gpgsm_status (ctrl, STATUS_BADSIG, NULL); goto next_signer; } + gpgsm_cert_use_verify_p (cert); /* this displays an info message */ log_debug ("signature okay - checking certs\n"); gpgsm_status (ctrl, STATUS_GOODSIG, NULL); {