Creating a CA

Creating a Certificate Authority is easy. There are many scripts out there to do it for you. However, creating a CA that is easy to manage can be tricky. This should walk you through creating a CA and explain all the pieces.

Note: This page takes an extra step to make a fairly PKIX-compliant Certificate Authority. In pariticular, it ensures that the email address associated with your CA is in the SubjectAltName extension rather than in the DN. The former is the PKIX and X509v3 standard way of presenting an email address while the later is the old X509v1 way.

Initial Preperation

  1. Create the directory your CA will live in
    mkdir CA
  2. Create the various pieces
    mkdir CA/{certsdb,certreqs,crl,private}
    Here's what each of those directories do:
    certsdb
    This is where signed certs will be stored
    certreqs
    This is where copies of the original CSRs will be stored
    crl
    This is where your CRL will be stored
    private
    This is where the private key for the CA will live

  3. Protect your private directory
    chmod 700 CA/private
  4. Create the flat-file DB for your certificates
    touch CA/index.txt

    This is where a list of all signed certs will go. Openssl will use this to keep track of what's happened.

Configuration

  1. You'll want to make a configuration file for the CA separate from the system openssl configuration file. So move into the CA directory, and make a copy:
    cd CA
    cp /etc/openssl.cnf .

    Your system openssl.cnf may be in some place other than /etc/openssl.cnf. If it's not there, try /usr/lib/ssl/openssl.cnf or /usr/share/ssl/openssl.cnf. If all else fails, run locate openssl.cnf.

  2. We need to make some changes to the openssl.cnf. Start with the base config in openssl.cnf page.

  3. Now, in order to make sure the CA itself has the email in SubjectAltName instead of the Subject (for PKIX compliance), ensure that your [ v3_req ] section has subjectAltName = email:move. If you'd prefer the old v1-style way of email in the Subject, simply remove this line.

  4. Next, unfortunately since openssl doesn't always handle things nicely, we need to make a copy of both the v3_ca and usr_cert sections. Then to the original's, we'll add the line SubjectAltName = email:move. Again, this is necessary for a PKIX compliant CA. Skip this step if you prefer the old way. This will look like:
    ####################################################################
    # Extensions for when we sign normal certs (specified as default)
    [ usr_cert ]
    basicConstraints = CA:false
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid,issuer
    subjectAltName = email:move
    
    ####################################################################
    # Same as above, but cert req already has SubjectAltName
    [ usr_cert_has_san ]
    basicConstraints = CA:false
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid,issuer
    
    ####################################################################
    # Extensions to use when signing a CA
    [ v3_ca ]
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always,issuer:always
    basicConstraints = CA:true
    subjectAltName=email:move
    
    ####################################################################
    # Same as above, but CA req already has SubjectAltName
    [ v3_ca_has_san ]
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always,issuer:always
    basicConstraints = CA:true
    

    The reason we have to do this is that if you have subjectAltName = email:move set when signing a certificate that doesn't have an email in the subject (i.e. is already PKIX compliant), openssl will 'move' the email from the subject (since it's not there, that's null) to the SubjectAltName extension thus deleting the original. Remember, you use a section with the -extensions arguement.

    All of these options are explained in openssl.cnf page.

  5. Decide on a CRL distribution method. In order to revoke certificates, you need to make a CRL publically available. This is usually done via a web server. For this example, we'll say you're going to put your CRL at http://www.example.com/example_ca.crl. Then you'll need to add this information to all 4 extension sections: the v3_ca, v3_ca_has_san, usr_cert, and usr_cert_has_san sections. To do that, add a line to each section as follows:

    crlDistributionPoints = URI:http://www.example.com/example_ca.crl

    Again, be sure to put this all 4 extension sections.

Create The CA

  1. Create the keypair (private key and CSR)
    openssl req -new -newkey rsa:2048 -keyout private/cakey.pem -out careq.pem -config ./openssl.cnf

    Here -new denotes a new keypair, -newkey rsa:2048 specifies the size and type of your private key: RSA 2048-bit, -keyout dictates where they new private key will go, -out determines where the request will go, and -config tells openssl to use our config rather than the default config.

    Note that as of January 1, 2011, Microsoft will remove all CAs with keys of size 1024-bit or smaller from their browsers and OSes. You should be using 2048 or bigger anyway, but if you interact with Microsoft systems, you'll definitely have to ensure you set your keysize to 2048. The default for openssl is 1024, so be sure to specify it manually as we did above. Thanks to Chet Burgess for the pointer.

  2. Self-sign the CSR to make your CA CRT
    openssl ca -create_serial -out cacert.pem -days 365 -keyfile private/cakey.pem -selfsign -extensions v3_ca_has_san -config ./openssl.cnf -infiles careq.pem

    Note the choice of v3_ca_has_san here. If you prefer the old-style, simply use v3_ca here instead.

    -create_serial is especially important. Many HOW-TOs will have you echo "01" into the serial file thus starting the serial number at 1, and using 8-bit serial numbers instead of 128-bit serial numbers. This will generate a random 128-bit serial number to start with. The randomness helps to ensure that if you make a mistake and start over, you won't overwrite existing serial numbers out there.
    -out determines where the self-signed certificate will go.
    -days determines how long the certificate will be valid for.
    -keyfile specifies the private key to use for signing (this was created in the last step).
    -selfsign tells openssl to use the data from the CSR when signing instead of expecting a CA CRT.
    -extensions tells openssl to use the v3_root_ca section of the config we added above to determine what extensions to use.
    -config again specifies our config.
    -infiles specifies what to sign, which in this case is the CSR for our new CA.

Note that while you can use req to create a self-signed certificate all in one step, req does not support the '-create_serial' option, and does not leave the intermediate CSR for you (though you can generate later), and thus is not the best option.

You now have a functional Certificate Authority. See Managing your CA for information on signing certificates, creating CRLs, and other management tasks. If you need to change an existing CA, see Modifying your CA.