viernes, 10 de febrero de 2012

Generación de certificados PKCS12 con OpenSSL

Va a hacer ahora un año que hice por última vez algún desarrollo en el que tuviera que utilizar certificados y firmas digitales. Recordándolo, siempre tuve la sensación de que había demasiada poca información disponible de cómo tratar con ellos en distintas plataformas, y siempre información muy atomizada y para casos concretos, nunca una guía extensa sobre las diferentes opciones para el desarrollo.

Voy a ver si durante una serie de posts consigo resumir algo de la información que aprendí entonces.

El formato de certificados de cliente más extendido es el PKCS12, básicamente porque es el que se utiliza en windows, que sigue siendo el sistema operativo de cliente más extendido. La forma de mover estos certificados suele ser mediante un fichero que tiene extensión pfx y está protegido por contraseña. Esta contraseña básicamente lo que hace es cifrar el contenido del fichero para que, si alguien nos lo roba, no pueda acceder a nuestro certificado.

Normalmente estos certificados de cliente los podemos obtener de entidades reconocidas, que nos los emiten para que podamos acreditar que somos quien decimos ser. Ahora bien, para el desarrollo de aplicaciones necesitamos tener certificados de prueba, que no necesariamente tienen que estar emitidos por una entidad de confianza, sino por nosotros mismos.

Para generar nuestros propios certificados disponemos de varias herramientas, pero voy a centrarme en una que está disponible tanto para Linux como para Windows, pero que en los sistemas Linux suele venir además instalada por defecto: OpenSSL.

Si vamos a generar muchos certificados y simular el comportamiento real de la aplicación, lo primero que tendríamos que hacer es generarnos nuestra propia CA (entidad certificadora). Para ello, podemos seguir las siguientes instrucciones

1) Create a directory
Let's call it sslcert:
mkdir sslcert
Now protect that directory so only the user you are running as (and root) can access it:
chmod 0700 sslcert



2) Create two subdirectories
Cd into the first directory and make two subdirectories. Let's call them certs and private.
cd sslcert
mkdir certs private



3) Create a database to keep track of each certificate signed
Type:
echo '100001' >serial
touch certindex.txt



4) Make a custom config file for openssl to use
Create a file using your ASCII text editor. We will call it openssl.cnf. Here are the basics needed for this exercise (edit as needed):
#
# OpenSSL configuration file.
#
 
# Establish working directory.
 
dir     = .
 
[ ca ]
default_ca    = CA_default
 
[ CA_default ]
serial     = $dir/serial
database    = $dir/certindex.txt
new_certs_dir    = $dir/certs
certificate    = $dir/cacert.pem
private_key    = $dir/private/cakey.pem
default_days    = 365
default_md    = md5
preserve    = no
email_in_dn    = no
nameopt     = default_ca
certopt     = default_ca
policy     = policy_match
 
[ policy_match ]
countryName    = match
stateOrProvinceName   = match
organizationName   = match
organizationalUnitName   = optional
commonName    = supplied
emailAddress    = optional
 
[ req ]
default_bits    = 1024   # Size of keys
default_keyfile    = key.pem  # name of generated keys
default_md    = md5    # message digest algorithm
string_mask    = nombstr  # permitted characters
distinguished_name   = req_distinguished_name
req_extensions    = v3_req
 
[ req_distinguished_name ]
# Variable name    Prompt string
#-------------------------   ----------------------------------
0.organizationName   = Organization Name (company)
organizationalUnitName   = Organizational Unit Name (department, division)
emailAddress    = Email Address
emailAddress_max   = 40
localityName    = Locality Name (city, district)
stateOrProvinceName   = State or Province Name (full name)
countryName    = Country Name (2 letter code)
countryName_min    = 2
countryName_max    = 2
commonName    = Common Name (hostname, IP, or your name)
commonName_max    = 64
 
# Default values for the above, for consistency and less typing.
# Variable name    Value
#------------------------   ------------------------------
0.organizationName_default  = My Company
localityName_default   = My Town
stateOrProvinceName_default  = State or Providence
countryName_default   = US
 
[ v3_ca ]
basicConstraints   = CA:TRUE
subjectKeyIdentifier   = hash
authorityKeyIdentifier   = keyid:always,issuer:always
 
[ v3_req ]
basicConstraints   = CA:FALSE
subjectKeyIdentifier   = hash


5) Create a root certificate
All other certificates you create will be based off of this. Because you are not a commercial certificate authority, software may complain when they use your certificates. However you can give people one of the files, the "public" one, that will be created and they can manually import it. From then on your certificates will load just like the commercial ones.
To create, while in the 'sslcert' directory, type:
openssl req -new -x509 -extensions v3_ca -keyout \
private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf
Note the backslash (\) at the end of the first line. If your OS supports it, this is a way to type long command lines. Simply press after it and you will be prompted to continue typing. Otherwise, leave it out and continue typing.
Note the -days 365 option. For a root certificate you may want it to last longer than one year so that you do not have to reissue it so often. I set mine to 10 years.
You will be prompted for information and a password. Do not loose this password, make sure it is a secure one, and back up the two files that are created.
The two files that are created are cacert.pem, which is the one you can give to others for import in their browsers, and cakey.pem, which will be in the private directory.



