mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
096e7457ec
The asymmetric quotes used by GNU in the past (`...') don't render nicely on modern systems. We now use two \x27 characters ('...'). The proper solution would be to use the correct Unicode symmetric quotes here. However this has the disadvantage that the system requires Unicode support. We don't want that today. If Unicode is available a generated po file can be used to output proper quotes. A simple sed script like the one used for en@quote is sufficient to change them. The changes have been done by applying sed -i "s/\`\([^'\`]*\)'/'\1'/g" to most files and fixing obvious problems by hand. The msgid strings in the po files were fixed with a similar command.
433 lines
12 KiB
C
433 lines
12 KiB
C
/* certreqgen-ui.c - Simple user interface for certreqgen.c
|
|
* Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
|
|
*
|
|
* This file is part of GnuPG.
|
|
*
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <assert.h>
|
|
|
|
#include "gpgsm.h"
|
|
#include <gcrypt.h>
|
|
|
|
#include "i18n.h"
|
|
#include "ttyio.h"
|
|
#include "membuf.h"
|
|
|
|
|
|
/* Prompt for lines and append them to MB. */
|
|
static void
|
|
ask_mb_lines (membuf_t *mb, const char *prefix)
|
|
{
|
|
char *answer = NULL;
|
|
|
|
do
|
|
{
|
|
xfree (answer);
|
|
answer = tty_get ("> ");
|
|
tty_kill_prompt ();
|
|
trim_spaces (answer);
|
|
if (*answer)
|
|
{
|
|
put_membuf_str (mb, prefix);
|
|
put_membuf_str (mb, answer);
|
|
put_membuf (mb, "\n", 1);
|
|
}
|
|
}
|
|
while (*answer);
|
|
xfree (answer);
|
|
}
|
|
|
|
/* Helper to store stuff in a membuf. */
|
|
void
|
|
store_key_value_lf (membuf_t *mb, const char *key, const char *value)
|
|
{
|
|
put_membuf_str (mb, key);
|
|
put_membuf_str (mb, value);
|
|
put_membuf (mb, "\n", 1);
|
|
}
|
|
|
|
/* Helper tp store a membuf create by mb_ask_lines into MB. Returns
|
|
-1 on error. */
|
|
int
|
|
store_mb_lines (membuf_t *mb, membuf_t *lines)
|
|
{
|
|
char *p;
|
|
|
|
if (get_membuf_len (lines))
|
|
{
|
|
put_membuf (lines, "", 1);
|
|
p = get_membuf (lines, NULL);
|
|
if (!p)
|
|
return -1;
|
|
put_membuf_str (mb, p);
|
|
xfree (p);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Chech whether we have a key for the key with HEXGRIP. Returns NULL
|
|
if not or a string describing the type of the key (RSA, ELG, DSA,
|
|
etc..). */
|
|
static const char *
|
|
check_keygrip (ctrl_t ctrl, const char *hexgrip)
|
|
{
|
|
gpg_error_t err;
|
|
ksba_sexp_t public;
|
|
size_t publiclen;
|
|
int algo;
|
|
|
|
if (hexgrip[0] == '&')
|
|
hexgrip++;
|
|
|
|
err = gpgsm_agent_readkey (ctrl, 0, hexgrip, &public);
|
|
if (err)
|
|
return NULL;
|
|
publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
|
|
|
|
get_pk_algo_from_canon_sexp (public, publiclen, &algo);
|
|
xfree (public);
|
|
|
|
switch (algo)
|
|
{
|
|
case GCRY_PK_RSA: return "RSA";
|
|
case GCRY_PK_DSA: return "DSA";
|
|
case GCRY_PK_ELG: return "ELG";
|
|
case GCRY_PK_ECDSA: return "ECDSA";
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/* This function is used to create a certificate request from the
|
|
command line. In the past the similar gpgsm-gencert.sh script has
|
|
been used for it; however that scripts requires a full Unix shell
|
|
and thus is not suitable for the Windows port. So here is the
|
|
re-implementation. */
|
|
void
|
|
gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
|
|
{
|
|
gpg_error_t err;
|
|
char *answer;
|
|
int selection;
|
|
estream_t fp = NULL;
|
|
int method;
|
|
char *keytype_buffer = NULL;
|
|
const char *keytype;
|
|
char *keygrip = NULL;
|
|
unsigned int nbits;
|
|
int minbits = 1024;
|
|
int maxbits = 4096;
|
|
int defbits = 2048;
|
|
const char *keyusage;
|
|
char *subject_name;
|
|
membuf_t mb_email, mb_dns, mb_uri, mb_result;
|
|
char *result = NULL;
|
|
int i;
|
|
const char *s, *s2;
|
|
int selfsigned;
|
|
|
|
answer = NULL;
|
|
init_membuf (&mb_email, 100);
|
|
init_membuf (&mb_dns, 100);
|
|
init_membuf (&mb_uri, 100);
|
|
init_membuf (&mb_result, 512);
|
|
|
|
again:
|
|
/* Get the type of the key. */
|
|
tty_printf (_("Please select what kind of key you want:\n"));
|
|
tty_printf (_(" (%d) RSA\n"), 1 );
|
|
tty_printf (_(" (%d) Existing key\n"), 2 );
|
|
tty_printf (_(" (%d) Existing key from card\n"), 3 );
|
|
|
|
do
|
|
{
|
|
xfree (answer);
|
|
answer = tty_get (_("Your selection? "));
|
|
tty_kill_prompt ();
|
|
selection = *answer? atoi (answer): 1;
|
|
}
|
|
while (!(selection >= 1 && selection <= 3));
|
|
method = selection;
|
|
|
|
/* Get size of the key. */
|
|
if (method == 1)
|
|
{
|
|
keytype = "RSA";
|
|
for (;;)
|
|
{
|
|
xfree (answer);
|
|
answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
|
|
tty_kill_prompt ();
|
|
trim_spaces (answer);
|
|
nbits = *answer? atoi (answer): defbits;
|
|
if (nbits < minbits || nbits > maxbits)
|
|
tty_printf(_("%s keysizes must be in the range %u-%u\n"),
|
|
"RSA", minbits, maxbits);
|
|
else
|
|
break; /* Okay. */
|
|
}
|
|
tty_printf (_("Requested keysize is %u bits\n"), nbits);
|
|
/* We round it up so that it better matches the word size. */
|
|
if (( nbits % 64))
|
|
{
|
|
nbits = ((nbits + 63) / 64) * 64;
|
|
tty_printf (_("rounded up to %u bits\n"), nbits);
|
|
}
|
|
}
|
|
else if (method == 2)
|
|
{
|
|
for (;;)
|
|
{
|
|
xfree (answer);
|
|
answer = tty_get (_("Enter the keygrip: "));
|
|
tty_kill_prompt ();
|
|
trim_spaces (answer);
|
|
|
|
if (!*answer)
|
|
goto again;
|
|
else if (strlen (answer) != 40 &&
|
|
!(answer[0] == '&' && strlen (answer+1) == 40))
|
|
tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n"));
|
|
else if (!(keytype = check_keygrip (ctrl, answer)) )
|
|
tty_printf (_("No key with this keygrip\n"));
|
|
else
|
|
break; /* Okay. */
|
|
}
|
|
xfree (keygrip);
|
|
keygrip = answer;
|
|
answer = NULL;
|
|
nbits = 1024; /* A dummy value is sufficient. */
|
|
}
|
|
else /* method == 3 */
|
|
{
|
|
char *serialno;
|
|
strlist_t keypairlist, sl;
|
|
int count;
|
|
|
|
err = gpgsm_agent_scd_serialno (ctrl, &serialno);
|
|
if (err)
|
|
{
|
|
tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
|
|
goto again;
|
|
}
|
|
tty_printf (_("Serial number of the card: %s\n"), serialno);
|
|
xfree (serialno);
|
|
|
|
err = gpgsm_agent_scd_keypairinfo (ctrl, &keypairlist);
|
|
if (err)
|
|
{
|
|
tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
|
|
goto again;
|
|
}
|
|
|
|
do
|
|
{
|
|
tty_printf (_("Available keys:\n"));
|
|
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
|
|
tty_printf (" (%d) %s\n", count, sl->d);
|
|
xfree (answer);
|
|
answer = tty_get (_("Your selection? "));
|
|
tty_kill_prompt ();
|
|
trim_spaces (answer);
|
|
selection = atoi (answer);
|
|
}
|
|
while (!(selection > 0 && selection < count));
|
|
|
|
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
|
|
if (count == selection)
|
|
break;
|
|
|
|
s = sl->d;
|
|
while (*s && !spacep (s))
|
|
s++;
|
|
while (spacep (s))
|
|
s++;
|
|
|
|
xfree (keygrip);
|
|
keygrip = NULL;
|
|
xfree (keytype_buffer);
|
|
keytype_buffer = xasprintf ("card:%s", s);
|
|
free_strlist (keypairlist);
|
|
keytype = keytype_buffer;
|
|
nbits = 1024; /* A dummy value is sufficient. */
|
|
}
|
|
|
|
/* Ask for the key usage. */
|
|
tty_printf (_("Possible actions for a %s key:\n"), "RSA");
|
|
tty_printf (_(" (%d) sign, encrypt\n"), 1 );
|
|
tty_printf (_(" (%d) sign\n"), 2 );
|
|
tty_printf (_(" (%d) encrypt\n"), 3 );
|
|
do
|
|
{
|
|
xfree (answer);
|
|
answer = tty_get (_("Your selection? "));
|
|
tty_kill_prompt ();
|
|
trim_spaces (answer);
|
|
selection = *answer? atoi (answer): 1;
|
|
switch (selection)
|
|
{
|
|
case 1: keyusage = "sign, encrypt"; break;
|
|
case 2: keyusage = "sign"; break;
|
|
case 3: keyusage = "encrypt"; break;
|
|
default: keyusage = NULL; break;
|
|
}
|
|
}
|
|
while (!keyusage);
|
|
|
|
/* Get the subject name. */
|
|
do
|
|
{
|
|
size_t erroff, errlen;
|
|
|
|
xfree (answer);
|
|
answer = tty_get (_("Enter the X.509 subject name: "));
|
|
tty_kill_prompt ();
|
|
trim_spaces (answer);
|
|
if (!*answer)
|
|
tty_printf (_("No subject name given\n"));
|
|
else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
|
|
{
|
|
if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
|
|
tty_printf (_("Invalid subject name label '%.*s'\n"),
|
|
(int)errlen, answer+erroff);
|
|
else
|
|
{
|
|
/* TRANSLATORS: The 22 in the second string is the
|
|
length of the first string up to the "%s". Please
|
|
adjust it do the length of your translation. The
|
|
second string is merely passed to atoi so you can
|
|
drop everything after the number. */
|
|
tty_printf (_("Invalid subject name '%s'\n"), answer);
|
|
tty_printf ("%*s^\n",
|
|
atoi (_("22 translator: see "
|
|
"certreg-ui.c:gpgsm_gencertreq_tty"))
|
|
+ (int)erroff, "");
|
|
}
|
|
*answer = 0;
|
|
}
|
|
}
|
|
while (!*answer);
|
|
subject_name = answer;
|
|
answer = NULL;
|
|
|
|
/* Get the email addresses. */
|
|
tty_printf (_("Enter email addresses"));
|
|
tty_printf (_(" (end with an empty line):\n"));
|
|
ask_mb_lines (&mb_email, "Name-Email: ");
|
|
|
|
/* DNS names. */
|
|
tty_printf (_("Enter DNS names"));
|
|
tty_printf (_(" (optional; end with an empty line):\n"));
|
|
ask_mb_lines (&mb_dns, "Name-DNS: ");
|
|
|
|
/* URIs. */
|
|
tty_printf (_("Enter URIs"));
|
|
tty_printf (_(" (optional; end with an empty line):\n"));
|
|
ask_mb_lines (&mb_uri, "Name-URI: ");
|
|
|
|
|
|
/* Want a self-signed certificate? */
|
|
selfsigned = tty_get_answer_is_yes
|
|
(_("Create self-signed certificate? (y/N) "));
|
|
|
|
|
|
/* Put it all together. */
|
|
store_key_value_lf (&mb_result, "Key-Type: ", keytype);
|
|
{
|
|
char numbuf[30];
|
|
snprintf (numbuf, sizeof numbuf, "%u", nbits);
|
|
store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
|
|
}
|
|
if (keygrip)
|
|
store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
|
|
store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
|
|
if (selfsigned)
|
|
store_key_value_lf (&mb_result, "Serial: ", "random");
|
|
store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
|
|
if (store_mb_lines (&mb_result, &mb_email))
|
|
goto mem_error;
|
|
if (store_mb_lines (&mb_result, &mb_dns))
|
|
goto mem_error;
|
|
if (store_mb_lines (&mb_result, &mb_uri))
|
|
goto mem_error;
|
|
put_membuf (&mb_result, "", 1);
|
|
result = get_membuf (&mb_result, NULL);
|
|
if (!result)
|
|
goto mem_error;
|
|
|
|
tty_printf (_("These parameters are used:\n"));
|
|
for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
|
|
tty_printf (" %.*s\n", (int)(s2-s), s);
|
|
tty_printf ("\n");
|
|
|
|
if (!tty_get_answer_is_yes ("Proceed with creation? (y/N) "))
|
|
goto leave;
|
|
|
|
/* Now create a parameter file and generate the key. */
|
|
fp = es_fopenmem (0, "w+");
|
|
if (!fp)
|
|
{
|
|
log_error (_("error creating temporary file: %s\n"), strerror (errno));
|
|
goto leave;
|
|
}
|
|
es_fputs (result, fp);
|
|
es_rewind (fp);
|
|
if (selfsigned)
|
|
tty_printf ("%s", _("Now creating self-signed certificate. "));
|
|
else
|
|
tty_printf ("%s", _("Now creating certificate request. "));
|
|
tty_printf ("%s", _("This may take a while ...\n"));
|
|
|
|
{
|
|
int save_pem = ctrl->create_pem;
|
|
ctrl->create_pem = 1; /* Force creation of PEM. */
|
|
err = gpgsm_genkey (ctrl, fp, output_stream);
|
|
ctrl->create_pem = save_pem;
|
|
}
|
|
if (!err)
|
|
{
|
|
if (selfsigned)
|
|
tty_printf (_("Ready.\n"));
|
|
else
|
|
tty_printf
|
|
(_("Ready. You should now send this request to your CA.\n"));
|
|
}
|
|
|
|
|
|
goto leave;
|
|
mem_error:
|
|
log_error (_("resource problem: out of core\n"));
|
|
leave:
|
|
es_fclose (fp);
|
|
xfree (answer);
|
|
xfree (subject_name);
|
|
xfree (keytype_buffer);
|
|
xfree (keygrip);
|
|
xfree (get_membuf (&mb_email, NULL));
|
|
xfree (get_membuf (&mb_dns, NULL));
|
|
xfree (get_membuf (&mb_uri, NULL));
|
|
xfree (get_membuf (&mb_result, NULL));
|
|
xfree (result);
|
|
}
|