{{tag>ssl certificates}} ====== Creating CA and signing server and client certs with openssl ====== Can be used for anything that requires SSL certs, including stunnel certs. For stunnel certs client cert should be concatenated to the CA server file (rootCA.crt below) on the stunnel server. Also see [[https://github.com/OpenVPN/easy-rsa|easy-rsa]] for a [[https://github.com/OpenVPN/easy-rsa/blob/master/README.quickstart.md|scripted way]] of doing below. ===== Configuring your CA ===== mkdir -p /tmp/myCA/ cd /tmp/myCA mkdir certs csr newcerts private On Ubuntu 18.04 example openssl.cnf is in /usr/lib/ssl/openssl.cnf. cp /usr/lib/ssl/openssl.cnf /tmp/myCA/ echo 00 > serial echo 00 > crlnumber touch index.txt index.txt.attr Change the dir parameter in openssl.cnf to /tmp/myCA (no trailing slash and use absolute path!). ===== Create the CA ===== Generate CA private key with or without passphrase ==== Create CA private key without passphrase ==== openssl genrsa -out rootCA.key 4096 ==== Create CA private key with passphrase ==== openssl genrsa -des3 -passout pass:qwerty -out private/rootCA.key 2048 ==== Remove passphrase if needed ==== openssl rsa -passin pass:qwerty -in private/rootCA.key -out private/rootCA.key ==== Create CA self-signed certificate ==== openssl req -config openssl.cnf -new -x509 -subj '/C=DE/L=City/O=MyORG/CN=somename' -days 3650 -key private/rootCA.key -out certs/rootCA.crt Or you can have openssl prompt you for the info with this command: openssl req -new -x509 -days 3650 -sha256 -key private/rootCA.key -out certs/rootCA.crt ===== Create a SSL Server certificate ===== ==== Create private key for the server without passphrase ==== openssl genrsa -out private/server.key 2048 ==== Create private key for the server with passphrase ==== openssl genrsa -des3 -passout pass:qwerty -out private/server.key 2048 ==== Remove passphrase ==== openssl rsa -passin pass:qwerty -in private/server.key -out private/server.key ==== Create CSR for the server. Change CN. ==== openssl req -config openssl.cnf -new -subj '/C=DE/L=City/O=MyORG/CN=someothername' -key private/server.key -out csr/server.csr Or interactively openssl req -new -sha256 -key private/server.key -out csr/server.csr ==== Create certificate for the server ==== openssl ca -batch -config openssl.cnf -days 3650 -in csr/server.csr -out certs/server.crt -keyfile private/rootCA.key -cert certs/rootCA.crt -policy policy_anything Alternatively with a custom provided config file openssl ca -config mycustom-config.conf -cert certs/rootCA.crt -keyfile private/rootCA.key -in csr/server.csr -out certs/server.crt Contents of //mycustom-config.conf//: [ ca ] default_ca = Practical-TLS_CA-config [ Practical-TLS_CA-config ] dir = RootCA/CA certs = $dir new_certs_dir = $dir database = $dir/index.txt serial = $dir/serial default_days = 365 default_crl_days = 30 default_md = sha256 preserve = no copy_extensions = copy policy = DN_attributes x509_extensions = certificate_extensions [ DN_attributes ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ certificate_extensions ] basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = serverAuth ===== Create a SSL Client certificate ===== To use the client certificate in Firefox you need to export it to the correct format like so openssl pkcs12 -export -in certs/client.crt -inkey private/client.key -out certs/client.p12 Then you can import it via Settings > Security > View certificates > Import. Also the server config needs to be added, e.g. for nginx server { ... ssl_verify_client on; ssl_client_certificate /etc/nginx/rootCA.crt; ... ==== Create private key for the client without passphrase ==== openssl genrsa -out private/client.key 2048 ==== Create private key for a client ==== openssl genrsa -des3 -passout pass:qwerty -out private/client.key 2048 ==== Remove passphrase ==== openssl rsa -passin pass:qwerty -in private/client.key -out private/client.key ==== Create CSR for the client. Change CN. ==== openssl req -config openssl.cnf -new -subj '/C=DE/L=City/O=MyORG/CN=thirdname' -key private/client.key -out csr/client.csr Or interactively openssl req -new -sha256 -key private/client.key -out csr/client.csr ==== Create client certificate. ==== openssl ca -batch -config openssl.cnf -days 3650 -in csr/client.csr -out certs/client.crt -keyfile private/rootCA.key -cert certs/rootCA.crt -policy policy_anything ===== Verfiy certs ===== openssl verify -CAfile certs/rootCA.crt certs/client.crt openssl verify -CAfile certs/rootCA.crt certs/server.crt To inspect the CSR you can run: openssl req -in client.csr -noout -text To inspect the certificate: openssl x509 -in client.crt -noout -text To inspect the key: openssl rsa -in client.key -noout -text ===== Additional extensions ===== If you need to add some x509 certificate extensions. like Subject Alternative Name (SAN) for additional domains you can provide a config file to the CSR similar to this: //mycsr.conf//: [ req ] distinguished_name = requested_distinguished_name req_extensions = requested_extensions [ requested_distinguished_name ] countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name (full name) localityName = Locality Name (eg, city) organizationName = Organization Name (eg, company) commonName = Common Name countryName_default = HR stateOrProvinceName_default = North Province localityName_default = The Town organizationName_default = Secret org [ requested_extensions ] subjectAltName = @list_of_alternative_names [ list_of_alternative_names ] DNS.1 = example.com DNS.2 = en.admin.example.com DNS.3 = fr.admin.example.com DNS.5 = es.admin.example.com DNS.6 = mywebsite.com DNS.7 = *.mywebsite.com DNS.8 = lol.com DNS.9 = *.lol.com Above configuration will prompt you for commonName, organizationName etc. If you want to avoid prompting use below configuration: [ req ] default_bits = 2048 default_keyfile = keyfile.pem distinguished_name = req_distinguished_name attributes = req_attributes prompt = no output_password = mypass [ req_distinguished_name ] C = GB ST = Test State or Province L = Test Locality O = Organization Name OU = Organizational Unit Name CN = Common Name emailAddress = test@email.address [ req_attributes ] Note that the **prompt=no**, different attribute names in **req_distinguished_name** and empty **req_attributes** part. You cannot define *_min, *_max and *_default when prompt is set to no. Defining Organization Name, Locality etc. will not work with Letsencrypt. O and OU are only used for organization validation certificates. Let’s Encrypt only offers domain validation and can’t make any assertion as to the person or company that owns/manages the domain. Then after generating the key openssl genrsa -out private/client.key 2048 create the CSR openssl req -new -sha256 -config mycsr.conf -key private/client.key -out csr/client.csr ====== Tested on ====== * Ubuntu 18.04, 20.04.04 * stunnel ====== See also ====== * [[wiki:openssl_commands|Openssl commands]] ====== References ====== * http://theheat.dk/blog/?p=1023 * [[https://community.letsencrypt.org/t/organization-o-and-organizational-unit-ou-in-field-issued-to/5236|Letsencrypt does not support O, OU etc. fields in certificates]] * https://github.com/openssl/openssl/issues/11287#issuecomment-811483183 * https://www.openssl.org/docs/man1.1.1/man1/req.html * https://groups.google.com/g/mailing.openssl.users/c/kdCLWzJ5w1I * https://www.ssltrust.com.au/help/setup-guides/client-certificate-authentication * https://pavelevstigneev.medium.com/setting-nginx-with-letsencrypt-and-client-ssl-certificates-3ae608bb0e66