Use Private Certificate Authority to Sign Certificate Signing Request on Linux

I’ll assume that you created a private CA using my tutorial. I also make the following assumptions before proceeding with the tutorial.

  • OpenSSL has been installed
  • CA private key is in /home/cg/myca/private/
  • CA root certificate is in /home/cg/myca/certs/
  • CA’s config file, caconfig.cnf, is in /home/cg/myca/conf/
  • serial is in /home/cg/myca/
  • index.txt is in /home/cg/myca/

Copy CSR

You should copy/download the CSR to /home/cg/myca/csr/ directory.

Sign CSR

Then run the following command to sign it.

openssl x509 -days 3650 -CA certs/crt.ca.cg.pem -CAkey private/key.ca.cg.pem -req -in csr/csr.server1.pem -outform PEM -out certs/crt.server1.pem -CAserial serial

You’ll be asked to provide the passphrase for the CA root certificate key. The final file, crt.server1.pem, is to be sent to the person who initiated the CSR. This is the final certificate they’ll use.

Generate Certificate Signing Request on Linux

You create a CSR and have it signed by a CA before you can use a certificate. This tutorial is a continuation from my tutorial on creating a CA. However, you do not need to create a CA to generate a CSR.

Install Prerequisites

I wrote this tutorial using Fedora 18. The only prerequisite I needed was OpenSSL.

su -c 'yum install openssl'

Create Directory Structure

mkdir /home/cg/mycert

cd /home/cg/mycert/

mkdir private conf csr

We will run all commands by default in the /home/cg/mycert directory, unless stated otherwise.

Config File

vim /home/cg/mycert/conf/serverconfig.cnf

This file would serve as the config file if you wish to use it. An example file is below.

[ ca ]
default_ca = CA_default

[ CA_default ]
dir = /home/cg/mycert/
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/certs/cacert.pem
serial = $dir/serial
#crl = $dir/crl.pem
private_key = $dir/private/cakey.pem
#RANDFILE = $dir/private/.rand
x509_extensions = usr_cert
#crl_extensions = crl_ext
default_days = 3650
#default_startdate = YYMMDDHHMMSSZ
#default_enddate = YYMMDDHHMMSSZ
#default_crl_days= 30
#default_crl_hours = 24
default_md = sha1
preserve = no
#msie_hack
policy = policy_match

[ policy_match ]
countryName = match
stateOrProvinceName = match
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ req ]
default_bits = 4096 # Size of keys
default_keyfile = key.pem # name of generated keys
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
#input_password
#output_password
string_mask = nombstr # permitted characters
req_extensions = v3_req

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = US
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = New York
localityName = Locality Name (city, district)
localityName_default = New York
organizationName = Organization Name (company)
organizationName_default = Code Ghar
organizationalUnitName = Organizational Unit Name (department, division)
organizationalUnitName_default = IT
commonName = Common Name (hostname, FQDN, IP, or your name)
commonName_max = 64
commonName_default = CGIT
emailAddress = Email Address
emailAddress_max = 40
emailAddress_default = codeghar@example.com

[ req_attributes ]
#challengePassword = A challenege password
#challengePassword_min = 4
#challengePassword_max = 20
#unstructuredName = An optional company name

[ usr_cert ]
basicConstraints= CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
#nsComment = ''OpenSSL Generated Certificate''
#nsCertType = client, email, objsign for ''everything including object signing''
subjectAltName=email:copy
issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl = 
#nsRenewalUrl =
#nsCaPolicyUrl = 
#nsSslServerName =

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:TRUE
#keyUsage = cRLSign, keyCertSign
#nsCertType = sslCA, emailCA
#subjectAltName=email:copy
#issuerAltName=issuer:copy
#obj=DER:02:03

[ crl_ext ]
#issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always

Generate CSR

You can use the config file (serverconfig.cnf) we created in the previous step to answer a lot of the questions asked during certificate generation. Just run the following command and answer the questions. Most questions will have the default values provided in serverconfig.cnf.

openssl req -new -config conf/serverconfig.cnf -keyform PEM -keyout private/key.csr.server1.pem -outform PEM -out csr/csr.server1.pem -nodes

If you want to provide your own custom values you may run the following command instead.

openssl req -new -newkey rsa:4096 -keyform PEM -keyout private/key.csr.server1.pem -outform PEM -out csr/csr.server1.pem -nodes

You will be asked relevant questions. Following is an example output of the process.

