summaryrefslogtreecommitdiffstats
path: root/sm
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2006-03-21 10:56:47 +0100
committerWerner Koch <wk@gnupg.org>2006-03-21 10:56:47 +0100
commit6b19366e4e4583bc70f43c2ac138b9a7decb7075 (patch)
tree74ccd4d237a7579e9251c05fc4df78372bd37bc7 /sm
parentFixed card removal problems (diff)
downloadgnupg2-6b19366e4e4583bc70f43c2ac138b9a7decb7075.tar.xz
gnupg2-6b19366e4e4583bc70f43c2ac138b9a7decb7075.zip
Add Kludge for RegTP sillyness.
Diffstat (limited to 'sm')
-rw-r--r--sm/ChangeLog9
-rw-r--r--sm/certchain.c127
-rw-r--r--sm/gpgsm.h3
-rw-r--r--sm/qualified.c18
4 files changed, 146 insertions, 11 deletions
diff --git a/sm/ChangeLog b/sm/ChangeLog
index 764faa67d..02505962c 100644
--- a/sm/ChangeLog
+++ b/sm/ChangeLog
@@ -1,3 +1,12 @@
+2006-03-21 Werner Koch <wk@g10code.com>
+
+ * certchain.c (get_regtp_ca_info): New.
+ (allowed_ca): Use it.
+
+2006-03-20 Werner Koch <wk@g10code.com>
+
+ * qualified.c (gpgsm_is_in_qualified_list): New optional arg COUNTRY.
+
2006-02-17 Werner Koch <wk@g10code.com>
* call-dirmngr.c (start_dirmngr): Print name of dirmngr to be started.
diff --git a/sm/certchain.c b/sm/certchain.c
index 0c14fc88f..44d72efd3 100644
--- a/sm/certchain.c
+++ b/sm/certchain.c
@@ -1,5 +1,6 @@
/* certchain.c - certificate chain validation
- * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005,
+ * 2006 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -39,6 +40,10 @@
#include "i18n.h"
+static int get_regtp_ca_info (ksba_cert_t cert, int *chainlen);
+
+
+
/* If LISTMODE is true, print FORMAT using LISTMODE to FP. If
LISTMODE is false, use the string to print an log_info or, if
IS_ERROR is true, and log_error. */
@@ -128,6 +133,11 @@ allowed_ca (ksba_cert_t cert, int *chainlen, int listmode, FILE *fp)
return err;
if (!flag)
{
+ if (get_regtp_ca_info (cert, chainlen))
+ {
+ return 0; /* RegTP issued certificate. */
+ }
+
do_list (1, listmode, fp,_("issuer certificate is not marked as a CA"));
return gpg_error (GPG_ERR_BAD_CA_CERT);
}
@@ -267,7 +277,7 @@ check_cert_policy (ksba_cert_t cert, int listmode, FILE *fplist)
}
-/* Helper fucntion for find_up. This resets the key handle and search
+/* Helper function for find_up. This resets the key handle and search
for an issuer ISSUER with a subjectKeyIdentifier of KEYID. Returns
0 obn success or -1 when not found. */
static int
@@ -796,7 +806,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
{
/* Need to consult the list of root certificates for
qualified signatures. */
- err = gpgsm_is_in_qualified_list (ctrl, subject_cert);
+ err = gpgsm_is_in_qualified_list (ctrl, subject_cert, NULL);
if (!err)
is_qualified = 1;
else if ( gpg_err_code (err) == GPG_ERR_NOT_FOUND)
@@ -807,8 +817,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
gpg_strerror (err));
if ( is_qualified != -1 )
{
- /* Cache the result but don't care toomuch about
- an error. */
+ /* Cache the result but don't care too much
+ about an error. */
buf[0] = !!is_qualified;
err = ksba_cert_set_user_data (subject_cert,
"is_qualified", buf, 1);
@@ -1181,3 +1191,110 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
return rc;
}
+
+
+/* Check whether the certificate CERT has been issued by the German
+ authority for qualified signature. They do not set the
+ basicConstraints and thus we need this workaround. It works by
+ looking up the root certificate and checking whether that one is
+ listed as a qualified certificate for Germany.
+
+ We also try to cache this data but as long as don't keep a
+ reference to the certificate this won't be used.
+
+ Returns: True if CERT is a RegTP issued CA cert (i.e. the root
+ certificate itself or one of the CAs). In that case CHAINLEN will
+ receive the length of the chain which is either 0 or 1.
+*/
+static int
+get_regtp_ca_info (ksba_cert_t cert, int *chainlen)
+{
+ gpg_error_t err;
+ ksba_cert_t next;
+ int rc = 0;
+ int i, depth;
+ char country[3];
+ ksba_cert_t array[4];
+ char buf[2];
+ size_t buflen;
+ int dummy_chainlen;
+
+ if (!chainlen)
+ chainlen = &dummy_chainlen;
+
+ *chainlen = 0;
+ err = ksba_cert_get_user_data (cert, "regtp_ca_chainlen",
+ &buf, sizeof (buf), &buflen);
+ if (!err)
+ {
+ /* Got info. */
+ if (buflen < 2 || !*buf)
+ return 0; /* Nothing found. */
+ *chainlen = buf[1];
+ return 1; /* This is a regtp CA. */
+ }
+ else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
+ {
+ log_error ("ksba_cert_get_user_data(%s) failed: %s\n",
+ "regtp_ca_chainlen", gpg_strerror (err));
+ return 0; /* Nothing found. */
+ }
+
+ /* Need to gather the info. This requires to walk up the chain
+ until we have found the root. Because we are only interested in
+ German Bundesnetzagentur (former RegTP) derived certificates 3
+ levels are enough. (The German signature law demands a 3 tier
+ hierachy; thus there is only one CA between the EE and the Root
+ CA.) */
+ memset (&array, 0, sizeof array);
+
+ depth = 0;
+ ksba_cert_ref (cert);
+ array[depth++] = cert;
+ ksba_cert_ref (cert);
+ while (depth < DIM(array) && !(rc=gpgsm_walk_cert_chain (cert, &next)))
+ {
+ ksba_cert_release (cert);
+ ksba_cert_ref (next);
+ array[depth++] = next;
+ cert = next;
+ }
+ ksba_cert_release (cert);
+ if (rc != -1 || !depth || depth == DIM(array) )
+ {
+ /* We did not reached the root. */
+ goto leave;
+ }
+
+ /* If this is a German signature law issued certificate, we store
+ additional additional information. */
+ if (!gpgsm_is_in_qualified_list (NULL, array[depth-1], country)
+ && !strcmp (country, "de"))
+ {
+ /* Setting the pathlen for the root CA and the CA flag for the
+ next one is all what we need to do. */
+ err = ksba_cert_set_user_data (array[depth-1], "regtp_ca_chainlen",
+ "\x01\x01", 2);
+ if (!err && depth > 1)
+ err = ksba_cert_set_user_data (array[depth-2], "regtp_ca_chainlen",
+ "\x01\x00", 2);
+ if (err)
+ log_error ("ksba_set_user_data(%s) failed: %s\n",
+ "regtp_ca_chainlen", gpg_strerror (err));
+ for (i=0; i < depth; i++)
+ ksba_cert_release (array[i]);
+ *chainlen = (depth>1? 0:1);
+ return 1;
+ }
+
+ leave:
+ /* Nothing special with this certificate. Mark the target
+ certificate anyway to avoid duplicate lookups. */
+ err = ksba_cert_set_user_data (cert, "regtp_ca_chainlen", "", 1);
+ if (err)
+ log_error ("ksba_set_user_data(%s) failed: %s\n",
+ "regtp_ca_chainlen", gpg_strerror (err));
+ for (i=0; i < depth; i++)
+ ksba_cert_release (array[i]);
+ return 0;
+}
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index dc863f682..438252050 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -296,7 +296,8 @@ int gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp);
int gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp);
/*-- qualified.c --*/
-gpg_error_t gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert);
+gpg_error_t gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert,
+ char *country);
gpg_error_t gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert);
gpg_error_t gpgsm_not_qualified_warning (ctrl_t ctrl, ksba_cert_t cert);
diff --git a/sm/qualified.c b/sm/qualified.c
index a52269734..07abaadc4 100644
--- a/sm/qualified.c
+++ b/sm/qualified.c
@@ -145,24 +145,29 @@ read_list (char *key, char *country, int *lnr)
per user because it is not a decision of the user.
Returns: 0 if the certificate is included. GPG_ERR_NOT_FOUND if it
- is not in the liost or any other error (e.g. if no list of
- qualified signatures is available. */
+ is not in the list or any other error (e.g. if no list of
+ qualified signatures is available. If COUNTRY has not been passed
+ as NULL a string witha maximum length of 2 will be copied into it;
+ thus the caller needs to provide a buffer of length 3. */
gpg_error_t
-gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert)
+gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert, char *country)
{
gpg_error_t err;
char *fpr;
char key[41];
- char country[2];
+ char mycountry[3];
int lnr = 0;
+ if (country)
+ *country = 0;
+
fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
if (!fpr)
return gpg_error (GPG_ERR_GENERAL);
if (listfp)
rewind (listfp);
- while (!(err = read_list (key, country, &lnr)))
+ while (!(err = read_list (key, mycountry, &lnr)))
{
if (!strcmp (key, fpr))
break;
@@ -170,6 +175,9 @@ gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert)
if (gpg_err_code (err) == GPG_ERR_EOF)
err = gpg_error (GPG_ERR_NOT_FOUND);
+ if (!err && country)
+ strcpy (country, mycountry);
+
xfree (fpr);
return err;
}