OPENSSL-CA(1SSL)

🌸 openssl-ca β€” it's giving Certificate Authority πŸ’…

(that's the openssl-ca page from the OpenSSL manual, bestie β€” section 1SSL, okurr?)


✨ NAME ✨

openssl-ca β€” a sample minimal CA application πŸŽ€ (yes, a whole Certificate Authority, she's small but she's mighty)


πŸ¦‹ SYNOPSIS πŸ¦‹

openssl ca [-help] [-verbose] [-quiet] [-config filename] [-name
section] [-section section] [-gencrl] [-revoke file] [-valid file]
[-status serial] [-updatedb] [-crl_reason reason] [-crl_hold
instruction] [-crl_compromise time] [-crl_CA_compromise time]
[-crl_lastupdate date] [-crl_nextupdate date] [-crldays days] [-crlhours
hours] [-crlsec seconds] [-crlexts section] [-startdate date]
[-not_before date] [-enddate date] [-not_after date] [-days arg] [-md
arg] [-policy arg] [-keyfile filename|uri] [-keyform DER|PEM|P12] [-key
arg] [-passin arg] [-cert file] [-certform DER|PEM|P12] [-selfsign] [-in
file] [-inform DER|<PEM>] [-out file] [-notext] [-dateopt] [-outdir dir]
[-infiles] [-spkac file] [-ss_cert file] [-preserveDN] [-noemailDN]
[-batch] [-extfile file] [-extensions section] [-subj arg] [-utf8]
[-sigopt nm:v] [-vfyopt nm:v] [-create_serial] [-rand_serial]
[-multivalue-rdn] [-rand files] [-writerand file] [-provider name]
[-provider-path path] [-provparam [name:]key=value] [-propquery propq]
[certreq...]

πŸ’– DESCRIPTION πŸ’–

Okay so listen. This command emulates a CA application β€” like, it pretends to be your Certificate Authority, does the whole signing-girl routine. 🫢 But lowkey read the WARNINGS section, fr fr, especially if you're thinking about using it in production. No cap, that part matters. πŸ’€

It spits out certificates that bear X.509 version 3 energy. And unless you say otherwise, key identifier extensions get included, exactly as described over in x509v3_config(5). πŸ‘‘

Bestie it can do so much:

  • It can sign certificate requests (CSRs) in a variety of forms, slay πŸ’…
  • It can generate certificate revocation lists (CRLs) 🌈
  • It also keeps a text database of the certificates it issued and what their status is β€” like a little receipts folder, iconic

When it comes to signing certificates, you got two vibes:

  1. Sign a single request β€” just pass it with the -in option, one and done ✨
  2. Sign a bunch of requests β€” drop a whole set of certreq files at the end, after all the options, and she'll process them all 🌸
✨ Little aside, bestie: there are also very lean ways of generating certificates. The req and x509 commands can create certificates directly, no CA drama required. Peep openssl-req(1) and openssl-x509(1) for the deets. πŸ’œ

And heads up β€” the descriptions of all the ca command options are grouped by what they're for, not just dumped in one big list. So organized of her. πŸŽ€

πŸ’– OPTIONS πŸ’–

okay bestie, buckle up, this is the big one. every single flag, no skips, no cap 🫢

  • -help β€” prints a usage message. that's it, that's the whole vibe. helpful when you're lost. πŸ™ˆ
  • -verbose β€” gives you the extra deets about what's going on. more tea, more info. ✨
  • -quiet β€” the opposite energy: fewer details about the operations. lowkey perfect for batch scripts or pipelines where you do NOT want the yapping. πŸ’…
  • -config filename β€” tells it which configuration file to use. it's optional! so if you skip it, the default is described in "COMMAND SUMMARY" in openssl(1). iykyk.
  • -name section, -section section β€” picks which configuration file section to use. this one overrides default_ca in the ca section. slay.
  • -in filename β€” an input file holding a single certificate request (CSR) that the CA is gonna sign. one (1) CSR. πŸŽ€
  • -inform DER|PEM β€” the format to use when loading CSR input files. by default PEM is tried first. full details live in openssl-format-options(1). πŸ¦‹
  • -ss_cert filename β€” a single self-signed certificate for the CA to sign. iconic.
  • -spkac filename β€” a file with a single Netscape signed public key and challenge, plus additional field values, all to be signed by the CA. peep the SPKAC FORMAT section for the required input and output format. ⭐
  • -infiles β€” if you use this, it has to be the last option. everything after it is treated as names of files containing certificate requests. no take-backs, periodt.
  • -out filename β€” where the certificates get output. default is standard output. the certificate details also get printed out to this file in PEM format (except that -spkac outputs DER format). πŸ’œ
  • -outdir directory β€” the directory to output certs to. each cert gets written to a filename made of the serial number in hex with .pem appended. cute and organised. 🌸
  • -cert filename β€” the CA certificate. it must match with -keyfile. they're a package deal, bestie. πŸ’ž
  • -certform DER|PEM|P12 β€” the format of the data in certificate input files. unspecified by default. details in openssl-format-options(1).
  • -keyfile filename|uri β€” the CA private key used to sign certificate requests. this must match with -cert. again: package deal. πŸ”
  • -keyform DER|PEM|P12 β€” the format of the private key input file. unspecified by default. yep, openssl-format-options(1) again.
  • *-sigopt *nm:v β€” passes options to the signature algorithm during sign operations. the names and values are algorithm-specific and documented in "Signature parameters" in provider-signature(7). 🧚
  • *-vfyopt *nm:v β€” passes options to the signature algorithm during verify operations. names and values are algorithm-specific. 🌈

this often needs to be given while signing too, because the self-signature of a certificate signing request (CSR) is verified against the included public key, and that verification may need its own set of options. multi-tasking queen. πŸ‘‘

  • -key password β€” the password used to encrypt the private key. ⚠️ since on some systems the command line arguments are visible (like when using ps(1) on Unix), use this option with caution. better to use -passin instead. do NOT be reckless with this one bestie, i'm serious. 🚨
  • -passin arg β€” the key password source for key files and certificate PKCS#12 files. format of arg is in openssl-passphrase-options(1). way safer vibe. πŸ’–
  • -selfsign β€” says the issued certificates should be signed with the key the certificate requests were signed with (the one given with -keyfile). certificate requests signed with a different key get ignored. and if -spkac, -ss_cert or -gencrl are given, -selfsign is ignored. 😭

a consequence of using -selfsign is that the self-signed certificate shows up among the entries in the certificate database (see the config option database), and it uses the same serial number counter as all other certificates signed with the self-signed certificate. keep that in mind.

  • -notext β€” don't output the text form of a certificate to the output file. no yapping in text form. πŸ™ˆ
  • -dateopt β€” specifies the date output format. values are: rfc_822 and iso_8601. defaults to rfc_822. ⏰
  • -startdate date, -not_before date β€” lets you explicitly set the start date. the format is YYMMDDHHMMSSZ (same as an ASN1 UTCTime structure), or YYYYMMDDHHMMSSZ (same as an ASN1 GeneralizedTime structure). in both formats, seconds SS and timezone Z must be present. alternatively you can also use "today". πŸ—“οΈ
  • -enddate date, -not_after date β€” lets you explicitly set the expiry date. same formats: YYMMDDHHMMSSZ (ASN1 UTCTime) or YYYYMMDDHHMMSSZ (ASN1 GeneralizedTime), and again, seconds SS and timezone Z must be present. alternatively "today" works too. ✨

heads up: this overrides the -days option. πŸ’…

  • -days arg β€” how many days from today the certificate is certified for.

regardless of the option -not_before, the days are always counted from today. and when used together with -not_after/-startdate, the explicit expiry date takes precedence. so yeah, explicit wins. πŸ‘‘

  • -md alg β€” the message digest to use. any digest supported by the openssl-dgst(1) command works. for signing algorithms that don't support a digest (i.e. Ed25519 and Ed448) any message digest that's set is ignored. this option also applies to CRLs. 🧚
  • -policy arg β€” defines the CA "policy" to use. it's a section in the configuration file that decides which fields should be mandatory or match the CA certificate. check the POLICY FORMAT section for more. πŸ“‹
  • -preserveDN β€” normally the DN order of a certificate matches the order of the fields in the relevant policy section. when this is set, the order matches the request instead. it's largely for compatibility with the older IE enrollment control, which would only accept certificates if their DNs matched the order of the request. not needed for Xenroll. vintage tech behaviour fr. πŸ’€
  • -noemailDN β€” the DN of a certificate can contain the EMAIL field if it's present in the request DN, but honestly good policy is just having the e-mail set into the altName extension of the certificate. when this option is set, the EMAIL field is removed from the certificate's subject and set only in the, eventually present, extensions. the email_in_dn keyword in the config file can enable this behaviour. πŸ“§
  • -batch β€” sets batch mode. in this mode no questions will be asked and all certificates will be certified automatically. hands-off, main character energy. πŸ€–
  • -extensions section β€” the config file section containing certificate extensions to add when a certificate is issued. defaults to x509_extensions unless the -extfile option is used. the x509v3_config(5) manual page has the details on the extension section format. πŸŽ€
  • -extfile file β€” an additional configuration file to read certificate extensions from. it uses its unnamed ("default") section unless the -extensions option is also used. πŸ“‚
  • -subj arg β€” supersedes the subject name given in the request.

the arg must be formatted as "/type0=value0/type1=value1/type2=...". special characters may be escaped by "\" (backslash), and whitespace is retained. empty values are permitted, but the corresponding type will not be included in the resulting certificate. giving a single "/" leads to an empty sequence of RDNs (a NULL-DN). multi-valued RDNs can be formed by placing a "+" character instead of a "/" between the AttributeValueAssertions (AVAs) that specify the members of the set. example:

"/DC=org/DC=OpenSSL/DC=users/UID=123456+CN=John Doe"

look at that formatting, we love to see it. πŸ’…

  • -utf8 β€” makes field values be interpreted as UTF8 strings. by default they're interpreted as ASCII. this means the field values β€” whether prompted from a terminal or obtained from a configuration file β€” must be valid UTF8 strings. 🌸
  • -create_serial β€” if reading a serial from the text file as specified in the configuration fails, this option creates a new random serial to use as the next serial number. but bestie, to get random serial numbers, use the -rand_serial flag instead β€” -create_serial should only be used for simple error-recovery. πŸ™
  • -rand_serial β€” generates a large random number to use as the serial number. this overrides any option or configuration to use a serial number file. no cap, totally random. 🎲
  • -multivalue-rdn β€” this option has been deprecated and has no effect. it's giving ghost of options past. πŸ‘»
  • -rand files, -writerand file β€” see "Random State Options" in openssl(1) for the details. 🎲
  • -provider name β€” -provider-path path β€” -provparam [name:]key=value β€” -propquery propq β€” see "Provider Options" in openssl(1), provider(7), and property(7). πŸ“š

πŸ’… CRL OPTIONS πŸ’…

Bestie, this is the certificate revocation list zone β€” aka the receipts section, where certificates go when they've done something shady. Here's every knob you can twist ✨

  • -gencrl β€” makes a whole new CRL out of whatever's sitting in the index file. That's it, that's the job πŸ’–
  • -crl_lastupdate time β€” lets you hand-set the CRL's lastUpdate field yourself instead of letting the universe decide. If you don't pass it, the current time gets used automatically. It takes times in YYMMDDHHMMSSZ format (same shape as an ASN1 UTCTime structure) or YYYYMMDDHHMMSSZ format (same shape as an ASN1 GeneralizedTime structure) πŸ•°οΈ
  • -crl_nextupdate time β€” hand-sets the nextUpdate field. Heads up though: if you use this, any values you gave for -crldays, -crlhours and -crlsec just get ignored entirely, no cap. Takes the same time formats as -crl_lastupdate ✨
  • -crldays num β€” how many days from now until the next CRL is due. That's the number dropped into the CRL's nextUpdate field πŸ“…
  • -crlhours num β€” how many hours from now until the next CRL is due ⏰
  • -crlsec num β€” how many seconds from now until the next CRL is due ⏱️
  • -revoke filename β€” points at a file holding the certificate you want to revoke. Sorry babes, it's giving consequences 🚫
  • -valid filename β€” points at a file holding a certificate you want to add as a Valid certificate entry βœ…
  • -status serial β€” shows you the revocation status of the certificate with that exact serial number, then exits immediately πŸ•΅οΈβ€β™€οΈ
  • -updatedb β€” refreshes the database index and purges out all the expired certificates. Decluttering, but for your CA 🧹✨
  • -crl_reason reason β€” sets the revocation reason, where reason is one of: unspecified, keyCompromise, CACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold or removeFromCRL. Matching the reason is case insensitive (so go off, capitalize how you feel). Setting any revocation reason at all makes the CRL v2 πŸ”₯
fr fr: in practice removeFromCRL isn't particularly useful, because it's only used in delta CRLs β€” and delta CRLs are not currently implemented. So like… it's there, but it's not there 😭
  • -crl_hold instruction β€” sets the CRL revocation reason code to certificateHold and the hold instruction to instruction, which has to be an OID. Technically any OID can be used, but normally you'd only reach for holdInstructionNone (whose use is deprecated in RFC 5280), holdInstructionCallIssuer or holdInstructionReject πŸ’…
  • -crl_compromise time β€” sets the revocation reason to keyCompromise and the compromise time to time. And time should be in GeneralizedTime format, i.e. YYYYMMDDHHMMSSZ ⏳
  • -crl_CA_compromise time β€” literally the same as crl_compromise, except the revocation reason gets set to CACompromise instead πŸ‘‘
  • -crlexts section β€” the section of the config file that holds the CRL extensions you want included. If there's no CRL extension section present, you get a V1 CRL. If the CRL extension section is present β€” even if it's totally empty β€” you get a V2 CRL. Note that the extensions being specified here are CRL extensions, not CRL entry extensions, okay bestie, don't get it twisted πŸ’– Also, some software (for example, Netscape πŸ‘€) can't handle V2 CRLs at all. Check the x509v3_config(5) manual page for the deets on the extension section format πŸ“š

πŸŽ€ CONFIGURATION FILE OPTIONS πŸŽ€

So how does this command even find your options in the config file? The way it works is like this: if you used the -name command line option, then that names the section to be used. Otherwise, the section that gets used must be named in the default_ca option of the ca section of the configuration file (or in the default section of the configuration file) πŸ—‚οΈ

And besides default_ca, the following options get read directly from the ca section:

  • RANDFILE
  • preserve
  • msie_hack
Okay so with the exception of RANDFILE, this is probably a bug and may change in future releases. We're just being honest with you πŸ™ˆ

A whole bunch of the config file options are straight-up identical to command line options. And when an option exists in both the config file and the command line? The command line value wins, every time πŸ’… And if an option is described as mandatory, then it must be present in the config file β€” or you use the command line equivalent (if there is one).

  • oid_file β€” names a file containing additional OBJECT IDENTIFIERS. Each line of that file should be: the numerical form of the object identifier, then whitespace, then the short name, then whitespace, and finally the long name ✨
  • oid_section β€” names a section in the config file containing extra object identifiers. Each line should be the short name of the object identifier, followed by =, followed by the numerical form. When you use this option, the short and long names are literally the same 🀝
  • new_certs_dir β€” same thing as the -outdir command line option. It says where new certificates get placed. Mandatory πŸ“
  • certificate β€” same as -cert. Gives you the file containing the CA certificate. Mandatory πŸ“œ
  • private_key β€” same as the -keyfile option. The file containing the CA private key. Mandatory (and like… keep it secret bestie) πŸ”
  • RANDFILE β€” at startup, this specified file gets loaded into the random number generator, and at exit 256 bytes will be written to it. (Note: using a RANDFILE is not necessary anymore, see the "HISTORY" section πŸ¦‹)
  • default_days β€” same as the -days option. The number of days from today to certify a certificate for πŸ“†
  • default_startdate β€” same as the -startdate option. The start date to certify a certificate for. If you don't set it, the current time is used πŸ•
  • default_enddate β€” same as the -enddate option. Either this option or default_days (or the command line equivalents) must be present. Pick one, you gotta πŸ“Œ
  • default_crl_hours, default_crl_days β€” same as the -crlhours and the -crldays options. These only get used if neither command line option is present. And at least one of them must be present to generate a CRL πŸ—“οΈ
  • default_md β€” same as the -md option. Mandatory β€” except where the signing algorithm doesn't require a digest, i.e. Ed25519 and Ed448 πŸ”
  • database β€” the text database file to use. Mandatory. This file has to be present, even though initially it'll just be empty πŸ—ƒοΈ
  • unique_subject β€” if the value yes is given, the valid certificate entries in the database must have unique subjects. If the value no is given, several valid certificate entries may have the exact same subject. The default value is yes, to stay compatible with older (pre 0.9.8) versions of OpenSSL. However, to make CA certificate roll-over easier, it's recommended to use the value no β€” especially if you combine it with the -selfsign command line option 🌈

Note that it's valid in some circumstances for certificates to be created without any subject at all. And in the case where there are multiple certificates without subjects, that doesn't count as a duplicate πŸ’«

  • serial β€” a text file containing the next serial number to use, in hex. Mandatory. This file must be present and contain a valid serial number πŸ”’
  • crlnumber β€” a text file containing the next CRL number to use, in hex. The CRL number only gets inserted into the CRLs if this file exists. And if this file is present, it must contain a valid CRL number πŸ”–
  • x509_extensions β€” a fallback to the -extensions option πŸͺ‚
  • crl_extensions β€” a fallback to the -crlexts option πŸͺ‚
  • preserve β€” the same as -preserveDN πŸ’–
  • email_in_dn β€” the same as -noemailDN. If you want the EMAIL field removed from the DN of the certificate, simply set this to 'no'. If it's not present, the default is to allow the EMAIL field in the certificate's DN πŸ“§
  • msie_hack β€” the same as -msie_hack πŸͺ„
  • policy β€” the same as -policy. Mandatory. Peep the POLICY FORMAT section for more info πŸ“‹
  • name_opt, cert_opt β€” these options let you control the format used to display the certificate details when the user is being asked to confirm signing. Every option supported by the x509 utility's -nameopt and -certopt switches can be used here β€” except that no_signame and no_sigdump are permanently set and can't be disabled. (This is because the certificate signature can't be displayed at this point, since the certificate hasn't been signed yet. Awkward πŸ˜…)

For convenience, the value ca_default is accepted by both of them, and produces a reasonable output πŸ‘‘

If neither option is present, the format used in earlier versions of OpenSSL is used. And use of the old format is strongly discouraged, because it only displays fields mentioned in the policy section, mishandles multicharacter string types, and doesn't display extensions at all. It's giving ancient πŸ’€

  • copy_extensions β€” decides how extensions in certificate requests should be handled. If it's set to none, or the option isn't present at all, then extensions are ignored and not copied to the certificate. If set to copy, then any extensions present in the request that aren't already present get copied over to the certificate. If set to copyall, then all extensions in the request get copied to the certificate β€” and if the extension is already present in the certificate, it gets deleted first. Check the WARNINGS section before using this option!!

The main use of this option is to let a certificate request supply values for certain extensions, such as subjectAltName ✨


πŸ“‹ POLICY FORMAT πŸ“‹

The policy section is a set of variables corresponding to certificate DN fields, and every one of them comes with a vibe check:

  • if the value is "match" β€” then the field value must match the same field in the CA certificate 🀝
  • if the value is "supplied" β€” then it must be present βœ…
  • if the value is "optional" β€” then it may be present πŸ€·β€β™€οΈ

And here's the sneaky part: any fields not mentioned in the policy section get silently deleted β€” unless the -preserveDN option is set. But honestly, that can be regarded more as a quirk than intended behaviour πŸ™ˆ


πŸ¦‹ SPKAC FORMAT πŸ¦‹

The input to the -spkac command line option is a Netscape signed public key and challenge. Usually this comes from the KEYGEN tag in an HTML form, to create a new private key. It is, however, possible to create SPKACs using openssl-spkac(1) ✨

The file should contain the variable SPKAC set to the value of the SPKAC, plus the required DN components as name value pairs. And if you need to include the same component twice, it can be preceded by a number and a . πŸ’…

When processing SPKAC format, the output is DER if the -out flag is used β€” but PEM format if sending to stdout or if the -outdir flag is used πŸ“€

🌸 EXAMPLES 🌸

Okay bestie, real talk before we dive in: these examples are assuming that the whole directory structure this command wants is already set up, and that all the relevant files already exist. None of that happens magically ✨ β€” you (or past-you) gotta handle it. Usually that means making a CA certificate + private key with openssl-req(1), plus a serial number file, plus an empty index file, and then tucking all of them into the right directories. Iconic setup ritual, honestly.

So if you're rolling with the sample config file down below, you'd create demoCA, demoCA/private and demoCA/newcerts. Your CA certificate gets copied to demoCA/cacert.pem and its private key goes to demoCA/private/cakey.pem. Then you'd make a file called demoCA/serial with something like "01" inside it, and the empty index file demoCA/index.txt. That's the whole vibe check. πŸ’…


Sign a certificate request:

 openssl ca -in req.pem -out newcert.pem

Sign a certificate request, but with CA extensions:

 openssl ca -in req.pem -extensions v3_ca -out newcert.pem

Generate a CRL:

 openssl ca -gencrl -out crl.pem

Sign several requests at once:

 openssl ca -infiles req1.pem req2.pem req3.pem

Certify a Netscape SPKAC:

 openssl ca -spkac spkac.txt

A sample SPKAC file β€” heads up, the SPKAC line has been truncated for clarity, so don't come for me about it looking short 🫢:

 SPKAC=MIG0MGAwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PDhCeV/xIxUg8V70YRxK2A5
 CN=Steve Test
 emailAddress=steve@openssl.org
 0.OU=OpenSSL Group
 1.OU=Another Group

And here's a sample configuration file with the sections that actually matter for this command, periodt:

 [ ca ]
 default_ca      = CA_default            # The default ca section

 [ CA_default ]

 dir            = ./demoCA              # top dir
 database       = $dir/index.txt        # index file.
 new_certs_dir  = $dir/newcerts         # new certs dir

 certificate    = $dir/cacert.pem       # The CA cert
 serial         = $dir/serial           # serial no file
 #rand_serial    = yes                  # for random serial#'s
 private_key    = $dir/private/cakey.pem# CA private key

 default_days   = 365                   # how long to certify for
 default_crl_days= 30                   # how long before next CRL
 default_md     = sha256                # md to use

 policy         = policy_any            # default policy
 email_in_dn    = no                    # Don't add the email into cert DN

 name_opt       = ca_default            # Subject name display option
 cert_opt       = ca_default            # Certificate display option
 copy_extensions = none                 # Don't copy extensions from request

 [ policy_any ]
 countryName            = supplied
 stateOrProvinceName    = optional
 organizationName       = optional
 organizationalUnitName = optional
 commonName             = supplied
 emailAddress           = optional

πŸ“ FILES πŸ“

Quick note before the list, bestie: every single one of these locations can move. Like, all of them. Where they live can change because of compile time options, configuration file entries, environment variables, or command line options. The values written below are just the defaults, no cap. πŸ‘‘

 /usr/local/ssl/lib/openssl.cnf - master configuration file
 ./demoCA                       - main CA directory
 ./demoCA/cacert.pem            - CA certificate
 ./demoCA/private/cakey.pem     - CA private key
 ./demoCA/serial                - CA serial number file
 ./demoCA/serial.old            - CA serial number backup file
 ./demoCA/index.txt             - CA text database file
 ./demoCA/index.txt.old         - CA text database backup file
 ./demoCA/certs                 - certificate output file

🚫 RESTRICTIONS 🚫

Bestie, listen. The text database index file is a critical part of this whole process, and if it gets corrupted it can be genuinely difficult to fix. Like, the way that it's theoretically possible to rebuild the index file from all the issued certificates and a current CRL… but there is no option to do this. So. Yeah. Be careful. 😭

V2 CRL features β€” looking at you, delta CRLs β€” are not currently supported. Not yet, anyway.

And even though you can throw several requests at it and have them handled all at once, you can only include one SPKAC or self-signed certificate. That's the limit. Sorry bestie. πŸ’€


πŸ’€ BUGS πŸ’€

Okay so, saying it plainly: this command is quirky and at times downright unfriendly. That's the manpage's words and honestly? Fair.

Using an in-memory text database can cause problems once you've got large numbers of certificates hanging around, because β€” as the name implies β€” the database has to be kept in memory. πŸ™ˆ

This command really needs rewriting, or at least the required functionality exposed at either a command or interface level so a more user-friendly replacement could handle things properly. The script CA.pl helps a little, but ngl not very much.

Any fields in a request that aren't present in a policy get silently deleted. Poof. Gone. This does not happen if you use the -preserveDN option. And to enforce the absence of the EMAIL field within the DN β€” as suggested by RFCs β€” no matter what's in the request's subject, you can use the -noemailDN option. The behaviour should be more friendly and configurable, fr fr.

Also: canceling some commands by refusing to certify a certificate can create an empty file. Random but true. 🌸


⚠️ WARNINGS ⚠️

This is the part where we get serious for a sec. Pay attention, bestie. 🫢

This command was originally meant as an example of how to do things in a CA. Its code does not have production quality. It was not supposed to be used as a full blown CA itself β€” and yet, some people are using it for exactly that purpose, at least internally. If that's you: take specific care to properly secure the private key(s) used for signing certificates. It's advisable to keep them in a secure HW storage, like a smart card or an HSM, and access them via a suitable crypto provider. Protect the key. Always. πŸ”

This command is effectively a single user command: no locking is done on the various files, and attempts to run more than one openssl ca command on the same database can have unpredictable results. Don't do it. Just don't.

The copy_extensions option should be used with caution. If care isn't taken, it can be a security risk. For example: if a certificate request contains a basicConstraints extension with CA:TRUE, and the copy_extensions value is set to copyall, and the user doesn't spot this when the certificate is displayed β€” then this will hand the requester a valid CA certificate. Yeah. Not cute. 😭 This situation can be avoided by setting copy_extensions to copy and including basicConstraints with CA:FALSE in the configuration file. Then, if the request contains a basicConstraints extension, it'll just be ignored. Slay.

It's also advisable to include values for other extensions such as keyUsage, to prevent a request from supplying its own values. Don't let the requests write their own rules. πŸ’…

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. The parent said no. ✨


πŸ“œ HISTORY πŸ“œ

Since OpenSSL 1.1.1, this program follows RFC5280. Specifically, certificate validity period (specified by any of -startdate, -enddate and -days) and CRL last/next update time (specified by any of -crl_lastupdate, -crl_nextupdate, -crldays, -crlhours and -crlsec) will be encoded as UTCTime if the dates are earlier than year 2049 (included), and as GeneralizedTime if the dates are in year 2050 or later. Time formats said "let me pick based on the era." πŸ•°οΈ

OpenSSL 1.1.1 introduced a new random generator (CSPRNG) with an improved seeding mechanism. The new seeding mechanism makes it unnecessary to define a RANDFILE for saving and restoring randomness. That option is retained mainly for compatibility reasons. Lowkey obsolete, highkey still here. πŸ¦‹

The -section option was added in OpenSSL 3.0.0.

The -multivalue-rdn option has become obsolete in OpenSSL 3.0.0 and has no effect. It's giving ghost. πŸ‘»

Since OpenSSL 3.2, generated certificates bear X.509 version 3, and key identifier extensions are included by default.

The -engine option was removed in OpenSSL 4.0.

The -msie-hack option was removed in OpenSSL 4.0.

As of OpenSSL 4.0, the ca utility no longer has specialised built-in logic to add the SKID or AKID extensions β€” they're handled through configuration files and command-line options just like any other extension. Equality. Periodt. 🌈


πŸ‘€ SEE ALSO πŸ‘€


Copyright 2000-2026 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


And that's the whole page, bestie!! πŸŽ€ This was OpenSSL 4.0.3, dated 2026-09-29, filed under OPENSSL-CA(1SSL). Go forth and sign responsibly β€” keep your keys safe, keep your index file uncorrupted, and never ever run two of these on the same database at once. Mwah πŸ’…βœ¨πŸ«Ά

πŸ“¦ where this page comes from