Generating a 4096 bit RSA private key
..............................................................................++
.................++
writing new private key to 'private/key.csr.server1.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:
State or Province Name (full name) [New York]:
Locality Name (city, district) [New York]:
Organization Name (company) [Code Ghar]:
Organizational Unit Name (department, division) [IT]:
Common Name (hostname, FQDN, IP, or your name) [CGIT]:
Email Address [codeghar@example.com]:server1@example.com

Two files, key.csr.server1.pem and csr.server1.pem, will be created in $dir/private and $dir/csr directories respectively. Keep these files in a safe location and back them up.

You will submit csr.server1.pem to the CA who will sign it. The CA will sign the file and return the resulting file to you. That will be the certificate you will finally use.

Create Private Certificate Authority on Linux

This tutorial will show you how to create your own private CA or Certificate Authority. This will give you the opportunity to sign your own certificates without having to pay someone else. However, since your private CA will not be trusted by others it may prompt warnings when others use it. You will need to add your root certificate to the machines you want to trust your CA.

I had written a similar article in 2008 (Create a Certificate Authority and Certificates with OpenSSL) but this tutorial supersedes the instructions for creating CA in the older one.

Install Prerequisites

I wrote this tutorial using Fedora 18. The only prerequisite I needed was OpenSSL.

su -c 'yum install openssl'

Create Directory Structure

mkdir /home/cg/myca

cd /home/cg/myca/

mkdir private certs newcerts conf export csr

echo '01' > serial

touch index.txt

We will run all commands by default in the /home/cg/myca directory, unless stated otherwise.

Config File

vim /home/cg/myca/conf/caconfig.cnf

This file would serve as the default config file for the CA. It should look something like the following:

[ ca ]
default_ca = CA_default

[ CA_default ]
dir = /home/cg/myca/
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/certs/cacert.pem
serial = $dir/serial
#crl = $dir/crl.pem
private_key = $dir/private/cakey.pem
#RANDFILE = $dir/private/.rand
x509_extensions = usr_cert
#crl_extensions = crl_ext
default_days = 3650
#default_startdate = YYMMDDHHMMSSZ
#default_enddate = YYMMDDHHMMSSZ
#default_crl_days= 30
#default_crl_hours = 24
default_md = sha1
preserve = no
#msie_hack
policy = policy_match

[ policy_match ]
countryName = match
stateOrProvinceName = match
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ req ]
default_bits = 4096 # Size of keys
default_keyfile = key.pem # name of generated keys
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
#input_password
#output_password
string_mask = nombstr # permitted characters
req_extensions = v3_req

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = US
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = New York
localityName = Locality Name (city, district)
localityName_default = New York
organizationName = Organization Name (company)
organizationName_default = Code Ghar
organizationalUnitName = Organizational Unit Name (department, division)
organizationalUnitName_default = IT
commonName = Common Name (hostname, FQDN, IP, or your name)
commonName_max = 64
commonName_default = CGIT
emailAddress = Email Address
emailAddress_max = 40
emailAddress_default = codeghar@example.com

[ req_attributes ]
#challengePassword = A challenege password
#challengePassword_min = 4
#challengePassword_max = 20
#unstructuredName = An optional company name

[ usr_cert ]
basicConstraints= CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
#nsComment = ''OpenSSL Generated Certificate''
#nsCertType = client, email, objsign for ''everything including object signing''
subjectAltName=email:copy
issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl = 
#nsRenewalUrl =
#nsCaPolicyUrl = 
#nsSslServerName =

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:TRUE
#keyUsage = cRLSign, keyCertSign
#nsCertType = sslCA, emailCA
#subjectAltName=email:copy
#issuerAltName=issuer:copy
#obj=DER:02:03

[ crl_ext ]
#issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always

Thanks to http://wwwneu.secit.at/web/documentation/openssl/openssl_cnf.html for helping with this file.

Generate Root Certificate

You can use the config file (caconfig.cnf) we created in the previous step to answer a lot of the questions asked during certificate generation. Just run the following command and answer the questions. Most questions will have the default values provided in caconfig.cnf.

openssl req -new -x509 -days 3650 -config conf/caconfig.cnf -keyform PEM -keyout private/key.ca.cg.pem -outform PEM -out certs/crt.ca.cg.pem

Although we specified the default number of days in caconfig.cnf file, we still have to specify the days flag when using the x509 flag. If we don’t the certificate is created with a default value of 30 days. Thanks to Re: default_days problem and OpenSSL req(1).

If you want to provide your own custom values you may run the following command instead.

