* gpgsm.c (main): New options --no-log-file and --debug-none.

* certreqgen.c (get_parameter, get_parameter_value): Add SEQ arg
to allow enumeration.  Changed all callers.
(create_request): Process DNS and URI parameters.

* gpgsm-gencert.sh: Reworked to allow for multiple email addresses
as well as DNsanmes and URi.  Present the parameter file before
creating the certificate.
This commit is contained in:
Werner Koch 2005-07-21 18:29:13 +00:00
parent 5e47c18612
commit 99f403b015
5 changed files with 164 additions and 36 deletions

View File

@ -1,3 +1,11 @@
2005-07-21 Werner Koch <wk@g10code.com>
* gpgsm.c (main): New options --no-log-file and --debug-none.
* certreqgen.c (get_parameter, get_parameter_value): Add SEQ arg
to allow enumeration. Changed all callers.
(create_request): Process DNS and URI parameters.
2005-07-20 Werner Koch <wk@g10code.com> 2005-07-20 Werner Koch <wk@g10code.com>
* keylist.c (email_kludge): Reworked. * keylist.c (email_kludge): Reworked.

View File

@ -1,5 +1,5 @@
/* certreqgen.c - Generate a key and a certification request /* certreqgen.c - Generate a key and a certification request
* Copyright (C) 2002, 2003 Free Software Foundation, Inc. * Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -71,7 +71,11 @@ The format of the native parameter file is follows:
Name-DN: subject name Name-DN: subject name
This is the DN name of the subject in rfc2253 format. This is the DN name of the subject in rfc2253 format.
Name-Email: <string> Name-Email: <string>
The ist the email address The is an email address for the altSubjectName
Name-DNS: <string>
The is an DNS name for the altSubjectName
Name-URI: <string>
The is an URI for the altSubjectName
Here is an example: Here is an example:
$ cat >foo <<EOF $ cat >foo <<EOF
@ -109,7 +113,9 @@ enum para_name {
pKEYLENGTH, pKEYLENGTH,
pKEYUSAGE, pKEYUSAGE,
pNAMEDN, pNAMEDN,
pNAMEEMAIL pNAMEEMAIL,
pNAMEDNS,
pNAMEURI
}; };
struct para_data_s { struct para_data_s {
@ -155,26 +161,27 @@ release_parameter_list (struct para_data_s *r)
} }
static struct para_data_s * static struct para_data_s *
get_parameter (struct para_data_s *para, enum para_name key) get_parameter (struct para_data_s *para, enum para_name key, int seq)
{ {
struct para_data_s *r; struct para_data_s *r;
for (r = para; r && r->key != key; r = r->next) for (r = para; r ; r = r->next)
; if ( r->key == key && !seq--)
return r; return r;
return NULL;
} }
static const char * static const char *
get_parameter_value (struct para_data_s *para, enum para_name key) get_parameter_value (struct para_data_s *para, enum para_name key, int seq)
{ {
struct para_data_s *r = get_parameter (para, key); struct para_data_s *r = get_parameter (para, key, seq);
return (r && *r->u.value)? r->u.value : NULL; return (r && *r->u.value)? r->u.value : NULL;
} }
static int static int
get_parameter_algo (struct para_data_s *para, enum para_name key) get_parameter_algo (struct para_data_s *para, enum para_name key)
{ {
struct para_data_s *r = get_parameter (para, key); struct para_data_s *r = get_parameter (para, key, 0);
if (!r) if (!r)
return -1; return -1;
if (digitp (r->u.value)) if (digitp (r->u.value))
@ -189,7 +196,7 @@ get_parameter_algo (struct para_data_s *para, enum para_name key)
static int static int
parse_parameter_usage (struct para_data_s *para, enum para_name key) parse_parameter_usage (struct para_data_s *para, enum para_name key)
{ {
struct para_data_s *r = get_parameter (para, key); struct para_data_s *r = get_parameter (para, key, 0);
char *p, *pn; char *p, *pn;
unsigned int use; unsigned int use;
@ -220,7 +227,7 @@ parse_parameter_usage (struct para_data_s *para, enum para_name key)
static unsigned int static unsigned int
get_parameter_uint (struct para_data_s *para, enum para_name key) get_parameter_uint (struct para_data_s *para, enum para_name key)
{ {
struct para_data_s *r = get_parameter (para, key); struct para_data_s *r = get_parameter (para, key, 0);
if (!r) if (!r)
return 0; return 0;
@ -241,12 +248,15 @@ read_parameters (ctrl_t ctrl, FILE *fp, ksba_writer_t writer)
static struct { static struct {
const char *name; const char *name;
enum para_name key; enum para_name key;
int allow_dups;
} keywords[] = { } keywords[] = {
{ "Key-Type", pKEYTYPE}, { "Key-Type", pKEYTYPE},
{ "Key-Length", pKEYLENGTH }, { "Key-Length", pKEYLENGTH },
{ "Key-Usage", pKEYUSAGE }, { "Key-Usage", pKEYUSAGE },
{ "Name-DN", pNAMEDN }, { "Name-DN", pNAMEDN },
{ "Name-Email", pNAMEEMAIL }, { "Name-Email", pNAMEEMAIL, 1 },
{ "Name-DNS", pNAMEDNS, 1 },
{ "Name-URI", pNAMEURI, 1 },
{ NULL, 0 } { NULL, 0 }
}; };
char line[1024], *p; char line[1024], *p;
@ -347,7 +357,7 @@ read_parameters (ctrl_t ctrl, FILE *fp, ksba_writer_t writer)
release_parameter_list (para); release_parameter_list (para);
para = NULL; para = NULL;
} }
else else if (!keywords[i].allow_dups)
{ {
for (r = para; r && r->key != keywords[i].key; r = r->next) for (r = para; r && r->key != keywords[i].key; r = r->next)
; ;
@ -433,9 +443,10 @@ proc_parameters (ctrl_t ctrl,
unsigned char keyparms[100]; unsigned char keyparms[100];
int rc; int rc;
ksba_sexp_t public; ksba_sexp_t public;
int seq;
/* check that we have all required parameters */ /* check that we have all required parameters */
assert (get_parameter (para, pKEYTYPE)); assert (get_parameter (para, pKEYTYPE, 0));
/* We can only use RSA for now. There is a with pkcs-10 on how to /* We can only use RSA for now. There is a with pkcs-10 on how to
use ElGamal because it is expected that a PK algorithm can always use ElGamal because it is expected that a PK algorithm can always
@ -443,20 +454,20 @@ proc_parameters (ctrl_t ctrl,
i = get_parameter_algo (para, pKEYTYPE); i = get_parameter_algo (para, pKEYTYPE);
if (i < 1 || i != GCRY_PK_RSA ) if (i < 1 || i != GCRY_PK_RSA )
{ {
r = get_parameter (para, pKEYTYPE); r = get_parameter (para, pKEYTYPE, 0);
log_error (_("line %d: invalid algorithm\n"), r->lnr); log_error (_("line %d: invalid algorithm\n"), r->lnr);
return gpg_error (GPG_ERR_INV_PARAMETER); return gpg_error (GPG_ERR_INV_PARAMETER);
} }
/* check the keylength */ /* check the keylength */
if (!get_parameter (para, pKEYLENGTH)) if (!get_parameter (para, pKEYLENGTH, 0))
nbits = 1024; nbits = 1024;
else else
nbits = get_parameter_uint (para, pKEYLENGTH); nbits = get_parameter_uint (para, pKEYLENGTH);
if (nbits < 1024 || nbits > 4096) if (nbits < 1024 || nbits > 4096)
{ {
/* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */ /* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */
r = get_parameter (para, pKEYTYPE); r = get_parameter (para, pKEYLENGTH, 0);
log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"), log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"),
r->lnr, nbits, 1024, 4096); r->lnr, nbits, 1024, 4096);
return gpg_error (GPG_ERR_INV_PARAMETER); return gpg_error (GPG_ERR_INV_PARAMETER);
@ -468,16 +479,16 @@ proc_parameters (ctrl_t ctrl,
/* check that there is a subject name and that this DN fits our /* check that there is a subject name and that this DN fits our
requirements */ requirements */
if (!(s=get_parameter_value (para, pNAMEDN))) if (!(s=get_parameter_value (para, pNAMEDN, 0)))
{ {
r = get_parameter (para, pKEYTYPE); r = get_parameter (para, pKEYTYPE, 0);
log_error (_("line %d: no subject name given\n"), r->lnr); log_error (_("line %d: no subject name given\n"), r->lnr);
return gpg_error (GPG_ERR_INV_PARAMETER); return gpg_error (GPG_ERR_INV_PARAMETER);
} }
/* fixme check s */ /* fixme check s */
/* check that the optional email address is okay */ /* check that the optional email address is okay */
if ((s=get_parameter_value (para, pNAMEEMAIL))) for (seq=0; (s=get_parameter_value (para, pNAMEEMAIL, seq)); seq++)
{ {
if (has_invalid_email_chars (s) if (has_invalid_email_chars (s)
|| *s == '@' || *s == '@'
@ -485,7 +496,7 @@ proc_parameters (ctrl_t ctrl,
|| s[strlen(s)-1] == '.' || s[strlen(s)-1] == '.'
|| strstr(s, "..")) || strstr(s, ".."))
{ {
r = get_parameter (para, pKEYTYPE); r = get_parameter (para, pNAMEEMAIL, seq);
log_error (_("line %d: not a valid email address\n"), r->lnr); log_error (_("line %d: not a valid email address\n"), r->lnr);
return gpg_error (GPG_ERR_INV_PARAMETER); return gpg_error (GPG_ERR_INV_PARAMETER);
} }
@ -497,7 +508,7 @@ proc_parameters (ctrl_t ctrl,
rc = gpgsm_agent_genkey (ctrl, keyparms, &public); rc = gpgsm_agent_genkey (ctrl, keyparms, &public);
if (rc) if (rc)
{ {
r = get_parameter (para, pKEYTYPE); r = get_parameter (para, pKEYTYPE, 0);
log_error (_("line %d: key generation failed: %s\n"), log_error (_("line %d: key generation failed: %s\n"),
r->lnr, gpg_strerror (rc)); r->lnr, gpg_strerror (rc));
return rc; return rc;
@ -524,6 +535,10 @@ create_request (ctrl_t ctrl,
int rc = 0; int rc = 0;
const char *s; const char *s;
unsigned int use; unsigned int use;
int seq;
char *buf, *p;
size_t len;
char numbuf[30];
err = ksba_certreq_new (&cr); err = ksba_certreq_new (&cr);
if (err) if (err)
@ -541,7 +556,7 @@ create_request (ctrl_t ctrl,
ksba_certreq_set_hash_function (cr, HASH_FNC, md); ksba_certreq_set_hash_function (cr, HASH_FNC, md);
ksba_certreq_set_writer (cr, outctrl->writer); ksba_certreq_set_writer (cr, outctrl->writer);
err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN)); err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN, 0));
if (err) if (err)
{ {
log_error ("error setting the subject's name: %s\n", log_error ("error setting the subject's name: %s\n",
@ -550,11 +565,8 @@ create_request (ctrl_t ctrl,
goto leave; goto leave;
} }
s = get_parameter_value (para, pNAMEEMAIL); for (seq=0; (s = get_parameter_value (para, pNAMEEMAIL, seq)); seq++)
if (s)
{ {
char *buf;
buf = xtrymalloc (strlen (s) + 3); buf = xtrymalloc (strlen (s) + 3);
if (!buf) if (!buf)
{ {
@ -575,6 +587,60 @@ create_request (ctrl_t ctrl,
} }
} }
for (seq=0; (s = get_parameter_value (para, pNAMEDNS, seq)); seq++)
{
len = strlen (s);
assert (len);
snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
buf = p = xtrymalloc (11 + strlen (numbuf) + len + 3);
if (!buf)
{
rc = OUT_OF_CORE (errno);
goto leave;
}
p = stpcpy (p, "(8:dns-name");
p = stpcpy (p, numbuf);
p = stpcpy (p, s);
strcpy (p, ")");
err = ksba_certreq_add_subject (cr, buf);
xfree (buf);
if (err)
{
log_error ("error setting the subject's alternate name: %s\n",
gpg_strerror (err));
rc = err;
goto leave;
}
}
for (seq=0; (s = get_parameter_value (para, pNAMEURI, seq)); seq++)
{
len = strlen (s);
assert (len);
snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
buf = p = xtrymalloc (6 + strlen (numbuf) + len + 3);
if (!buf)
{
rc = OUT_OF_CORE (errno);
goto leave;
}
p = stpcpy (p, "(3:uri");
p = stpcpy (p, numbuf);
p = stpcpy (p, s);
strcpy (p, ")");
err = ksba_certreq_add_subject (cr, buf);
xfree (buf);
if (err)
{
log_error ("error setting the subject's alternate name: %s\n",
gpg_strerror (err));
rc = err;
goto leave;
}
}
err = ksba_certreq_set_public_key (cr, public); err = ksba_certreq_set_public_key (cr, public);
if (err) if (err)

View File

@ -99,12 +99,14 @@ enum cmd_and_opt_values {
oDebug, oDebug,
oDebugLevel, oDebugLevel,
oDebugAll, oDebugAll,
oDebugNone,
oDebugWait, oDebugWait,
oDebugAllowCoreDump, oDebugAllowCoreDump,
oDebugNoChainValidation, oDebugNoChainValidation,
oDebugIgnoreExpiration, oDebugIgnoreExpiration,
oFixedPassphrase, oFixedPassphrase,
oLogFile, oLogFile,
oNoLogFile,
oEnableSpecialFilenames, oEnableSpecialFilenames,
@ -330,6 +332,7 @@ static ARGPARSE_OPTS opts[] = {
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") }, { oQuiet, "quiet", 0, N_("be somewhat more quiet") },
{ oNoTTY, "no-tty", 0, N_("don't use the terminal at all") }, { oNoTTY, "no-tty", 0, N_("don't use the terminal at all") },
{ oLogFile, "log-file" ,2, N_("use a log file for the server")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")},
{ oNoLogFile, "no-log-file" ,0, "@"},
#if 0 #if 0
{ oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") }, { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") },
{ oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") }, { oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") },
@ -351,6 +354,7 @@ static ARGPARSE_OPTS opts[] = {
{ oDebug, "debug" ,4|16, "@"}, { oDebug, "debug" ,4|16, "@"},
{ oDebugLevel, "debug-level" ,2, N_("|LEVEL|set the debugging level to LEVEL")}, { oDebugLevel, "debug-level" ,2, N_("|LEVEL|set the debugging level to LEVEL")},
{ oDebugAll, "debug-all" ,0, "@"}, { oDebugAll, "debug-all" ,0, "@"},
{ oDebugNone, "debug-none" ,0, "@"},
{ oDebugWait, "debug-wait" ,1, "@"}, { oDebugWait, "debug-wait" ,1, "@"},
{ oDebugAllowCoreDump, "debug-allow-core-dump", 0, "@" }, { oDebugAllowCoreDump, "debug-allow-core-dump", 0, "@" },
{ oDebugNoChainValidation, "debug-no-chain-validation", 0, "@"}, { oDebugNoChainValidation, "debug-no-chain-validation", 0, "@"},
@ -1032,7 +1036,8 @@ main ( int argc, char **argv)
break; break;
case oLogFile: logfile = pargs.r.ret_str; break; case oLogFile: logfile = pargs.r.ret_str; break;
case oNoLogFile: logfile = NULL; break;
case oBatch: case oBatch:
opt.batch = 1; opt.batch = 1;
greeting = 0; greeting = 0;
@ -1046,6 +1051,7 @@ main ( int argc, char **argv)
case oDebug: debug_value |= pargs.r.ret_ulong; break; case oDebug: debug_value |= pargs.r.ret_ulong; break;
case oDebugAll: debug_value = ~0; break; case oDebugAll: debug_value = ~0; break;
case oDebugNone: debug_value = 0; break;
case oDebugLevel: debug_level = pargs.r.ret_str; break; case oDebugLevel: debug_level = pargs.r.ret_str; break;
case oDebugWait: debug_wait = pargs.r.ret_int; break; case oDebugWait: debug_wait = pargs.r.ret_int; break;
case oDebugAllowCoreDump: case oDebugAllowCoreDump:

View File

@ -1,3 +1,9 @@
2005-07-21 Werner Koch <wk@g10code.com>
* gpgsm-gencert.sh: Reworked to allow for multiple email addresses
as well as DNsanmes and URi. Present the parameter file before
creating the certificate.
2005-07-04 Marcus Brinkmann <marcus@g10code.de> 2005-07-04 Marcus Brinkmann <marcus@g10code.de>
* symcryptrun.c (SYMC_BAD_PASSPHRASE, SYMC_CANCELED): New symbols, * symcryptrun.c (SYMC_BAD_PASSPHRASE, SYMC_CANCELED): New symbols,

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# -*- sh -*- # -*- sh -*-
# gpgsm-gencert.c - Generate X.509 certificates through GPGSM. # gpgsm-gencert.c - Generate X.509 certificates through GPGSM.
# Copyright (C) 2004 Free Software Foundation, Inc. # Copyright (C) 2004, 2005 Free Software Foundation, Inc.
# #
# This file is part of GnuPG. # This file is part of GnuPG.
# #
@ -93,25 +93,67 @@ KEY_LENGTH=$ANSWER
query_user_menu "Key usage" "sign, encrypt" "sign" "encrypt" query_user_menu "Key usage" "sign, encrypt" "sign" "encrypt"
KEY_USAGE=$ANSWER KEY_USAGE=$ANSWER
query_user "Name" query_user "Name (DN)"
NAME=$ANSWER NAME=$ANSWER
query_user "E-Mail address" EMAIL_ADDRESSES=
EMAIL_ADDRESS=$ANSWER LF=
while : ; do
query_user "E-Mail addresses (end with an empty line)"
[ -z "$ANSWER" ] && break
EMAIL_ADDRESSES="${EMAIL_ADDRESSES}${LF}Name-Email: $ANSWER"
LF='
'
done
DNS_ADDRESSES=
LF=
while : ; do
query_user "DNS Names (optional; end with an empty line)"
[ -z "$ANSWER" ] && break
DNS_ADDRESSES="${DNS_ADDRESSES}${LF}Name-DNS: $ANSWER"
LF='
'
done
URI_ADDRESSES=
LF=
while : ; do
query_user "URIs (optional; end with an empty line)"
[ -z "$ANSWER" ] && break
URI_ADDRESSES="${URI_ADDRESSES}${LF}Name-URI: $ANSWER"
LF='
'
done
file_parameter=$(mktemp "/tmp/gpgsm.XXXXXX") file_parameter=$(mktemp "/tmp/gpgsm.XXXXXX")
outfile=$(mktemp "/tmp/gpgsm.XXXXXX") outfile=$(mktemp "/tmp/gpgsm.XXXXXX")
cat > "$file_parameter" <<EOF
(
cat <<EOF
Key-Type: $KEY_TYPE Key-Type: $KEY_TYPE
Key-Length: $KEY_LENGTH Key-Length: $KEY_LENGTH
Key-Usage: $KEY_USAGE Key-Usage: $KEY_USAGE
Name-DN: $NAME Name-DN: $NAME
Name-Email: $EMAIL_ADDRESS
EOF EOF
[ -n "$EMAIL_ADDRESSES" ] && echo "$EMAIL_ADDRESSES"
[ -n "$DNS_ADDRESSES" ] && echo "$DNS_ADDRESSES"
[ -n "$URI_ADDRESSES" ] && echo "$URI_ADDRESSES"
) > "$file_parameter"
echo 'Parameters for certificate request to create:' >&2
cat -n "$file_parameter" >&2
echo >&2
query_user_menu "Really create such a CSR?" "yes" "no"
[ "$ANSWER" != "yes" ] && exit 1
echo -e "$ASSUAN_COMMANDS" | \ echo -e "$ASSUAN_COMMANDS" | \
gpgsm --server 4< "$file_parameter" 5>"$outfile" >/dev/null ./gpgsm --no-log-file --debug-level none --debug-none \
--server 4< "$file_parameter" 5>"$outfile" >/dev/null
cat "$outfile" cat "$outfile"