mirror of
https://github.com/openssl/openssl.git
synced 2024-11-24 02:23:51 +08:00
Add copy_extensions option to 'ca' utility.
This commit is contained in:
parent
e890dcdb19
commit
791bd0cd2b
4
CHANGES
4
CHANGES
@ -3,6 +3,10 @@
|
||||
|
||||
Changes between 0.9.6 and 0.9.7 [xx XXX 2000]
|
||||
|
||||
*) Add a 'copy_extensions' option to the 'ca' utility. This copies
|
||||
extensions from a certificate request to the certificate.
|
||||
[Steve Henson]
|
||||
|
||||
*) Allow multiple 'certopt' and 'nameopt' options to be separated
|
||||
by commas. Add 'namopt' and 'certopt' options to the 'ca' config
|
||||
file: this allows the display of the certificate about to be
|
||||
|
56
apps/apps.c
56
apps/apps.c
@ -809,6 +809,62 @@ int set_name_ex(unsigned long *flags, const char *arg)
|
||||
return set_multi_opts(flags, arg, ex_tbl);
|
||||
}
|
||||
|
||||
int set_ext_copy(int *copy_type, const char *arg)
|
||||
{
|
||||
if (!strcasecmp(arg, "none"))
|
||||
*copy_type = EXT_COPY_NONE;
|
||||
else if (!strcasecmp(arg, "copy"))
|
||||
*copy_type = EXT_COPY_ADD;
|
||||
else if (!strcasecmp(arg, "copyall"))
|
||||
*copy_type = EXT_COPY_ALL;
|
||||
else
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int copy_extensions(X509 *x, X509_REQ *req, int copy_type)
|
||||
{
|
||||
STACK_OF(X509_EXTENSION) *exts = NULL;
|
||||
X509_EXTENSION *ext, *tmpext;
|
||||
ASN1_OBJECT *obj;
|
||||
int i, idx, ret = 0;
|
||||
if (!x || !req || (copy_type == EXT_COPY_NONE))
|
||||
return 1;
|
||||
exts = X509_REQ_get_extensions(req);
|
||||
|
||||
for(i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
|
||||
ext = sk_X509_EXTENSION_value(exts, i);
|
||||
obj = X509_EXTENSION_get_object(ext);
|
||||
idx = X509_get_ext_by_OBJ(x, obj, -1);
|
||||
/* Does extension exist? */
|
||||
if (idx != -1) {
|
||||
/* If normal copy don't override existing extension */
|
||||
if (copy_type == EXT_COPY_ADD)
|
||||
continue;
|
||||
/* Delete all extensions of same type */
|
||||
do {
|
||||
tmpext = X509_get_ext(x, idx);
|
||||
X509_delete_ext(x, idx);
|
||||
X509_EXTENSION_free(tmpext);
|
||||
idx = X509_get_ext_by_OBJ(x, obj, -1);
|
||||
} while (idx != -1);
|
||||
}
|
||||
if (!X509_add_ext(x, ext, -1))
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
|
||||
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int set_multi_opts(unsigned long *flags, const char *arg, const NAME_EX_TBL *in_tbl)
|
||||
{
|
||||
STACK_OF(CONF_VALUE) *vals;
|
||||
|
@ -153,6 +153,8 @@ void print_name(BIO *out, char *title, X509_NAME *nm, unsigned long lflags);
|
||||
#endif
|
||||
int set_cert_ex(unsigned long *flags, const char *arg);
|
||||
int set_name_ex(unsigned long *flags, const char *arg);
|
||||
int set_ext_copy(int *copy_type, const char *arg);
|
||||
int copy_extensions(X509 *x, X509_REQ *req, int copy_type);
|
||||
int app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2);
|
||||
int add_oid_section(BIO *err, LHASH *conf);
|
||||
X509 *load_cert(BIO *err, char *file, int format);
|
||||
@ -170,6 +172,10 @@ X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath);
|
||||
#define FORMAT_SMIME 6
|
||||
#define FORMAT_ENGINE 7
|
||||
|
||||
#define EXT_COPY_NONE 0
|
||||
#define EXT_COPY_ADD 1
|
||||
#define EXT_COPY_ALL 2
|
||||
|
||||
#define NETSCAPE_CERT_HDR "certificate"
|
||||
|
||||
#define APP_PASS_LEN 1024
|
||||
|
84
apps/ca.c
84
apps/ca.c
@ -134,6 +134,7 @@
|
||||
#define ENV_MSIE_HACK "msie_hack"
|
||||
#define ENV_NAMEOPT "name_opt"
|
||||
#define ENV_CERTOPT "cert_opt"
|
||||
#define ENV_EXTCOPY "copy_extensions"
|
||||
|
||||
#define ENV_DATABASE "database"
|
||||
|
||||
@ -303,7 +304,7 @@ int MAIN(int argc, char **argv)
|
||||
int notext=0;
|
||||
unsigned long nameopt = 0, certopt = 0;
|
||||
int default_op = 1;
|
||||
int ext_copy = 0;
|
||||
int ext_copy = EXT_COPY_NONE;
|
||||
X509 *x509=NULL;
|
||||
X509 *x=NULL;
|
||||
BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL;
|
||||
@ -798,6 +799,18 @@ bad:
|
||||
else
|
||||
ERR_clear_error();
|
||||
|
||||
f=CONF_get_string(conf,section,ENV_EXTCOPY);
|
||||
|
||||
if (f)
|
||||
{
|
||||
if (!set_ext_copy(&ext_copy, f))
|
||||
{
|
||||
BIO_printf(bio_err, "Invalid extension copy option: \"%s\"\n", f);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else
|
||||
ERR_clear_error();
|
||||
|
||||
/*****************************************************************/
|
||||
/* lookup where to write new certificates */
|
||||
@ -1944,40 +1957,6 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
|
||||
|
||||
if (default_op)
|
||||
old_entry_print(bio_err, obj, str);
|
||||
#if 0
|
||||
j=i2a_ASN1_OBJECT(bio_err,obj);
|
||||
pbuf=buf;
|
||||
for (j=22-j; j>0; j--)
|
||||
*(pbuf++)=' ';
|
||||
*(pbuf++)=':';
|
||||
*(pbuf++)='\0';
|
||||
BIO_puts(bio_err,buf);
|
||||
|
||||
if (str->type == V_ASN1_PRINTABLESTRING)
|
||||
BIO_printf(bio_err,"PRINTABLE:'");
|
||||
else if (str->type == V_ASN1_T61STRING)
|
||||
BIO_printf(bio_err,"T61STRING:'");
|
||||
else if (str->type == V_ASN1_IA5STRING)
|
||||
BIO_printf(bio_err,"IA5STRING:'");
|
||||
else if (str->type == V_ASN1_UNIVERSALSTRING)
|
||||
BIO_printf(bio_err,"UNIVERSALSTRING:'");
|
||||
else
|
||||
BIO_printf(bio_err,"ASN.1 %2d:'",str->type);
|
||||
|
||||
p=(char *)str->data;
|
||||
for (j=str->length; j>0; j--)
|
||||
{
|
||||
if ((*p >= ' ') && (*p <= '~'))
|
||||
BIO_printf(bio_err,"%c",*p);
|
||||
else if (*p & 0x80)
|
||||
BIO_printf(bio_err,"\\0x%02X",*p);
|
||||
else if ((unsigned char)*p == 0xf7)
|
||||
BIO_printf(bio_err,"^?");
|
||||
else BIO_printf(bio_err,"^%c",*p+'@');
|
||||
p++;
|
||||
}
|
||||
BIO_printf(bio_err,"'\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Ok, now we check the 'policy' stuff. */
|
||||
@ -2171,7 +2150,6 @@ again2:
|
||||
if (!X509_set_issuer_name(ret,X509_get_subject_name(x509)))
|
||||
goto err;
|
||||
|
||||
BIO_printf(bio_err,"Certificate is to be certified until ");
|
||||
if (strcmp(startdate,"today") == 0)
|
||||
X509_gmtime_adj(X509_get_notBefore(ret),0);
|
||||
else ASN1_UTCTIME_set_string(X509_get_notBefore(ret),startdate);
|
||||
@ -2180,10 +2158,6 @@ again2:
|
||||
X509_gmtime_adj(X509_get_notAfter(ret),(long)60*60*24*days);
|
||||
else ASN1_UTCTIME_set_string(X509_get_notAfter(ret),enddate);
|
||||
|
||||
ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ret));
|
||||
if (days) BIO_printf(bio_err," (%d days)",days);
|
||||
BIO_printf(bio_err, "\n");
|
||||
|
||||
if (!X509_set_subject_name(ret,subject)) goto err;
|
||||
|
||||
pktmp=X509_REQ_get_pubkey(req);
|
||||
@ -2251,16 +2225,32 @@ again2:
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy extensions from request (if any) */
|
||||
|
||||
if (!copy_extensions(ret, req, ext_copy))
|
||||
{
|
||||
BIO_printf(bio_err, "ERROR: adding extensions from request\n");
|
||||
ERR_print_errors(bio_err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
if (!default_op)
|
||||
{
|
||||
BIO_printf(bio_err, "Certificate Details:\n");
|
||||
/* Never print signature details because signature not present */
|
||||
certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME;
|
||||
X509_print_ex(bio_err, ret, nameopt, certopt);
|
||||
}
|
||||
|
||||
BIO_printf(bio_err,"Certificate is to be certified until ");
|
||||
ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ret));
|
||||
if (days) BIO_printf(bio_err," (%d days)",days);
|
||||
BIO_printf(bio_err, "\n");
|
||||
|
||||
if (!batch)
|
||||
{
|
||||
if (!default_op)
|
||||
{
|
||||
BIO_printf(bio_err, "Certificate Details:\n");
|
||||
/* Never print signature details because signature not present */
|
||||
certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME;
|
||||
X509_print_ex(bio_err, ret, nameopt, certopt);
|
||||
}
|
||||
|
||||
BIO_printf(bio_err,"Sign the certificate? [y/n]:");
|
||||
(void)BIO_flush(bio_err);
|
||||
buf[0]='\0';
|
||||
|
@ -53,6 +53,9 @@ x509_extensions = usr_cert # The extentions to add to the cert
|
||||
name_opt = ca_default # Subject Name options
|
||||
cert_opt = ca_default # Certificate field options
|
||||
|
||||
# Extension copying option: use with caution.
|
||||
# copy_extensions = copy
|
||||
|
||||
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
|
||||
# so this is commented out by default to leave a V1 CRL.
|
||||
# crl_extensions = crl_ext
|
||||
|
@ -334,6 +334,20 @@ OpenSSL is used. Use of the old format is B<strongly> discouraged because
|
||||
it only displays fields mentioned in the B<policy> section, mishandles
|
||||
multicharacter string types and does not display extensions.
|
||||
|
||||
=item B<copy_extensions>
|
||||
|
||||
determines how extensions in certificate requests should be handled.
|
||||
If set to B<none> or this option is not present then extensions are
|
||||
ignored and not copied to the certificate. If set to B<copy> then any
|
||||
extensions present in the request that are not already present are copied
|
||||
to the certificate. If set to B<copyall> then all extensions in the
|
||||
request are copied to the certificate: if the extension is already present
|
||||
in the certificate it is deleted first. See the B<WARNINGS> section before
|
||||
using this option.
|
||||
|
||||
The main use of this option is to allow a certificate request to supply
|
||||
values for certain extensions such as subjectAltName.
|
||||
|
||||
=back
|
||||
|
||||
=head1 POLICY FORMAT
|
||||
@ -426,6 +440,7 @@ A sample configuration file with the relevant sections for B<ca>:
|
||||
|
||||
nameopt = default_ca # Subject name display option
|
||||
certopt = default_ca # Certificate display option
|
||||
copy_extensions = none # Don't copy extensions from request
|
||||
|
||||
[ policy_any ]
|
||||
countryName = supplied
|
||||
@ -491,10 +506,6 @@ The use of an in memory text database can cause problems when large
|
||||
numbers of certificates are present because, as the name implies
|
||||
the database has to be kept in memory.
|
||||
|
||||
Certificate request extensions are ignored: some kind of "policy" should
|
||||
be included to use certain static extensions and certain extensions
|
||||
from the request.
|
||||
|
||||
It is not possible to certify two certificates with the same DN: this
|
||||
is a side effect of how the text database is indexed and it cannot easily
|
||||
be fixed without introducing other problems. Some S/MIME clients can use
|
||||
@ -513,6 +524,30 @@ The behaviour should be more friendly and configurable.
|
||||
Cancelling some commands by refusing to certify a certificate can
|
||||
create an empty file.
|
||||
|
||||
=head1 WARNINGS
|
||||
|
||||
The B<copy_extensions> option should be used with caution. If care is
|
||||
not taken then it can be a security risk. For example if a certificate
|
||||
request contains a basicConstraints extension with CA:TRUE and the
|
||||
B<copy_extensions> value is set to B<copyall> and the user does not spot
|
||||
this when the certificate is displayed then this will hand the requestor
|
||||
a valid CA certificate.
|
||||
|
||||
This situation can be avoided by setting B<copy_extensions> to B<copy>
|
||||
and including basicConstraints with CA:FALSE in the configuration file.
|
||||
Then if the request contains a basicConstraints extension it will be
|
||||
ignored.
|
||||
|
||||
It is advisable to also include values for other extensions such
|
||||
as B<keyUsage> to prevent a request supplying its own values.
|
||||
|
||||
Additional restrictions can be placed on the CA certificate itself.
|
||||
For example if the CA certificate has:
|
||||
|
||||
basicConstraints = CA:TRUE, pathlen:0
|
||||
|
||||
then even if a certificate is issued with CA:TRUE it will not be valid.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<req(1)|req(1)>, L<spkac(1)|spkac(1)>, L<x509(1)|x509(1)>, L<CA.pl(1)|CA.pl(1)>,
|
||||
|
Loading…
Reference in New Issue
Block a user