openssl req -new -x509 -days 3650 -newkey rsa:4096 -extensions v3_ca -keyform PEM -keyout private/key.ca.cg.pem -outform PEM -out certs/crt.ca.cg.pem

You will be asked for a passphrase. Make sure you use a secure passphrase and don’t forget it. You will also be asked other relevant questions. Following is an example output of the process.

Generating a 4096 bit RSA private key
..............................................................................++
...........................................................................................................................................................................................................................................++
writing new private key to 'private/key.ca.cg.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:
State or Province Name (full name) [New York]:
Locality Name (city, district) [New York]:
Organization Name (company) [Code Ghar]:
Organizational Unit Name (department, division) [IT]:
Common Name (hostname, FQDN, IP, or your name) [CGIT]:
Email Address [codeghar@example.com]:

Two files, key.ca.cg.pem and crt.ca.cg.pem, will be created in $dir/private and $dir/certs directories respectively. Make sure you keep these files in a secure place and make their backups.

crt.ca.cg.pem is your root certificate and will be used to sign all the other certificates.

Verify Root Certificate

You should verify that the certificate was created properly with accurate information.

openssl x509 -in certs/crt.ca.cg.pem -inform pem -noout -text

Export Root Certificate

Since this newly created CA and its root certificate are not recognized and trusted by any computer, you need to import the root certificate on all other computers. By default an OS will have a list of trusted CAs and you need to import your CA to that list. The process varies for different OSes.

Windows

The root certificate we created is in PEM encoded format. For Windows we need it to be in DER encoded format. A great resource on the differences between the two is DER vs. CRT vs. CER vs. PEM Certificates and How To Convert Them.

openssl x509 -in certs/crt.ca.cg.pem -outform der -out export/ca.cg.crt

Verify the certificate was created successfully.

openssl x509 -in export/ca.cg.crt -inform der -noout -text

Once you have the exported file, copy it to your Windows machine. You can follow the instructions provided by How To Import a Trusted Root Certification Authority In Windows to import the certificate to the Trusted Root Certification Authorities store on Local Computer.

You can also export the certificate to PKCS12 format. Thanks to Importing a User Certificate to the Windows Certificate Store for this information.

openssl pkcs12 -export -out export/ca.cg.p12 -in certs/crt.ca.cg.pem -inkey private/key.ca.cg.pem

You will be asked to provide the passphrase you used to create the root certificate. You will also be asked for a new “Export Password”.

Copy the .p12 file to Windows and double-click it. A wizard will open and guide you to install it.

Conclusion

The process to create a CA is very simple. Next I will write about signing a certificate request.

Further Reading

Linux Ecosystem is Less About Technology More About Ideas

I was watching The Real Story Behind Wayland and X, a talk by Daniel Stone. The way he described the X server, we had been using a terrible piece of technology for years (still are). Linux had an inferior product doing critical things for the user. There were developers trying to fix its issues but were hindered by many other issues. A fresh start was needed and Wayland it was. It could even have been Mir.

My epiphany was that it’s not about a particular piece of technology. Its design or implementation could be highly undesirable but it keeps doing something useful-ish. The Linux ecosystem encourages you to fix the issues in existing technology or start from scratch. In the long run the Linux ecosystem is all about getting to a perfect OS from a technological standpoint. The users and developers should be prepared to throw everything out. That’s what innovation is all about. Of course, you’ll lose a few features here and there but that might not always be a bad thing. There’s more work to do when building something new and it takes longer to complete it. But at the end of the day, after all the pain and suffering, something beautiful and useful does emerge.

Letting go of X was a simple decision. These decisions may not always be as simple in other situations. But we should support those who want to improve things for everyone.

Create Network PXE Boot Server with Fedora 18

Special thanks to Manually configure a PXE server, from Fedora’s documentation, for providing very useful information. You should consider that documentation as much more authoritative than this post. I have tried to focus on setting up infrastructure for multiple distros, BIOS, and IPv4. I’ll update with IPv6 and EFI as I test that.

Disclaimer: Although I have tested this post it may still be incomplete or may contain errors.

Installing an OS over the network is a big time saver, especially when combined with autoconfig options such as Kickstart, Pressed, and AutoYaST. The first step in doing so is create the infrastructure that allows a computer or server to boot from the network and install the OS. These instructions were created using Fedora 18. Install it in a VM and you are good to go. Make sure it uses static IPv4 and IPv6 addresses and is accessible via SSH.

