mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Support X.509 certificate creation.
Using "gpgsm --genkey" allows the creation of a self-signed certificate via a new prompt. Using "gpgsm --genkey --batch" should allow the creation of arbitrary certificates controlled by a parameter file. An example parameter file is Key-Type: RSA Key-Length: 1024 Key-Grip: 2C50DC6101C10C9C643E315FE3EADCCBC24F4BEA Key-Usage: sign, encrypt Serial: random Name-DN: CN=some test key Name-Email: foo@example.org Name-Email: bar@exmaple.org Hash-Algo: SHA384 not-after: 2038-01-16 12:44 This creates a self-signed X.509 certificate using the key given by the keygrip and using SHA-384 as hash algorithm. The keyword signing-key can be used to sign the certificate with a different key. See sm/certreggen.c for details.
This commit is contained in:
parent
bb6d1b48f6
commit
28c157b55c
4
NEWS
4
NEWS
@ -19,9 +19,13 @@ Noteworthy changes in version 2.1.0beta2 (unreleased)
|
|||||||
|
|
||||||
* Dirmngr has taken over the function of the keyserver helpers. Thus
|
* Dirmngr has taken over the function of the keyserver helpers. Thus
|
||||||
we now have a specified direct interface to keyservers via Dirmngr.
|
we now have a specified direct interface to keyservers via Dirmngr.
|
||||||
|
LDAP, DNS and mail backends are not yet implemented.
|
||||||
|
|
||||||
* ECC support for GPG as described by draft-jivsov-openpgp-ecc-06.txt.
|
* ECC support for GPG as described by draft-jivsov-openpgp-ecc-06.txt.
|
||||||
|
|
||||||
|
* New GPGSM feature to create certificates from a parameter file.
|
||||||
|
Add prompt to the --gen-key UI to create self-signed certificates.
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 2.1.0beta1 (2010-10-26)
|
Noteworthy changes in version 2.1.0beta1 (2010-10-26)
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
|
@ -793,7 +793,8 @@ Unattended key generation
|
|||||||
This feature allows unattended generation of keys controlled by a
|
This feature allows unattended generation of keys controlled by a
|
||||||
parameter file. To use this feature, you use --gen-key together with
|
parameter file. To use this feature, you use --gen-key together with
|
||||||
--batch and feed the parameters either from stdin or from a file given
|
--batch and feed the parameters either from stdin or from a file given
|
||||||
on the commandline.
|
on the commandline. The description below is only for GPG; GPGSM has
|
||||||
|
a similar feature, see the file sm/certreqgen.c for a description.
|
||||||
|
|
||||||
The format of this file is as follows:
|
The format of this file is as follows:
|
||||||
o Text only, line length is limited to about 1000 chars.
|
o Text only, line length is limited to about 1000 chars.
|
||||||
@ -1220,6 +1221,8 @@ OIDs below the GnuPG arc:
|
|||||||
1.3.6.1.4.1.11591.2 GnuPG
|
1.3.6.1.4.1.11591.2 GnuPG
|
||||||
1.3.6.1.4.1.11591.2.1 notation
|
1.3.6.1.4.1.11591.2.1 notation
|
||||||
1.3.6.1.4.1.11591.2.1.1 pkaAddress
|
1.3.6.1.4.1.11591.2.1.1 pkaAddress
|
||||||
|
1.3.6.1.4.1.11591.2.2 X.509 extensions
|
||||||
|
1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
|
||||||
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
|
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
|
||||||
|
|
||||||
|
|
||||||
|
23
sm/ChangeLog
23
sm/ChangeLog
@ -1,3 +1,24 @@
|
|||||||
|
2011-03-01 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* certreqgen.c (pSERIAL, pISSUERDN, pNOTBEFORE, pNOTAFTER)
|
||||||
|
(pSIGNINGKEY, pHASHALGO): New.
|
||||||
|
(reqgen_ctrl_s): Remove field WRITER.
|
||||||
|
(read_parameters): Support new keywords. Change arg WRITER to
|
||||||
|
OUT_FP; pass that to proc_parameters.
|
||||||
|
(proc_parameters): Add arg WRITER. Check values of new keywords.
|
||||||
|
Create writer object here. Support generation of certificates.
|
||||||
|
(create_request): Take new arg SIGKEY. Allow for hash algorithms
|
||||||
|
other than SHA-1. Set serialno and other values for certificate
|
||||||
|
creation.
|
||||||
|
(gpgsm_genkey): Do not create writer object but pass output stream
|
||||||
|
to read_parameters.
|
||||||
|
* certreqgen-ui.c (gpgsm_gencertreq_tty): Ask for self-signed.
|
||||||
|
* misc.c (transform_sigval): New.
|
||||||
|
|
||||||
|
2011-02-25 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* certreqgen.c (create_request): Add arg SIGKEY.
|
||||||
|
|
||||||
2010-11-25 Werner Koch <wk@g10code.com>
|
2010-11-25 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* base64.c (gpgsm_create_writer): Remove arg FP which is not used
|
* base64.c (gpgsm_create_writer): Remove arg FP which is not used
|
||||||
@ -2876,7 +2897,7 @@ h2007-11-22 Werner Koch <wk@g10code.com>
|
|||||||
|
|
||||||
|
|
||||||
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
||||||
2010 Free Software Foundation, Inc.
|
2010, 2011 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is free software; as a special exception the author gives
|
This file is free software; as a special exception the author gives
|
||||||
unlimited permission to copy and/or distribute it, with or without
|
unlimited permission to copy and/or distribute it, with or without
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* certreqgen-ui.c - Simple user interface for certreqgen.c
|
/* certreqgen-ui.c - Simple user interface for certreqgen.c
|
||||||
* Copyright (C) 2007, 2010 Free Software Foundation, Inc.
|
* Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -145,6 +145,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
|
|||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
int i;
|
int i;
|
||||||
const char *s, *s2;
|
const char *s, *s2;
|
||||||
|
int selfsigned;
|
||||||
|
|
||||||
answer = NULL;
|
answer = NULL;
|
||||||
init_membuf (&mb_email, 100);
|
init_membuf (&mb_email, 100);
|
||||||
@ -346,6 +347,11 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
|
|||||||
ask_mb_lines (&mb_email, "Name-URI: ");
|
ask_mb_lines (&mb_email, "Name-URI: ");
|
||||||
|
|
||||||
|
|
||||||
|
/* Want a self-signed certificate? */
|
||||||
|
selfsigned = tty_get_answer_is_yes
|
||||||
|
(_("Create self-signed certificate? (y/N) "));
|
||||||
|
|
||||||
|
|
||||||
/* Put it all together. */
|
/* Put it all together. */
|
||||||
store_key_value_lf (&mb_result, "Key-Type: ", keytype);
|
store_key_value_lf (&mb_result, "Key-Type: ", keytype);
|
||||||
{
|
{
|
||||||
@ -353,10 +359,12 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
|
|||||||
snprintf (numbuf, sizeof numbuf, "%u", nbits);
|
snprintf (numbuf, sizeof numbuf, "%u", nbits);
|
||||||
store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
|
store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
|
||||||
}
|
}
|
||||||
store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
|
|
||||||
store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
|
|
||||||
if (keygrip)
|
if (keygrip)
|
||||||
store_key_value_lf (&mb_result, "Key-Grip: ", 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))
|
if (store_mb_lines (&mb_result, &mb_email))
|
||||||
goto mem_error;
|
goto mem_error;
|
||||||
if (store_mb_lines (&mb_result, &mb_dns))
|
if (store_mb_lines (&mb_result, &mb_dns))
|
||||||
@ -368,14 +376,13 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
|
|||||||
if (!result)
|
if (!result)
|
||||||
goto mem_error;
|
goto mem_error;
|
||||||
|
|
||||||
tty_printf (_("Parameters to be used for the certificate request:\n"));
|
tty_printf (_("These parameters are used:\n"));
|
||||||
for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
|
for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
|
||||||
tty_printf (" %.*s\n", (int)(s2-s), s);
|
tty_printf (" %.*s\n", (int)(s2-s), s);
|
||||||
tty_printf ("\n");
|
tty_printf ("\n");
|
||||||
|
|
||||||
|
if (!tty_get_answer_is_yes ("Proceed with creation? (y/N) "))
|
||||||
if (!tty_get_answer_is_yes ("Really create request? (y/N) "))
|
goto leave;
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* Now create a parameter file and generate the key. */
|
/* Now create a parameter file and generate the key. */
|
||||||
fp = es_fopenmem (0, "w+");
|
fp = es_fopenmem (0, "w+");
|
||||||
@ -386,8 +393,9 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
|
|||||||
}
|
}
|
||||||
es_fputs (result, fp);
|
es_fputs (result, fp);
|
||||||
es_rewind (fp);
|
es_rewind (fp);
|
||||||
tty_printf (_("Now creating certificate request. "
|
tty_printf (_("Now creating %s. "
|
||||||
"This may take a while ...\n"));
|
"This may take a while ...\n"),
|
||||||
|
selfsigned?_("self-signed certificate"):_("certificate request"));
|
||||||
{
|
{
|
||||||
int save_pem = ctrl->create_pem;
|
int save_pem = ctrl->create_pem;
|
||||||
ctrl->create_pem = 1; /* Force creation of PEM. */
|
ctrl->create_pem = 1; /* Force creation of PEM. */
|
||||||
@ -395,7 +403,13 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
|
|||||||
ctrl->create_pem = save_pem;
|
ctrl->create_pem = save_pem;
|
||||||
}
|
}
|
||||||
if (!err)
|
if (!err)
|
||||||
tty_printf (_("Ready. You should now send this request to your CA.\n"));
|
{
|
||||||
|
if (selfsigned)
|
||||||
|
tty_printf (_("Ready.\n"));
|
||||||
|
else
|
||||||
|
tty_printf
|
||||||
|
(_("Ready. You should now send this request to your CA.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
goto leave;
|
goto leave;
|
||||||
|
493
sm/certreqgen.c
493
sm/certreqgen.c
@ -1,6 +1,6 @@
|
|||||||
/* certreqgen.c - Generate a key and a certification request
|
/* certreqgen.c - Generate a key and a certification [request]
|
||||||
* Copyright (C) 2002, 2003, 2005, 2007,
|
* Copyright (C) 2002, 2003, 2005, 2007, 2010,
|
||||||
* 2010 Free Software Foundation, Inc.
|
* 2011 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -43,6 +43,7 @@ The format of the native parameter file is follows:
|
|||||||
Perform the key generation. Note that an implicit commit is done
|
Perform the key generation. Note that an implicit commit is done
|
||||||
at the next "Key-Type" parameter.
|
at the next "Key-Type" parameter.
|
||||||
%certfile <filename>
|
%certfile <filename>
|
||||||
|
[Not yet implemented!]
|
||||||
Do not write the certificate to the keyDB but to <filename>.
|
Do not write the certificate to the keyDB but to <filename>.
|
||||||
This must be given before the first
|
This must be given before the first
|
||||||
commit to take place, duplicate specification of the same filename
|
commit to take place, duplicate specification of the same filename
|
||||||
@ -51,35 +52,83 @@ The format of the native parameter file is follows:
|
|||||||
and all keys are written to that file. If a new filename is given,
|
and all keys are written to that file. If a new filename is given,
|
||||||
this file is created (and overwrites an existing one).
|
this file is created (and overwrites an existing one).
|
||||||
Both control statements must be given.
|
Both control statements must be given.
|
||||||
|
|
||||||
o The order of the parameters does not matter except for "Key-Type"
|
o The order of the parameters does not matter except for "Key-Type"
|
||||||
which must be the first parameter. The parameters are only for the
|
which must be the first parameter. The parameters are only for the
|
||||||
generated keyblock and parameters from previous key generations are not
|
generated keyblock and parameters from previous key generations are not
|
||||||
used. Some syntactically checks may be performed.
|
used. Some syntactically checks may be performed.
|
||||||
|
|
||||||
The currently defined parameters are:
|
The currently defined parameters are:
|
||||||
|
|
||||||
Key-Type: <algo>
|
Key-Type: <algo>
|
||||||
Starts a new parameter block by giving the type of the
|
Starts a new parameter block by giving the type of the
|
||||||
primary key. The algorithm must be capable of signing.
|
primary key. The algorithm must be capable of signing.
|
||||||
This is a required parameter. For now the only supported
|
This is a required parameter. For now the only supported
|
||||||
algorithm is "rsa".
|
algorithm is "rsa".
|
||||||
|
|
||||||
Key-Length: <length-in-bits>
|
Key-Length: <length-in-bits>
|
||||||
Length of the key in bits. Default is 2048.
|
Length of the key in bits. Default is 2048.
|
||||||
Key-Grip: hexstring
|
|
||||||
|
Key-Grip: <hexstring>
|
||||||
This is optional and used to generate a request for an already
|
This is optional and used to generate a request for an already
|
||||||
existing key. Key-Length will be ignored when given,
|
existing key. Key-Length will be ignored when given,
|
||||||
|
|
||||||
Key-Usage: <usage-list>
|
Key-Usage: <usage-list>
|
||||||
Space or comma delimited list of key usage, allowed values are
|
Space or comma delimited list of key usage, allowed values are
|
||||||
"encrypt" and "sign". This is used to generate the KeyUsage extension.
|
"encrypt" and "sign". This is used to generate the KeyUsage extension.
|
||||||
Please make sure that the algorithm is capable of this usage. Default
|
Please make sure that the algorithm is capable of this usage. Default
|
||||||
is to allow encrypt and sign.
|
is to allow encrypt and sign.
|
||||||
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 is an email address for the altSubjectName
|
The is an email address for the altSubjectName
|
||||||
|
|
||||||
Name-DNS: <string>
|
Name-DNS: <string>
|
||||||
The is an DNS name for the altSubjectName
|
The is an DNS name for the altSubjectName
|
||||||
|
|
||||||
Name-URI: <string>
|
Name-URI: <string>
|
||||||
The is an URI for the altSubjectName
|
The is an URI for the altSubjectName
|
||||||
|
|
||||||
|
The following parameters are only used if a certificate (and not
|
||||||
|
a certificate signing request) is requested:
|
||||||
|
|
||||||
|
Serial: <sn>
|
||||||
|
If this parameter is given an X.509 certificate will be
|
||||||
|
generated. SN is expected to be a hex string representing an
|
||||||
|
unsigned integer of arbitary length. The special value
|
||||||
|
"random" can be used to crete a 64 bit random serial number.
|
||||||
|
|
||||||
|
Issuer-DN: <issuer_name>
|
||||||
|
This is the DN name of the issuer in rfc2253 format. If it is
|
||||||
|
not set the subject DN will be used instead. This creates a
|
||||||
|
self-signed certificate. Only in this case a special GnuPG
|
||||||
|
extension will then be included in the certificate to mark it
|
||||||
|
as a standalone certificate.
|
||||||
|
|
||||||
|
Creation-Date: <iso-date>
|
||||||
|
Set the notBefore date of the certificate. Either a date like
|
||||||
|
"1986-04-26" or a full timestamp like "19860426T042640" may be
|
||||||
|
used. The time is considered to be UTC. If it is not given
|
||||||
|
the current date is used.
|
||||||
|
|
||||||
|
Expire-Date: <iso-date>
|
||||||
|
Set the notBefore date of the certificate. Either a date like
|
||||||
|
"1986-04-26" or a full timestamp like "19860426T042640" may be
|
||||||
|
used. The time is considered to be UTC. If it is not given a
|
||||||
|
default value is used.
|
||||||
|
|
||||||
|
Signing-Key: <keygrip>
|
||||||
|
This gives the keygrip of the key used to sign the
|
||||||
|
certificate. If it is not given a self-signed certificate
|
||||||
|
will be created.
|
||||||
|
|
||||||
|
Hash-Algo: <hash-algo>
|
||||||
|
Use HASH-ALGO for this certificate. The supported hash
|
||||||
|
algorithms are: "sha-1", "sha-256", "sha-384" and "sha-512".
|
||||||
|
"sha-1" is the default.
|
||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
$ cat >foo <<EOF
|
$ cat >foo <<EOF
|
||||||
%echo Generating a standard key
|
%echo Generating a standard key
|
||||||
@ -111,18 +160,26 @@ EOF
|
|||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
||||||
enum para_name {
|
enum para_name
|
||||||
pKEYTYPE,
|
{
|
||||||
pKEYLENGTH,
|
pKEYTYPE,
|
||||||
pKEYGRIP,
|
pKEYLENGTH,
|
||||||
pKEYUSAGE,
|
pKEYGRIP,
|
||||||
pNAMEDN,
|
pKEYUSAGE,
|
||||||
pNAMEEMAIL,
|
pNAMEDN,
|
||||||
pNAMEDNS,
|
pNAMEEMAIL,
|
||||||
pNAMEURI
|
pNAMEDNS,
|
||||||
};
|
pNAMEURI,
|
||||||
|
pSERIAL,
|
||||||
|
pISSUERDN,
|
||||||
|
pNOTBEFORE,
|
||||||
|
pNOTAFTER,
|
||||||
|
pSIGNINGKEY,
|
||||||
|
pHASHALGO
|
||||||
|
};
|
||||||
|
|
||||||
struct para_data_s {
|
struct para_data_s
|
||||||
|
{
|
||||||
struct para_data_s *next;
|
struct para_data_s *next;
|
||||||
int lnr;
|
int lnr;
|
||||||
enum para_name key;
|
enum para_name key;
|
||||||
@ -132,24 +189,28 @@ struct para_data_s {
|
|||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reqgen_ctrl_s {
|
struct reqgen_ctrl_s
|
||||||
|
{
|
||||||
int lnr;
|
int lnr;
|
||||||
int dryrun;
|
int dryrun;
|
||||||
ksba_writer_t writer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const char oidstr_keyUsage[] = "2.5.29.15";
|
static const char oidstr_keyUsage[] = "2.5.29.15";
|
||||||
|
static const char oidstr_basicConstraints[] = "2.5.29.19";
|
||||||
|
static const char oidstr_standaloneCertificate[] = "1.3.6.1.4.1.11591.2.2.1";
|
||||||
|
|
||||||
|
|
||||||
static int proc_parameters (ctrl_t ctrl,
|
static int proc_parameters (ctrl_t ctrl,
|
||||||
struct para_data_s *para,
|
struct para_data_s *para,
|
||||||
|
estream_t out_fp,
|
||||||
struct reqgen_ctrl_s *outctrl);
|
struct reqgen_ctrl_s *outctrl);
|
||||||
static int create_request (ctrl_t ctrl,
|
static int create_request (ctrl_t ctrl,
|
||||||
struct para_data_s *para,
|
struct para_data_s *para,
|
||||||
const char *carddirect,
|
const char *carddirect,
|
||||||
ksba_const_sexp_t public,
|
ksba_const_sexp_t public,
|
||||||
struct reqgen_ctrl_s *outctrl);
|
ksba_const_sexp_t sigkey,
|
||||||
|
ksba_writer_t writer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -248,7 +309,7 @@ get_parameter_uint (struct para_data_s *para, enum para_name key)
|
|||||||
/* Read the certificate generation parameters from FP and generate
|
/* Read the certificate generation parameters from FP and generate
|
||||||
(all) certificate requests. */
|
(all) certificate requests. */
|
||||||
static int
|
static int
|
||||||
read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
|
read_parameters (ctrl_t ctrl, estream_t fp, estream_t out_fp)
|
||||||
{
|
{
|
||||||
static struct {
|
static struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -263,6 +324,14 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
|
|||||||
{ "Name-Email", pNAMEEMAIL, 1 },
|
{ "Name-Email", pNAMEEMAIL, 1 },
|
||||||
{ "Name-DNS", pNAMEDNS, 1 },
|
{ "Name-DNS", pNAMEDNS, 1 },
|
||||||
{ "Name-URI", pNAMEURI, 1 },
|
{ "Name-URI", pNAMEURI, 1 },
|
||||||
|
{ "Serial", pSERIAL },
|
||||||
|
{ "Issuer-DN", pISSUERDN },
|
||||||
|
{ "Creation-Date", pNOTBEFORE },
|
||||||
|
{ "Not-Before", pNOTBEFORE },
|
||||||
|
{ "Expire-Date", pNOTAFTER },
|
||||||
|
{ "Not-After", pNOTAFTER },
|
||||||
|
{ "Signing-Key", pSIGNINGKEY },
|
||||||
|
{ "Hash-Algo", pHASHALGO },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
char line[1024], *p;
|
char line[1024], *p;
|
||||||
@ -272,7 +341,6 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
|
|||||||
struct reqgen_ctrl_s outctrl;
|
struct reqgen_ctrl_s outctrl;
|
||||||
|
|
||||||
memset (&outctrl, 0, sizeof (outctrl));
|
memset (&outctrl, 0, sizeof (outctrl));
|
||||||
outctrl.writer = writer;
|
|
||||||
|
|
||||||
err = NULL;
|
err = NULL;
|
||||||
para = NULL;
|
para = NULL;
|
||||||
@ -309,7 +377,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
|
|||||||
outctrl.dryrun = 1;
|
outctrl.dryrun = 1;
|
||||||
else if (!ascii_strcasecmp( keyword, "%commit"))
|
else if (!ascii_strcasecmp( keyword, "%commit"))
|
||||||
{
|
{
|
||||||
rc = proc_parameters (ctrl, para, &outctrl);
|
rc = proc_parameters (ctrl, para, out_fp, &outctrl);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
any = 1;
|
any = 1;
|
||||||
@ -356,7 +424,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
|
|||||||
|
|
||||||
if (keywords[i].key == pKEYTYPE && para)
|
if (keywords[i].key == pKEYTYPE && para)
|
||||||
{
|
{
|
||||||
rc = proc_parameters (ctrl, para, &outctrl);
|
rc = proc_parameters (ctrl, para, out_fp, &outctrl);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
any = 1;
|
any = 1;
|
||||||
@ -399,7 +467,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, ksba_writer_t writer)
|
|||||||
}
|
}
|
||||||
else if (para)
|
else if (para)
|
||||||
{
|
{
|
||||||
rc = proc_parameters (ctrl, para, &outctrl);
|
rc = proc_parameters (ctrl, para, out_fp, &outctrl);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
any = 1;
|
any = 1;
|
||||||
@ -438,18 +506,19 @@ has_invalid_email_chars (const char *s)
|
|||||||
|
|
||||||
/* Check that all required parameters are given and perform the action */
|
/* Check that all required parameters are given and perform the action */
|
||||||
static int
|
static int
|
||||||
proc_parameters (ctrl_t ctrl,
|
proc_parameters (ctrl_t ctrl, struct para_data_s *para,
|
||||||
struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
|
estream_t out_fp, struct reqgen_ctrl_s *outctrl)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
struct para_data_s *r;
|
struct para_data_s *r;
|
||||||
const char *s;
|
const char *s, *string;
|
||||||
int i;
|
int i;
|
||||||
unsigned int nbits;
|
unsigned int nbits;
|
||||||
char numbuf[20];
|
char numbuf[20];
|
||||||
unsigned char keyparms[100];
|
unsigned char keyparms[100];
|
||||||
int rc;
|
int rc;
|
||||||
ksba_sexp_t public;
|
ksba_sexp_t public;
|
||||||
|
ksba_sexp_t sigkey = NULL;
|
||||||
int seq;
|
int seq;
|
||||||
size_t erroff, errlen;
|
size_t erroff, errlen;
|
||||||
char *cardkeyid = NULL;
|
char *cardkeyid = NULL;
|
||||||
@ -539,6 +608,100 @@ proc_parameters (ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check the optional serial number. */
|
||||||
|
string = get_parameter_value (para, pSERIAL, 0);
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
if (!strcmp (string, "random"))
|
||||||
|
; /* Okay. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (s=string, i=0; hexdigitp (s); s++, i++)
|
||||||
|
;
|
||||||
|
if (*s)
|
||||||
|
{
|
||||||
|
r = get_parameter (para, pSERIAL, 0);
|
||||||
|
log_error (_("line %d: invalid serial number\n"), r->lnr);
|
||||||
|
xfree (cardkeyid);
|
||||||
|
return gpg_error (GPG_ERR_INV_PARAMETER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the optional issuer DN. */
|
||||||
|
string = get_parameter_value (para, pISSUERDN, 0);
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
err = ksba_dn_teststr (string, 0, &erroff, &errlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
r = get_parameter (para, pISSUERDN, 0);
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
|
||||||
|
log_error (_("line %d: invalid issuer name label `%.*s'\n"),
|
||||||
|
r->lnr, (int)errlen, string+erroff);
|
||||||
|
else
|
||||||
|
log_error (_("line %d: invalid issuer name `%s' at pos %d\n"),
|
||||||
|
r->lnr, string, (int)erroff);
|
||||||
|
xfree (cardkeyid);
|
||||||
|
return gpg_error (GPG_ERR_INV_PARAMETER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the optional creation date. */
|
||||||
|
string = get_parameter_value (para, pNOTBEFORE, 0);
|
||||||
|
if (string && !string2isotime (NULL, string))
|
||||||
|
{
|
||||||
|
r = get_parameter (para, pNOTBEFORE, 0);
|
||||||
|
log_error (_("line %d: invalid date given\n"), r->lnr);
|
||||||
|
xfree (cardkeyid);
|
||||||
|
return gpg_error (GPG_ERR_INV_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check the optional expire date. */
|
||||||
|
string = get_parameter_value (para, pNOTAFTER, 0);
|
||||||
|
if (string && !string2isotime (NULL, string))
|
||||||
|
{
|
||||||
|
r = get_parameter (para, pNOTAFTER, 0);
|
||||||
|
log_error (_("line %d: invalid date given\n"), r->lnr);
|
||||||
|
xfree (cardkeyid);
|
||||||
|
return gpg_error (GPG_ERR_INV_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the optional signing key. */
|
||||||
|
string = get_parameter_value (para, pSIGNINGKEY, 0);
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
rc = gpgsm_agent_readkey (ctrl, 0, string, &sigkey);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
r = get_parameter (para, pKEYTYPE, 0);
|
||||||
|
log_error (_("line %d: error getting signing key by keygrip `%s'"
|
||||||
|
": %s\n"), r->lnr, s, gpg_strerror (rc));
|
||||||
|
xfree (cardkeyid);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the optional hash-algo. */
|
||||||
|
{
|
||||||
|
int mdalgo;
|
||||||
|
|
||||||
|
string = get_parameter_value (para, pHASHALGO, 0);
|
||||||
|
if (string && !((mdalgo = gcry_md_map_name (string))
|
||||||
|
&& (mdalgo == GCRY_MD_SHA1
|
||||||
|
|| mdalgo == GCRY_MD_SHA256
|
||||||
|
|| mdalgo == GCRY_MD_SHA384
|
||||||
|
|| mdalgo == GCRY_MD_SHA512)))
|
||||||
|
{
|
||||||
|
r = get_parameter (para, pHASHALGO, 0);
|
||||||
|
log_error (_("line %d: invalid hash algorithm given\n"), r->lnr);
|
||||||
|
xfree (cardkeyid);
|
||||||
|
return gpg_error (GPG_ERR_INV_PARAMETER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create or retrieve the public key. */
|
||||||
if (cardkeyid) /* Take the key from the current smart card. */
|
if (cardkeyid) /* Take the key from the current smart card. */
|
||||||
{
|
{
|
||||||
rc = gpgsm_agent_readkey (ctrl, 1, cardkeyid, &public);
|
rc = gpgsm_agent_readkey (ctrl, 1, cardkeyid, &public);
|
||||||
@ -547,6 +710,7 @@ proc_parameters (ctrl_t ctrl,
|
|||||||
r = get_parameter (para, pKEYTYPE, 0);
|
r = get_parameter (para, pKEYTYPE, 0);
|
||||||
log_error (_("line %d: error reading key `%s' from card: %s\n"),
|
log_error (_("line %d: error reading key `%s' from card: %s\n"),
|
||||||
r->lnr, cardkeyid, gpg_strerror (rc));
|
r->lnr, cardkeyid, gpg_strerror (rc));
|
||||||
|
xfree (sigkey);
|
||||||
xfree (cardkeyid);
|
xfree (cardkeyid);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -559,11 +723,12 @@ proc_parameters (ctrl_t ctrl,
|
|||||||
r = get_parameter (para, pKEYTYPE, 0);
|
r = get_parameter (para, pKEYTYPE, 0);
|
||||||
log_error (_("line %d: error getting key by keygrip `%s': %s\n"),
|
log_error (_("line %d: error getting key by keygrip `%s': %s\n"),
|
||||||
r->lnr, s, gpg_strerror (rc));
|
r->lnr, s, gpg_strerror (rc));
|
||||||
|
xfree (sigkey);
|
||||||
xfree (cardkeyid);
|
xfree (cardkeyid);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else /* Generate new key. */
|
else if (!outctrl->dryrun) /* Generate new key. */
|
||||||
{
|
{
|
||||||
sprintf (numbuf, "%u", nbits);
|
sprintf (numbuf, "%u", nbits);
|
||||||
snprintf ((char*)keyparms, DIM (keyparms)-1,
|
snprintf ((char*)keyparms, DIM (keyparms)-1,
|
||||||
@ -575,12 +740,45 @@ proc_parameters (ctrl_t ctrl,
|
|||||||
r = get_parameter (para, pKEYTYPE, 0);
|
r = get_parameter (para, pKEYTYPE, 0);
|
||||||
log_error (_("line %d: key generation failed: %s <%s>\n"),
|
log_error (_("line %d: key generation failed: %s <%s>\n"),
|
||||||
r->lnr, gpg_strerror (rc), gpg_strsource (rc));
|
r->lnr, gpg_strerror (rc), gpg_strsource (rc));
|
||||||
|
xfree (sigkey);
|
||||||
xfree (cardkeyid);
|
xfree (cardkeyid);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = create_request (ctrl, para, cardkeyid, public, outctrl);
|
|
||||||
|
if (!outctrl->dryrun)
|
||||||
|
{
|
||||||
|
Base64Context b64writer = NULL;
|
||||||
|
ksba_writer_t writer;
|
||||||
|
int create_cert ;
|
||||||
|
|
||||||
|
create_cert = !!get_parameter_value (para, pSERIAL, 0);
|
||||||
|
|
||||||
|
ctrl->pem_name = create_cert? "CERTIFICATE" : "CERTIFICATE REQUEST";
|
||||||
|
rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
|
||||||
|
if (rc)
|
||||||
|
log_error ("can't create writer: %s\n", gpg_strerror (rc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = create_request (ctrl, para, cardkeyid, public, sigkey, writer);
|
||||||
|
if (!rc)
|
||||||
|
{
|
||||||
|
rc = gpgsm_finish_writer (b64writer);
|
||||||
|
if (rc)
|
||||||
|
log_error ("write failed: %s\n", gpg_strerror (rc));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gpgsm_status (ctrl, STATUS_KEY_CREATED, "P");
|
||||||
|
log_info ("certificate%s created\n",
|
||||||
|
create_cert?"":" request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gpgsm_destroy_writer (b64writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (sigkey);
|
||||||
xfree (public);
|
xfree (public);
|
||||||
xfree (cardkeyid);
|
xfree (cardkeyid);
|
||||||
|
|
||||||
@ -595,25 +793,34 @@ create_request (ctrl_t ctrl,
|
|||||||
struct para_data_s *para,
|
struct para_data_s *para,
|
||||||
const char *carddirect,
|
const char *carddirect,
|
||||||
ksba_const_sexp_t public,
|
ksba_const_sexp_t public,
|
||||||
struct reqgen_ctrl_s *outctrl)
|
ksba_const_sexp_t sigkey,
|
||||||
|
ksba_writer_t writer)
|
||||||
{
|
{
|
||||||
ksba_certreq_t cr;
|
ksba_certreq_t cr;
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
gcry_md_hd_t md;
|
gcry_md_hd_t md;
|
||||||
ksba_stop_reason_t stopreason;
|
ksba_stop_reason_t stopreason;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
const char *s;
|
const char *s, *string;
|
||||||
unsigned int use;
|
unsigned int use;
|
||||||
int seq;
|
int seq;
|
||||||
char *buf, *p;
|
char *buf, *p;
|
||||||
size_t len;
|
size_t len;
|
||||||
char numbuf[30];
|
char numbuf[30];
|
||||||
|
ksba_isotime_t atime;
|
||||||
|
int certmode = 0;
|
||||||
|
int mdalgo;
|
||||||
|
|
||||||
err = ksba_certreq_new (&cr);
|
err = ksba_certreq_new (&cr);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
|
string = get_parameter_value (para, pHASHALGO, 0);
|
||||||
|
if (string)
|
||||||
|
mdalgo = gcry_md_map_name (string);
|
||||||
|
else
|
||||||
|
mdalgo = GCRY_MD_SHA1;
|
||||||
|
rc = gcry_md_open (&md, mdalgo, 0);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("md_open failed: %s\n", gpg_strerror (rc));
|
log_error ("md_open failed: %s\n", gpg_strerror (rc));
|
||||||
@ -623,7 +830,7 @@ create_request (ctrl_t ctrl,
|
|||||||
gcry_md_start_debug (md, "cr.cri");
|
gcry_md_start_debug (md, "cr.cri");
|
||||||
|
|
||||||
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, writer);
|
||||||
|
|
||||||
err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN, 0));
|
err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN, 0));
|
||||||
if (err)
|
if (err)
|
||||||
@ -720,7 +927,7 @@ create_request (ctrl_t ctrl,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set key usage flags. */
|
||||||
use = get_parameter_uint (para, pKEYUSAGE);
|
use = get_parameter_uint (para, pKEYUSAGE);
|
||||||
if (use == GCRY_PK_USAGE_SIGN)
|
if (use == GCRY_PK_USAGE_SIGN)
|
||||||
{
|
{
|
||||||
@ -749,6 +956,170 @@ create_request (ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* See whether we want to create an X.509 certificate. */
|
||||||
|
string = get_parameter_value (para, pSERIAL, 0);
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
certmode = 1;
|
||||||
|
|
||||||
|
/* Store the serial number. */
|
||||||
|
if (!strcmp (string, "random"))
|
||||||
|
{
|
||||||
|
char snbuf[3+8+1];
|
||||||
|
|
||||||
|
memcpy (snbuf, "(8:", 3);
|
||||||
|
gcry_create_nonce (snbuf+3, 8);
|
||||||
|
/* Clear high bit to guarantee a positive integer. */
|
||||||
|
snbuf[3] &= 0x7f;
|
||||||
|
snbuf[3+8] = ')';
|
||||||
|
err = ksba_certreq_set_serial (cr, snbuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *hexbuf;
|
||||||
|
|
||||||
|
/* Allocate a buffer large enough to prefix the string with
|
||||||
|
a '0' so to have an even number of digits. Prepend two
|
||||||
|
further '0' so that the binary result will have a leading
|
||||||
|
0 byte and thus can't be the representation of a negative
|
||||||
|
number. Note that ksba_certreq_set_serial strips all
|
||||||
|
unneeded leading 0 bytes. */
|
||||||
|
hexbuf = p = xtrymalloc (2 + 1 + strlen (string) + 1);
|
||||||
|
if (!hexbuf)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
if ((strlen (string) & 1))
|
||||||
|
*p++ = '0';
|
||||||
|
*p++ = '0';
|
||||||
|
*p++ = '0';
|
||||||
|
strcpy (p, string);
|
||||||
|
for (p=hexbuf, len=0; p[0] && p[1]; p += 2)
|
||||||
|
((unsigned char*)hexbuf)[len++] = xtoi_2 (s);
|
||||||
|
/* Now build the S-expression. */
|
||||||
|
snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
|
||||||
|
buf = p = xtrymalloc (1 + strlen (numbuf) + len + 1 + 1);
|
||||||
|
if (!buf)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
xfree (hexbuf);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
p = stpcpy (stpcpy (buf, "("), numbuf);
|
||||||
|
memcpy (p, hexbuf, len);
|
||||||
|
p += len;
|
||||||
|
strcpy (p, ")");
|
||||||
|
xfree (hexbuf);
|
||||||
|
err = ksba_certreq_set_serial (cr, buf);
|
||||||
|
xfree (buf);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error setting the serial number: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Store the issuer DN. If no issuer DN is given and no signing
|
||||||
|
key has been set we add the standalone extension and the
|
||||||
|
basic constraints to mark it as a self-signed CA
|
||||||
|
certificate. */
|
||||||
|
string = get_parameter_value (para, pISSUERDN, 0);
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
/* Issuer DN given. Note that this may be the same as the
|
||||||
|
subject DN and thus this could as well be a self-signed
|
||||||
|
certificate. However the caller needs to explicitly
|
||||||
|
specify basicConstraints and so forth. */
|
||||||
|
err = ksba_certreq_set_issuer (cr, string);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error setting the issuer DN: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (!string && !sigkey)
|
||||||
|
{
|
||||||
|
/* Self-signed certificate requested. Add basicConstraints
|
||||||
|
and the custom GnuPG standalone extension. */
|
||||||
|
err = ksba_certreq_add_extension (cr, oidstr_basicConstraints, 1,
|
||||||
|
"\x30\x03\x01\x01\xff", 5);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
err = ksba_certreq_add_extension (cr, oidstr_standaloneCertificate, 0,
|
||||||
|
"\x01\x01\xff", 3);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the creation date. */
|
||||||
|
string = get_parameter_value (para, pNOTBEFORE, 0);
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
if (!string2isotime (atime, string))
|
||||||
|
BUG (); /* We already checked the value. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gnupg_get_isotime (atime);
|
||||||
|
err = ksba_certreq_set_validity (cr, 0, atime);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error setting the creation date: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Store the expire date. If it is not given, libksba inserts a
|
||||||
|
default value. */
|
||||||
|
string = get_parameter_value (para, pNOTAFTER, 0);
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
if (!string2isotime (atime, string))
|
||||||
|
BUG (); /* We already checked the value. */
|
||||||
|
err = ksba_certreq_set_validity (cr, 1, atime);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error setting the expire date: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Figure out the signing algorithm. If no sigkey has been
|
||||||
|
given we set it to the public key to create a self-signed
|
||||||
|
certificate. */
|
||||||
|
if (!sigkey)
|
||||||
|
sigkey = public;
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned char *siginfo;
|
||||||
|
|
||||||
|
err = transform_sigval (sigkey,
|
||||||
|
gcry_sexp_canon_len (sigkey, 0, NULL, NULL),
|
||||||
|
mdalgo, &siginfo, NULL);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
err = ksba_certreq_set_siginfo (cr, siginfo);
|
||||||
|
xfree (siginfo);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error setting the siginfo: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
rc = err;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sigkey = public;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
err = ksba_certreq_build (cr, &stopreason);
|
err = ksba_certreq_build (cr, &stopreason);
|
||||||
@ -764,17 +1135,17 @@ create_request (ctrl_t ctrl,
|
|||||||
size_t n;
|
size_t n;
|
||||||
unsigned char grip[20];
|
unsigned char grip[20];
|
||||||
char hexgrip[41];
|
char hexgrip[41];
|
||||||
unsigned char *sigval;
|
unsigned char *sigval, *newsigval;
|
||||||
size_t siglen;
|
size_t siglen;
|
||||||
|
|
||||||
n = gcry_sexp_canon_len (public, 0, NULL, NULL);
|
n = gcry_sexp_canon_len (sigkey, 0, NULL, NULL);
|
||||||
if (!n)
|
if (!n)
|
||||||
{
|
{
|
||||||
log_error ("libksba did not return a proper S-Exp\n");
|
log_error ("libksba did not return a proper S-Exp\n");
|
||||||
rc = gpg_error (GPG_ERR_BUG);
|
rc = gpg_error (GPG_ERR_BUG);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)public, n);
|
rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)sigkey, n);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
|
log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
|
||||||
@ -790,14 +1161,15 @@ create_request (ctrl_t ctrl,
|
|||||||
gcry_sexp_release (s_pkey);
|
gcry_sexp_release (s_pkey);
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
|
|
||||||
log_info ("about to sign CSR for key: &%s\n", hexgrip);
|
log_info ("about to sign the %s for key: &%s\n",
|
||||||
|
certmode? "certificate":"CSR", hexgrip);
|
||||||
|
|
||||||
if (carddirect)
|
if (carddirect)
|
||||||
rc = gpgsm_scd_pksign (ctrl, carddirect, NULL,
|
rc = gpgsm_scd_pksign (ctrl, carddirect, NULL,
|
||||||
gcry_md_read(md, GCRY_MD_SHA1),
|
gcry_md_read (md, mdalgo),
|
||||||
gcry_md_get_algo_dlen (GCRY_MD_SHA1),
|
gcry_md_get_algo_dlen (mdalgo),
|
||||||
GCRY_MD_SHA1,
|
mdalgo,
|
||||||
&sigval, &siglen);
|
&sigval, &siglen);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *orig_codeset;
|
char *orig_codeset;
|
||||||
@ -810,9 +1182,9 @@ create_request (ctrl_t ctrl,
|
|||||||
" more.\n"));
|
" more.\n"));
|
||||||
i18n_switchback (orig_codeset);
|
i18n_switchback (orig_codeset);
|
||||||
rc = gpgsm_agent_pksign (ctrl, hexgrip, desc,
|
rc = gpgsm_agent_pksign (ctrl, hexgrip, desc,
|
||||||
gcry_md_read(md, GCRY_MD_SHA1),
|
gcry_md_read(md, mdalgo),
|
||||||
gcry_md_get_algo_dlen (GCRY_MD_SHA1),
|
gcry_md_get_algo_dlen (mdalgo),
|
||||||
GCRY_MD_SHA1,
|
mdalgo,
|
||||||
&sigval, &siglen);
|
&sigval, &siglen);
|
||||||
xfree (desc);
|
xfree (desc);
|
||||||
}
|
}
|
||||||
@ -822,8 +1194,14 @@ create_request (ctrl_t ctrl,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ksba_certreq_set_sig_val (cr, sigval);
|
err = transform_sigval (sigval, siglen, mdalgo,
|
||||||
|
&newsigval, NULL);
|
||||||
xfree (sigval);
|
xfree (sigval);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
err = ksba_certreq_set_sig_val (cr, newsigval);
|
||||||
|
xfree (newsigval);
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("failed to store the sig_val: %s\n",
|
log_error ("failed to store the sig_val: %s\n",
|
||||||
@ -850,18 +1228,8 @@ int
|
|||||||
gpgsm_genkey (ctrl_t ctrl, estream_t in_stream, estream_t out_stream)
|
gpgsm_genkey (ctrl_t ctrl, estream_t in_stream, estream_t out_stream)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
Base64Context b64writer = NULL;
|
|
||||||
ksba_writer_t writer;
|
|
||||||
|
|
||||||
ctrl->pem_name = "CERTIFICATE REQUEST";
|
rc = read_parameters (ctrl, in_stream, out_stream);
|
||||||
rc = gpgsm_create_writer (&b64writer, ctrl, out_stream, &writer);
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
log_error ("can't create writer: %s\n", gpg_strerror (rc));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = read_parameters (ctrl, in_stream, writer);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("error creating certificate request: %s <%s>\n",
|
log_error ("error creating certificate request: %s <%s>\n",
|
||||||
@ -869,17 +1237,6 @@ gpgsm_genkey (ctrl_t ctrl, estream_t in_stream, estream_t out_stream)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = gpgsm_finish_writer (b64writer);
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
log_error ("write failed: %s\n", gpg_strerror (rc));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpgsm_status (ctrl, STATUS_KEY_CREATED, "P");
|
|
||||||
log_info ("certificate request created\n");
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
gpgsm_destroy_writer (b64writer);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -429,6 +429,10 @@ int gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
|
|||||||
|
|
||||||
/*-- misc.c --*/
|
/*-- misc.c --*/
|
||||||
void setup_pinentry_env (void);
|
void setup_pinentry_env (void);
|
||||||
|
gpg_error_t transform_sigval (const unsigned char *sigval, size_t sigvallen,
|
||||||
|
int mdalgo,
|
||||||
|
unsigned char **r_newsigval,
|
||||||
|
size_t *r_newsigvallen);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,6 +186,7 @@ static struct
|
|||||||
|
|
||||||
/* GnuPG extensions */
|
/* GnuPG extensions */
|
||||||
{ "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
|
{ "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
|
||||||
|
{ "1.3.6.1.4.1.11591.2.2.1", "standaloneCertificate" },
|
||||||
|
|
||||||
/* Extensions used by the Bundesnetzagentur. */
|
/* Extensions used by the Bundesnetzagentur. */
|
||||||
{ "1.3.6.1.4.1.8301.3.5", "validityModel" },
|
{ "1.3.6.1.4.1.8301.3.5", "validityModel" },
|
||||||
|
132
sm/misc.c
132
sm/misc.c
@ -1,5 +1,5 @@
|
|||||||
/* misc.c - Miscellaneous fucntions
|
/* misc.c - Miscellaneous fucntions
|
||||||
* Copyright (C) 2004, 2009 Free Software Foundation, Inc.
|
* Copyright (C) 2004, 2009, 2011 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -31,6 +31,9 @@
|
|||||||
#include "gpgsm.h"
|
#include "gpgsm.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "sysutils.h"
|
#include "sysutils.h"
|
||||||
|
#include "../common/tlv.h"
|
||||||
|
#include "../common/sexp-parse.h"
|
||||||
|
|
||||||
|
|
||||||
/* Setup the environment so that the pinentry is able to get all
|
/* Setup the environment so that the pinentry is able to get all
|
||||||
required information. This is used prior to an exec of the
|
required information. This is used prior to an exec of the
|
||||||
@ -86,3 +89,130 @@ setup_pinentry_env (void)
|
|||||||
|
|
||||||
#endif /*!HAVE_W32_SYSTEM*/
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Transform a sig-val style s-expression as returned by Libgcrypt to
|
||||||
|
one which includes an algorithm identifier encoding the public key
|
||||||
|
and the hash algorithm. The public key algorithm is taken directly
|
||||||
|
from SIGVAL and the hash algorithm is given by MDALGO. This is
|
||||||
|
required because X.509 merges the public key algorithm and the hash
|
||||||
|
algorithm into one OID but Libgcrypt is not aware of that. The
|
||||||
|
function ignores missing parameters so that it can also be used to
|
||||||
|
create an siginfo value as expected by ksba_certreq_set_siginfo.
|
||||||
|
To create a siginfo s-expression a public-key s-expression may be
|
||||||
|
used instead of a sig-val. We only support RSA for now. */
|
||||||
|
gpg_error_t
|
||||||
|
transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
|
||||||
|
unsigned char **r_newsigval, size_t *r_newsigvallen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
const unsigned char *buf, *tok;
|
||||||
|
size_t buflen, toklen;
|
||||||
|
int depth, last_depth1, last_depth2;
|
||||||
|
int is_pubkey = 0;
|
||||||
|
const unsigned char *rsa_s = NULL;
|
||||||
|
size_t rsa_s_len;
|
||||||
|
const char *oid;
|
||||||
|
gcry_sexp_t sexp;
|
||||||
|
|
||||||
|
*r_newsigval = NULL;
|
||||||
|
if (r_newsigvallen)
|
||||||
|
*r_newsigvallen = 0;
|
||||||
|
|
||||||
|
buf = sigval;
|
||||||
|
buflen = sigvallen;
|
||||||
|
depth = 0;
|
||||||
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
|
return err;
|
||||||
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
|
return err;
|
||||||
|
if (tok && toklen == 7 && !memcmp ("sig-val", tok, toklen))
|
||||||
|
;
|
||||||
|
else if (tok && toklen == 10 && !memcmp ("public-key", tok, toklen))
|
||||||
|
is_pubkey = 1;
|
||||||
|
else
|
||||||
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
||||||
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
|
return err;
|
||||||
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
|
return err;
|
||||||
|
if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen))
|
||||||
|
return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
||||||
|
|
||||||
|
last_depth1 = depth;
|
||||||
|
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
|
||||||
|
&& depth && depth >= last_depth1)
|
||||||
|
{
|
||||||
|
if (tok)
|
||||||
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
||||||
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
|
return err;
|
||||||
|
if (tok && toklen == 1)
|
||||||
|
{
|
||||||
|
const unsigned char **mpi;
|
||||||
|
size_t *mpi_len;
|
||||||
|
|
||||||
|
switch (*tok)
|
||||||
|
{
|
||||||
|
case 's': mpi = &rsa_s; mpi_len = &rsa_s_len; break;
|
||||||
|
default: mpi = NULL; mpi_len = NULL; break;
|
||||||
|
}
|
||||||
|
if (mpi && *mpi)
|
||||||
|
return gpg_error (GPG_ERR_DUP_VALUE);
|
||||||
|
|
||||||
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
|
return err;
|
||||||
|
if (tok && mpi)
|
||||||
|
{
|
||||||
|
*mpi = tok;
|
||||||
|
*mpi_len = toklen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip to the end of the list. */
|
||||||
|
last_depth2 = depth;
|
||||||
|
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
|
||||||
|
&& depth && depth >= last_depth2)
|
||||||
|
;
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Map the hash algorithm to an OID. */
|
||||||
|
switch (mdalgo)
|
||||||
|
{
|
||||||
|
case GCRY_MD_SHA1:
|
||||||
|
oid = "1.2.840.113549.1.1.5"; /* sha1WithRSAEncryption */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCRY_MD_SHA256:
|
||||||
|
oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCRY_MD_SHA384:
|
||||||
|
oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCRY_MD_SHA512:
|
||||||
|
oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return gpg_error (GPG_ERR_DIGEST_ALGO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsa_s && !is_pubkey)
|
||||||
|
err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(s%b)))",
|
||||||
|
oid, (int)rsa_s_len, rsa_s);
|
||||||
|
else
|
||||||
|
err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s))", oid);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
err = make_canon_sexp (sexp, r_newsigval, r_newsigvallen);
|
||||||
|
gcry_sexp_release (sexp);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user