6) Installing the root certificate for use
See your browser's help for how to do this. For IE, go to Tools, Options, Content tab, Certificates, Import and follow the steps. Note that we called our root certificate cacert.pem. Rename this file to cacert.crt as it is an X.509 certificate. To make it easy for people to install your root certificate, cacert.crt, place it on your web site with a URL to it. When they click on it in most modern browsers, they can choose to "Open" or "Install" and it will walk them through the install steps.
Note for Mozilla and Firefox/Thuderbird users: Mozilla apps do not use MS Windows' certificate storage. If you use Mozilla, you only need to install the certificate in the browser and it will be available to the email client. If you use Firefox and Thunderbird, or just one of the two, you will need to manually import the certificate with Thunderbird. To do this, right-click the link to the certificate and choose "Save As...". Then in "Manage Certificates", access is via "Advanced" in newer versions, click the Import button.


Estas instrucciones están sacadas del post http://www.flatmtn.com/article/setting-openssl-create-certificates, del blog Flat Mountain que no sé si está abandonado o no publica mucho, pero que tiene información útil como ésta y muy bien explicada. Una vez tenemos nuestras claves raíz creadas, podemos crear los certificados de clientes. Os pongo aquí las instrucciones de cómo hacerlo sacadas del mismo blog.


1) Setup and create root certificate
Note: If all you are going to be creating is certificates to sign files and/or emails, and have an old box around I highly recommend loading it up with Apache, PHP, OpenSSL. Install PHPki and use it to create and manage your certificates. However, make sure this computer is not accessible over the internet.



2) For each person create a key and signing request
Assuming you have your root certificate created and you are in the 'sslcert' directory you can start creating certificates for each person in your company, or at least each one you want to be able to digitally sign drawings (or email or anything else certificates can be used for).
Type (all one line):
openssl req -new -nodes -out name-req.pem -keyout private/name-key.pem -days 365 -config ./openssl.cnf
Note the number of days. For employee certificates I like to keep this fairly short, but a year may be too short. For a newly hired person you might want to do it for the length of their probation period and then reissue it for longer after that.
You will be prompted for information, much like when creating the root certificate. I put "Employee" for the Organizational Unit, make sure to use their correct internet email address for Email Address, and use their full name for Common Name.

Name FieldExplanation
Country NameThe two-letter ISO abbreviation for your country
State or Province NameThe state or province where your organization is located. Can not be abbreviated.
City or LocalityThe city where your organization is located.
Organization NameThe exact legal name of your organization. Do not abbreviate
Organizational UnitOptional for additional organization information.
Common NameThe person's full name.
Email addressThe person's email address
Once you are done with the input, two files will be created:
name-req.pem - the request
name-key.pem - the private key in the private directory



3) Sign each request
This will generate the certificate.
Type:
openssl ca -out name-cert.pem -days 365 -config ./openssl.cnf -infiles name-req.pem
You will be prompted for the password used when creating the root certificate. Then you will be given a chance to review the information before signing. If anything is incorrect, now is the time to stop and redo things.
Two files are created:
name-cert.pem - which is the certificate
.pem - a copy of it in the certs directory.



4) Create the PKCS12 file
This file combines the person's public key, private key, and root certificate into one file.
Type (all one line):
openssl pkcs12 -export -in name-cert.pem -inkey private/name-key.pem -certfile cacert.pem -name "[friendly name]" -out name-cert.p12
[friendly name] can be what you want, but I use the person's full name (note: do not enclose any part of this with quotes, such as a nick name). You will be prompted for an "export password". This is what the user will use when they import the file and if they lose this file and need to export it from a storage "service" for use elsewhere. I let my people come over and type their own, since it is unchangeable once created.
Before you transfer them, note that the p12 format is binary and the pems are text. (This matters with FTP and a few other situations.) Also remember that the name-key.pem is the private key and should be guarded, whereas the name-cert.pem is the public certificate. While name-cert.p12 is encrypted with the password, it does contain the private key so I wouldn't leave it laying out for just anyone to get to.



5) Distribute the file(s)
The name-cert.p12 file is the one to give the person. They will need to know the export password used when creating the file. You can also give them their name-cert.pem and name-key.pem if you want. However, stress that if the name-cert.p12 file or the name-key.pem is compromised, ie lost or misplaced, that they must tell you immediately. Then you must revoke their existing one and issue a new one.
How the users import them depends on the application.

Una vez llegados a este punto, ya somos capaces de generar certificados para usuarios emitidos todos por la misma CA. De esta forma, más adelante podremos indicarle a nuestra aplicación que puede confiar en los certificados de usuario emitidos por dicha CA, algo muchas veces indispensable para el desarrollo de aplicaciones basadas en estas tecnologías.

Tengo intención de seguir con este tema en siguientes posts. En el próximo veremos cómo utilizar estos certificados para firmar información desde aplicaciones desarrolladas en C, utilizando también OpenSSL.