The network boot server used for these instructions was named noosa. Whenever noosa is mentioned in these instructions understand that it refers to the boot server. Let’s say noosa has an IPv4 address of 192.168.1.15 and IPv6 address of 2100:192:168:1::15. Create a user called idopxe on the server, used later in the instructions.

You’ll need a DHCP server running on this server. This could cause conflicts on your network if you’re already running a DHCP server. But if your current DHCP server supports the extra options mentioned in these instructions then you can continue to use it. Otherwise you may have to replace your current DHCP server with the one running on noosa.

Major steps in the process are:

  • Install and Configure TFTP Server
  • Create PXE Directory Structure
  • Copy OS ISOs to Boot Server
  • Extract Files from OS ISO
  • Configure PXE
  • Install and Configure HTTP Server
  • Install and Configure DHCP Server

Install and Configure TFTP Server

su -c 'yum install tftp-server'

Enable the service by editing the file /etc/xinetd.d/tftp and change

disable = yes

to

disable = no

Start the TFTP server. You’re starting xinetd because TFTP server is a xinetd-based service.

su -c 'systemctl start xinetd.service'

su -c 'systemctl enable xinetd.service'

You can now place files in /var/lib/tftpboot/ to be served by TFTP.

Create PXE Directory Structure

cd /var/lib/tftpboot/

su -c 'mkdir loopdir'

su -c 'mkdir linux'

su -c 'mkdir linux/fedora'

su -c 'mkdir linux/fedora/18'

su -c 'mkdir linux/fedora/18/x86_64'

su -c 'mkdir linux/fedora/18/x86_64/dvd'

su -c 'mkdir linux/fedora/18/x86_64/dvd/iso'

su -c 'mkdir linux/fedora/18/x86_64/dvd/files'

su -c 'mkdir linux/fedora/18/x86_64/dvd/kickstart'

Copy/download/upload Fedora 18 64-bit DVD ISO to /var/lib/tftpboot/linux/fedora/18/x86_64/dvd/iso/ directory.

Extract Files from OS ISO

su -c 'mount -o loop /var/lib/tftpboot/linux/fedora/18/x86_64/dvd/iso/Fedora-18-x86_64-DVD.iso /var/lib/tftpboot/loopdir'

rsync -v -a -H --exclude=TRANS.TBL /var/lib/tftpboot/loopdir/ /var/lib/tftpboot/linux/fedora/18/x86_64/dvd/files/

su -c 'umount /var/lib/tftpboot/loopdir'

Configure PXE

cd /var/lib/tftpboot/

su -c 'vim defaultbootmenu.txt'

Make sure it has the following contents:



== BOOT MENU ==

localdisk
fedora_18_dvd_64_bios_default
fedora_18_dvd_64_efi_default
fedora_18_dvd_64_bios_kickstart
fedora_18_dvd_64_efi_kickstart


Create a new directory:

su -c 'mkdir pxelinux.cfg'

cd pxelinux.cfg

su -c 'vim default'

DISPLAY defaultbootmenu.txt

DEFAULT localdisk

LABEL localdisk
    localboot 0x80

LABEL fedora_18_dvd_64_bios_default
    kernel linux/fedora/18/x86_64/dvd/files/isolinux/vmlinuz
    append initrd=linux/fedora/18/x86_64/dvd/files/isolinux/initrd.img repo=http://192.168.1.15/repo/linux/fedora/18/x86_64/dvd/files/

LABEL fedora_18_dvd_64_bios_kickstart
    kernel linux/fedora/18/x86_64/dvd/files/isolinux/vmlinuz
    append initrd=linux/fedora/18/x86_64/dvd/files/isolinux/initrd.img ks=http://192.168.1.15/repo/linux/fedora/18/x86_64/dvd/kickstart/anaconda-ks.cfg

implicit        1
prompt          1
timeout         300


You’ll need to install the SYSLINUX package.

su -c 'yum install syslinux'

Copy pxelinux.0 file from SYSLINUX to tftpboot directory.

cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/

Install and Configure HTTP Server

su -c 'yum install httpd'

su -c 'systemctl start httpd.service'

su -c 'systemctl enable httpd.service'

Remember to open ports in the firewall.

cd /var/www/html

su -c 'mkdir repo'

cd repo

su -c 'ln -s /var/lib/tftpboot/linux/ linux'

You’ll have to fix some SELinux permissions to allow httpd to be able to follow this symlink. The easiest way, if you aren’t familiar with SELinux, is to set it in permissive mode.

