-.\" $OpenBSD: openssl.1,v 1.153 2023/12/29 12:06:48 tb Exp $
+.\" $OpenBSD: openssl.1,v 1.154 2024/01/12 11:24:03 job Exp $
.\" ====================================================================
.\" Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
.\"
.\" copied and put under another distribution licence
.\" [including the GNU Public Licence.]
.\"
-.Dd $Mdocdate: December 29 2023 $
+.Dd $Mdocdate: January 12 2024 $
.Dt OPENSSL 1
.Os
.Sh NAME
.Op Fl extensions Ar section
.Op Fl extfile Ar file
.Op Fl fingerprint
+.Op Fl force_pubkey Ar key
.Op Fl hash
.Op Fl in Ar file
.Op Fl inform Cm der | net | pem
.Op Fl keyform Cm der | pem
.Op Fl md5 | sha1
.Op Fl modulus
+.Op Fl multivalue-rdn
.Op Fl nameopt Ar option
.Op Fl next_serial
.Op Fl noout
.Op Fl purpose
.Op Fl req
.Op Fl serial
+.Op Fl set_issuer Ar name
.Op Fl set_serial Ar n
+.Op Fl set_subject Ar name
.Op Fl setalias Ar arg
.Op Fl signkey Ar file
.Op Fl sigopt Ar nm:v
.Op Fl subject_hash_old
.Op Fl text
.Op Fl trustout
+.Op Fl utf8
.Op Fl x509toreq
.Ek
.El
versions before 1.0.0.
.It Fl modulus
Print the value of the modulus of the public key contained in the certificate.
+.It Fl multivalue-rdn
+This option causes the
+.Fl subj
+argument to be interpreted with full support for multivalued RDNs,
+for example
+.Qq "/DC=org/DC=OpenSSL/DC=users/UID=123456+CN=John Doe" .
+If
+.Fl multivalue-rdn
+is not used, the UID value is set to
+.Qq "123456+CN=John Doe" .
.It Fl nameopt Ar option
Customise how the subject or issuer names are displayed,
either using a list of comma-separated options or by specifying
.It Fl extfile Ar file
File containing certificate extensions to use.
If not specified, no extensions are added to the certificate.
+.It Fl force_pubkey Ar key
+Set the public key of the certificate to the public key contained in
+.Ar key .
.It Fl keyform Cm der | pem
-The format of the private key file used in the
+The format of the key file used in the
+.Fl force_pubkey
+and
.Fl signkey
-option.
+options.
.It Fl req
Expect a certificate request on input instead of a certificate.
+.It Fl set_issuer Ar name
+The issuer name to use.
+.Ar name
+must be formatted as /type0=value0/type1=value1/type2=...;
+characters may be escaped by
+.Sq \e
+(backslash);
+no spaces are skipped.
.It Fl set_serial Ar n
The serial number to use.
This option can be used with either the
The serial number can be decimal or hex (if preceded by
.Sq 0x ) .
Negative serial numbers can also be specified but their use is not recommended.
+.It Fl set_subject Ar name
+The subject name to use.
+.Ar name
+must be formatted as /type0=value0/type1=value1/type2=...;
+characters may be escaped by
+.Sq \e
+(backslash);
+no spaces are skipped.
.It Fl signkey Ar file
Self-sign
.Ar file
If the input is a certificate request, a self-signed certificate
is created using the supplied private key using the subject name in
the request.
+.It Fl utf8
+Interpret field values read from a terminal or obtained from a configuration
+file as UTF-8 strings.
+By default, they are interpreted as ASCII.
.It Fl x509toreq
Convert a certificate into a certificate request.
The
-/* $OpenBSD: x509.c,v 1.35 2023/11/21 17:56:19 tb Exp $ */
+/* $OpenBSD: x509.c,v 1.36 2024/01/12 11:24:03 job Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
static int callb(int ok, X509_STORE_CTX *ctx);
static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext,
- const EVP_MD *digest, CONF *conf, char *section);
+ const EVP_MD *digest, CONF *conf, char *section, X509_NAME *issuer);
static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
X509 *x, X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts,
char *serial, int create, int days, int clrext, CONF *conf, char *section,
- ASN1_INTEGER *sno);
+ ASN1_INTEGER *sno, X509_NAME *issuer);
static int purpose_print(BIO *bio, X509 *cert, const X509_PURPOSE *pt);
static struct {
unsigned long certflag;
int checkend;
int checkoffset;
+ unsigned long chtype;
int clrext;
int clrreject;
int clrtrust;
char *extfile;
char *extsect;
int fingerprint;
+ char *force_pubkey;
char *infile;
int informat;
int issuer;
int keyformat;
const EVP_MD *md_alg;
int modulus;
+ int multirdn;
int next_serial;
unsigned long nmflag;
int noout;
STACK_OF(ASN1_OBJECT) *reject;
int reqfile;
int serial;
+ char *set_issuer;
+ char *set_subject;
int sign_flag;
STACK_OF(OPENSSL_STRING) *sigopts;
ASN1_INTEGER *sno;
return (0);
}
+static int
+x509_opt_utf8(void)
+{
+ cfg.chtype = MBSTRING_UTF8;
+ return (0);
+}
+
static const struct option x509_options[] = {
{
.name = "C",
.opt.order = &cfg.fingerprint,
.order = &cfg.num,
},
+ {
+ .name = "force_pubkey",
+ .argname = "key",
+ .desc = "Force the public key to be put in the certificate",
+ .type = OPTION_ARG,
+ .opt.arg = &cfg.force_pubkey,
+ },
{
.name = "hash",
.desc = "Synonym for -subject_hash",
.opt.order = &cfg.modulus,
.order = &cfg.num,
},
+ {
+ .name = "multivalue-rdn",
+ .desc = "Enable support for multivalued RDNs",
+ .type = OPTION_FLAG,
+ .opt.flag = &cfg.multirdn,
+ },
{
.name = "nameopt",
.argname = "option",
.opt.order = &cfg.serial,
.order = &cfg.num,
},
+ {
+ .name = "set_issuer",
+ .argname = "name",
+ .desc = "Set the issuer name",
+ .type = OPTION_ARG,
+ .opt.arg = &cfg.set_issuer,
+ },
{
.name = "set_serial",
.argname = "n",
.type = OPTION_ARG_FUNC,
.opt.argfunc = x509_opt_set_serial,
},
+ {
+ .name = "set_subject",
+ .argname = "name",
+ .desc = "Set the subject name",
+ .type = OPTION_ARG,
+ .opt.arg = &cfg.set_subject,
+ },
{
.name = "setalias",
.argname = "arg",
.opt.order = &cfg.startdate,
.order = &cfg.num,
},
+ {
+ .name = "subj",
+ .type = OPTION_ARG,
+ .opt.arg = &cfg.set_subject,
+ },
{
.name = "subject",
.desc = "Print subject name",
.type = OPTION_FLAG,
.opt.flag = &cfg.trustout,
},
+ {
+ .name = "utf8",
+ .desc = "Input characters are in UTF-8 (default ASCII)",
+ .type = OPTION_FUNC,
+ .opt.func = x509_opt_utf8,
+ },
{
.name = "x509toreq",
.desc = "Output a certification request object",
" [-CAkeyform der | pem] [-CAserial file] [-certopt option]\n"
" [-checkend arg] [-clrext] [-clrreject] [-clrtrust] [-dates]\n"
" [-days arg] [-email] [-enddate] [-extensions section]\n"
- " [-extfile file] [-fingerprint] [-hash] [-in file]\n"
- " [-inform der | net | pem] [-issuer] [-issuer_hash]\n"
- " [-issuer_hash_old] [-keyform der | pem] [-md5 | -sha1]\n"
- " [-modulus] [-nameopt option] [-next_serial] [-noout]\n"
- " [-ocsp_uri] [-ocspid] [-out file]\n"
- " [-outform der | net | pem] [-passin arg] [-pubkey]\n"
- " [-purpose] [-req] [-serial] [-set_serial n] [-setalias arg]\n"
- " [-signkey file] [-sigopt nm:v] [-startdate] [-subject]\n"
- " [-subject_hash] [-subject_hash_old] [-text] [-trustout]\n"
- " [-x509toreq]\n");
+ " [-extfile file] [-fingerprint] [-force_pubkey key] [-hash]\n"
+ " [-in file] [-inform der | net | pem] [-issuer]\n"
+ " [-issuer_hash] [-issuer_hash_old] [-keyform der | pem]\n"
+ " [-md5 | -sha1] [-modulus] [-multivalue-rdn]\n"
+ " [-nameopt option] [-next_serial] [-noout] [-ocsp_uri]\n"
+ " [-ocspid] [-out file] [-outform der | net | pem]\n"
+ " [-passin arg] [-pubkey] [-purpose] [-req] [-serial]\n"
+ " [-set_issuer name] [-set_serial n] [-set_subject name]\n"
+ " [-setalias arg] [-signkey file] [-sigopt nm:v] [-startdate]\n"
+ " [-subject] [-subject_hash] [-subject_hash_old] [-text]\n"
+ " [-trustout] [-utf8] [-x509toreq]\n");
fprintf(stderr, "\n");
options_usage(x509_options);
fprintf(stderr, "\n");
int ret = 1;
X509_REQ *req = NULL;
X509 *x = NULL, *xca = NULL;
- EVP_PKEY *Upkey = NULL, *CApkey = NULL;
+ X509_NAME *iname = NULL, *sname = NULL;
+ EVP_PKEY *Fpkey = NULL, *Upkey = NULL, *CApkey = NULL;
int i;
BIO *out = NULL;
BIO *STDout = NULL;
}
memset(&cfg, 0, sizeof(cfg));
+ cfg.chtype = MBSTRING_ASC;
cfg.days = DEF_DAYS;
cfg.informat = FORMAT_PEM;
cfg.outformat = FORMAT_PEM;
goto end;
}
}
+ if (cfg.force_pubkey != NULL) {
+ if ((Fpkey = load_pubkey(bio_err, cfg.force_pubkey,
+ cfg.keyformat, 0, NULL, "Forced key")) == NULL)
+ goto end;
+ }
if (cfg.reqfile) {
EVP_PKEY *pkey;
BIO *in;
} else if (!X509_set_serialNumber(x, cfg.sno))
goto end;
- if (!X509_set_issuer_name(x, X509_REQ_get_subject_name(req)))
+ if (cfg.set_issuer != NULL) {
+ iname = parse_name(cfg.set_issuer, cfg.chtype,
+ cfg.multirdn);
+ if (iname == NULL)
+ goto end;
+ }
+
+ if (cfg.set_subject != NULL)
+ sname = parse_name(cfg.set_subject, cfg.chtype,
+ cfg.multirdn);
+ else
+ sname = X509_NAME_dup(X509_REQ_get_subject_name(req));
+ if (sname == NULL)
goto end;
- if (!X509_set_subject_name(x, X509_REQ_get_subject_name(req)))
+ if (!X509_set_subject_name(x, sname))
goto end;
if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL)
NULL) == NULL)
goto end;
- if ((pkey = X509_REQ_get0_pubkey(req)) == NULL)
+ if ((pkey = Fpkey) == NULL)
+ pkey = X509_REQ_get0_pubkey(req);
+ if (pkey == NULL)
goto end;
if (!X509_set_pubkey(x, pkey))
goto end;
}
if (!sign(x, Upkey, cfg.days,
cfg.clrext, cfg.digest,
- extconf, cfg.extsect))
+ extconf, cfg.extsect, iname))
goto end;
} else if (cfg.CA_flag == i) {
BIO_printf(bio_err, "Getting CA Private Key\n");
if (!x509_certify(ctx, cfg.CAfile, cfg.digest,
x, xca, CApkey, cfg.sigopts, cfg.CAserial,
cfg.CA_createserial, cfg.days, cfg.clrext,
- extconf, cfg.extsect, cfg.sno))
+ extconf, cfg.extsect, cfg.sno, iname))
goto end;
} else if (cfg.x509req == i) {
EVP_PKEY *pk;
NCONF_free(extconf);
BIO_free_all(out);
BIO_free_all(STDout);
+ X509_NAME_free(iname);
+ X509_NAME_free(sname);
X509_STORE_free(ctx);
X509_REQ_free(req);
X509_free(x);
X509_free(xca);
+ EVP_PKEY_free(Fpkey);
EVP_PKEY_free(Upkey);
EVP_PKEY_free(CApkey);
sk_OPENSSL_STRING_free(cfg.sigopts);
x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, X509 *x,
X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts,
char *serialfile, int create, int days, int clrext, CONF *conf,
- char *section, ASN1_INTEGER *sno)
+ char *section, ASN1_INTEGER *sno, X509_NAME *issuer)
{
int ret = 0;
ASN1_INTEGER *bs = NULL;
"CA certificate and CA private key do not match\n");
goto end;
}
- if (!X509_set_issuer_name(x, X509_get_subject_name(xca)))
+
+ if (issuer == NULL)
+ issuer = X509_get_subject_name(xca);
+ if (issuer == NULL)
+ goto end;
+ if (!X509_set_issuer_name(x, issuer))
goto end;
+
if (!X509_set_serialNumber(x, bs))
goto end;
/* self sign */
static int
sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest,
- CONF *conf, char *section)
+ CONF *conf, char *section, X509_NAME *issuer)
{
EVP_PKEY *pktmp;
EVP_PKEY_copy_parameters(pktmp, pkey);
EVP_PKEY_save_parameters(pktmp, 1);
- if (!X509_set_issuer_name(x, X509_get_subject_name(x)))
+ if (issuer == NULL)
+ issuer = X509_get_subject_name(x);
+ if (issuer == NULL)
+ goto err;
+ if (!X509_set_issuer_name(x, issuer))
goto err;
if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL)
goto err;