Add Kludge for RegTP sillyness.

This commit is contained in:
Werner Koch 2006-03-21 09:56:47 +00:00
parent 89824e5d59
commit 6b19366e4e
6 changed files with 152 additions and 12 deletions

3
NEWS
View File

@ -8,6 +8,9 @@ Noteworthy changes in version 1.9.21
* Cards are not anymore reseted at the end of a connection.
* [gpgsm] Kludge to allow use of Bundesnetzagentur issued
certificates.
Noteworthy changes in version 1.9.20 (2005-12-20)
-------------------------------------------------

4
TODO
View File

@ -18,7 +18,9 @@ might want to have an agent context for each service request
* sm/certchain.c
** When a certificate chain was sucessfully verified, make ephemeral certs used in this chain permanent.
** Try to keep certificate references somewhere
This will help with some of our caching code. We also need to test
that cachining; in particular "regtp_ca_chainlen".
* sm/decrypt.c
** replace leading zero in integer hack by a cleaner solution

View File

@ -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.

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}