su -c 'setenforce 0'

Install and Configure DHCP Server

su -c 'yum install dhcp'

Edit a config file to specify on which interface to allow DHCP services to run.

su -c 'vim /etc/sysconfig/dhcpd'

Just change the value for INTERFACES in this file. In our example we want to run DHCP on eth0. So the file should have the following contents.

DHCPDARGS="eth0";

If you want to run it on multiple interfaces, for example eth0 and eth1, then it should read

DHCPDARGS="eth0 eth1";

Now edit the dhcpd.conf file.

su -c 'vim /etc/dhcp/dhcpd.conf'

ddns-update-style none;
option domain-name "codeghar.com";
option domain-name-servers 192.168.1.200, 192.168.1.201;
default-lease-time 600;
max-lease-time 7200;
log-facility local7;
class "linux-server" {
    match if substring(hardware, 1,6) = 00:11:22:33:44:55;
}
subnet 192.168.1.0 netmask 255.255.255.0 {
    pool {
        range 192.168.1.91 192.168.1.100;
        filename "pxelinux.0";
        next-server 192.168.1.15;
        option subnet-mask 255.255.255.0;
        option broadcast-address 192.168.1.255;
        option routers 192.168.1.1;
        allow members of "linux-server";
    }
}

In this configuration we give a default domain name, name servers, and other information. pxelinux.0 is the default file that other servers will use to boot when using PXE boot. next-server has the IP address of the TFTP server. In our case it’s noosa. You can use the class to match MAC addresses of certain servers only, thus not giving out dynamic IPs to other servers on your network. If your existing DHCP server can provide these options then you don’t need to run the DHCP server on noosa and instead need to pass this configuration to servers doing a PXE boot.

su -c 'systemctl start dhcpd.service'

su -c 'systemctl enable dhcpd.service'

Boot from network

Now when you boot from your target machine and choose network boot, it will get a DHCP IP and present a menu of options (defined in defaultbootmenu file). Just pick whatever is appropriate and off you go.

The New Anaconda Installer in Fedora 18

If you have tried to install Fedora 18 you’ll have seen the new Anaconda installer. Many have found major issues with its design and function. I also had some trouble with it. To learn more about it, you can watch a demo presented at FUDCon 2013: An intro to the new Fedora 18 installer (YouTube). One thing that caught my attention was that until you click “Begin Installation” no actual changes are made. Instead, as you go through the installer, steps before you click “Begin Installation” are written to a Kickstart file. This Kickstart file does the actual installation when you click “Begin Installation”.

This gives power users or those with complicated environments a big workaround to the graphical installer. You can create your own Kickstart file and just use that to complete your installation. Use the Kickstart wiki page to learn more about writing your own Kickstarts. I am playing around with a bit and it’s surprisingly easy. I’m thinking of following up with a post on how to use a Kickstart file while installing from a Fedora DVD. I’ll also try to setup a GitHub repo with various Kickstart files I create and test.

In any case, whether the graphical installer is awesome or not, having the skill to create your own Kickstart files gives you more freedom. It makes for a repeatable installation with minimal or no manual intervention. A win-win if you ask me.

Don’t be Afraid of Software Bugs

Bugs are a part of software. Nothing can be perfect and software is no different. Humans can’t write software bug-free. In this situation we should accept the existence of bugs and learn to live with them. Although we should prepare for them as well.

One thing that keeps adding new bugs is adding new features. This can be handled by adding the least possible number of new features in a release, test them as much as possible, and then release. This follows the principle of release early release often. As you add more features, you make more releases. Don’t make too many changes in one release if you can help it.

Another way to catch as many bugs as possible is to test as much as possible before releasing. Add testing to each level of your development process. Include code reviews, unit tests, and test automation, among other strategies.

Finally, prepare a mitigation process or workflow to correct bugs as they are reported and to distribute fixes as soon as possible. With minimal changes in each release you have a greater chance of finding the cause of and solution to reported bugs.

When a consumer of your application has confidence that (a) each release has minimal new features, (b) each release has been tested properly, (c) you have a solid plan how to conquer bugs when they are discovered, then the consumer is not afraid of bugs. Consumers are then able to plan and upgrade to latest releases without worrying that bugs will mean extensive downtime.

Given this plan of action developers should also not be afraid of bugs. They are a part of life and will happen no matter how diligent you are. But keep your due diligence at its highest level so that the consumers of your software trust it.

Follow

Get every new post delivered to your Inbox.

Join 30 other followers