From 99f403b0154fa7c5c935f34122ebe860f30d12c6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 21 Jul 2005 18:29:13 +0000 Subject: [PATCH] * 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. --- sm/ChangeLog | 8 +++ sm/certreqgen.c | 122 +++++++++++++++++++++++++++++++---------- sm/gpgsm.c | 8 ++- tools/ChangeLog | 6 ++ tools/gpgsm-gencert.sh | 56 ++++++++++++++++--- 5 files changed, 164 insertions(+), 36 deletions(-) diff --git a/sm/ChangeLog b/sm/ChangeLog index cefa77e32..a76f586eb 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,11 @@ +2005-07-21 Werner Koch + + * 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 * keylist.c (email_kludge): Reworked. diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 2b920da7e..c9a092046 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -1,5 +1,5 @@ /* 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. * @@ -71,7 +71,11 @@ The format of the native parameter file is follows: Name-DN: subject name This is the DN name of the subject in rfc2253 format. Name-Email: - The ist the email address + The is an email address for the altSubjectName + Name-DNS: + The is an DNS name for the altSubjectName + Name-URI: + The is an URI for the altSubjectName Here is an example: $ cat >foo <key != key; r = r->next) - ; - return r; + for (r = para; r ; r = r->next) + if ( r->key == key && !seq--) + return r; + return NULL; } 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; } static int 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) return -1; if (digitp (r->u.value)) @@ -189,7 +196,7 @@ get_parameter_algo (struct para_data_s *para, enum para_name key) static int 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; unsigned int use; @@ -220,7 +227,7 @@ parse_parameter_usage (struct para_data_s *para, enum para_name key) static unsigned int 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) return 0; @@ -241,12 +248,15 @@ read_parameters (ctrl_t ctrl, FILE *fp, ksba_writer_t writer) static struct { const char *name; enum para_name key; + int allow_dups; } keywords[] = { { "Key-Type", pKEYTYPE}, { "Key-Length", pKEYLENGTH }, { "Key-Usage", pKEYUSAGE }, { "Name-DN", pNAMEDN }, - { "Name-Email", pNAMEEMAIL }, + { "Name-Email", pNAMEEMAIL, 1 }, + { "Name-DNS", pNAMEDNS, 1 }, + { "Name-URI", pNAMEURI, 1 }, { NULL, 0 } }; char line[1024], *p; @@ -347,7 +357,7 @@ read_parameters (ctrl_t ctrl, FILE *fp, ksba_writer_t writer) release_parameter_list (para); para = NULL; } - else + else if (!keywords[i].allow_dups) { 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]; int rc; ksba_sexp_t public; + int seq; /* 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 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); 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); return gpg_error (GPG_ERR_INV_PARAMETER); } /* check the keylength */ - if (!get_parameter (para, pKEYLENGTH)) + if (!get_parameter (para, pKEYLENGTH, 0)) nbits = 1024; else nbits = get_parameter_uint (para, pKEYLENGTH); if (nbits < 1024 || nbits > 4096) { /* 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"), r->lnr, nbits, 1024, 4096); 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 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); return gpg_error (GPG_ERR_INV_PARAMETER); } /* fixme check s */ /* 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) || *s == '@' @@ -485,7 +496,7 @@ proc_parameters (ctrl_t ctrl, || s[strlen(s)-1] == '.' || 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); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -497,7 +508,7 @@ proc_parameters (ctrl_t ctrl, rc = gpgsm_agent_genkey (ctrl, keyparms, &public); if (rc) { - r = get_parameter (para, pKEYTYPE); + r = get_parameter (para, pKEYTYPE, 0); log_error (_("line %d: key generation failed: %s\n"), r->lnr, gpg_strerror (rc)); return rc; @@ -524,6 +535,10 @@ create_request (ctrl_t ctrl, int rc = 0; const char *s; unsigned int use; + int seq; + char *buf, *p; + size_t len; + char numbuf[30]; err = ksba_certreq_new (&cr); if (err) @@ -541,7 +556,7 @@ create_request (ctrl_t ctrl, ksba_certreq_set_hash_function (cr, HASH_FNC, md); 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) { log_error ("error setting the subject's name: %s\n", @@ -550,11 +565,8 @@ create_request (ctrl_t ctrl, goto leave; } - s = get_parameter_value (para, pNAMEEMAIL); - if (s) + for (seq=0; (s = get_parameter_value (para, pNAMEEMAIL, seq)); seq++) { - char *buf; - buf = xtrymalloc (strlen (s) + 3); 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); if (err) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index fb6533030..0f9745a8c 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -99,12 +99,14 @@ enum cmd_and_opt_values { oDebug, oDebugLevel, oDebugAll, + oDebugNone, oDebugWait, oDebugAllowCoreDump, oDebugNoChainValidation, oDebugIgnoreExpiration, oFixedPassphrase, oLogFile, + oNoLogFile, oEnableSpecialFilenames, @@ -330,6 +332,7 @@ static ARGPARSE_OPTS opts[] = { { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, { oNoTTY, "no-tty", 0, N_("don't use the terminal at all") }, { oLogFile, "log-file" ,2, N_("use a log file for the server")}, + { oNoLogFile, "no-log-file" ,0, "@"}, #if 0 { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") }, { oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") }, @@ -351,6 +354,7 @@ static ARGPARSE_OPTS opts[] = { { oDebug, "debug" ,4|16, "@"}, { oDebugLevel, "debug-level" ,2, N_("|LEVEL|set the debugging level to LEVEL")}, { oDebugAll, "debug-all" ,0, "@"}, + { oDebugNone, "debug-none" ,0, "@"}, { oDebugWait, "debug-wait" ,1, "@"}, { oDebugAllowCoreDump, "debug-allow-core-dump", 0, "@" }, { oDebugNoChainValidation, "debug-no-chain-validation", 0, "@"}, @@ -1032,7 +1036,8 @@ main ( int argc, char **argv) break; case oLogFile: logfile = pargs.r.ret_str; break; - + case oNoLogFile: logfile = NULL; break; + case oBatch: opt.batch = 1; greeting = 0; @@ -1046,6 +1051,7 @@ main ( int argc, char **argv) case oDebug: debug_value |= pargs.r.ret_ulong; break; case oDebugAll: debug_value = ~0; break; + case oDebugNone: debug_value = 0; break; case oDebugLevel: debug_level = pargs.r.ret_str; break; case oDebugWait: debug_wait = pargs.r.ret_int; break; case oDebugAllowCoreDump: diff --git a/tools/ChangeLog b/tools/ChangeLog index c09819e26..e1dfce49d 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,9 @@ +2005-07-21 Werner Koch + + * 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 * symcryptrun.c (SYMC_BAD_PASSPHRASE, SYMC_CANCELED): New symbols, diff --git a/tools/gpgsm-gencert.sh b/tools/gpgsm-gencert.sh index ec5025b8f..44b06f3b3 100755 --- a/tools/gpgsm-gencert.sh +++ b/tools/gpgsm-gencert.sh @@ -1,7 +1,7 @@ #!/bin/sh # -*- sh -*- # 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. # @@ -93,25 +93,67 @@ KEY_LENGTH=$ANSWER query_user_menu "Key usage" "sign, encrypt" "sign" "encrypt" KEY_USAGE=$ANSWER -query_user "Name" +query_user "Name (DN)" NAME=$ANSWER -query_user "E-Mail address" -EMAIL_ADDRESS=$ANSWER +EMAIL_ADDRESSES= +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") outfile=$(mktemp "/tmp/gpgsm.XXXXXX") -cat > "$file_parameter" < "$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" | \ - 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"