Tag Archives: ssl - Page 2

Creating a PKCS7 (P7B) Using OpenSSL

Continuing the howto nature of this blog (and its peculiar obsession with OpenSSL), here’s a primer on packaging an arbitrary number of certificates into a single PKCS7 container. These files are quite useful for installing multiple certificates on Windows servers. They differ from PKCS12 (PFX) files in that they can’t store private keys. If you need to generate a PKCS12 then head to that article instead.

This example assumes that you have 2 different certificate files, each in PEM (Base64) format. You can add as many -certfile elements as you want to package in the file. Additionally, concatenated certificate chains are supported. 1

openssl crl2pkcs7 -nocrl -certfile cert1.cer -certfile cert2.cer -out outfile.p7b
  1. If you wish to provide DER encoded input files (or have DER output) you can use the -inform DER or -outform DER directives.

Checking A Remote Certificate Chain With OpenSSL

If you deal with SSL/TLS long enough you will run into situations where you need to examine what certificates are being presented by a server to the client. The best way to examine the raw output is via (what else but) OpenSSL.1

First let’s do a standard webserver connection (-showcerts dumps the PEM encoded certificates themselves for more extensive parsing if you desire. The output below snips them for readability.):

openssl s_client -showcerts -connect www.domain.com:443
CONNECTED(00000003)
--snip--
---
Certificate chain
 0 s:/C=US/ST=Texas/L=Carrollton/O=Woot Inc/CN=*.woot.com
   i:/C=US/O=SecureTrust Corporation/CN=SecureTrust CA
-----BEGIN CERTIFICATE-----
--snip--
-----END CERTIFICATE-----
 1 s:/C=US/O=SecureTrust Corporation/CN=SecureTrust CA
   i:/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority
-----BEGIN CERTIFICATE-----
--snip--
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=Texas/L=Carrollton/O=Woot Inc/CN=*.woot.com
issuer=/C=US/O=SecureTrust Corporation/CN=SecureTrust CA
---
No client certificate CA names sent
---
SSL handshake has read 2123 bytes and written 300 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 1024 bit
--snip--

There’s a lot of data here so I have truncated several sections to increase readability. Points of interest:

  1. The certificate chain consists of two certificates. At level 0 there is the server certificate with some parsed information. s: is the subject line of the certificate and i: contains information about the issuing CA.
  2. This particular server (www.woot.com) has sent an intermediate certificate as well. Subject and issuer information is provided for each certificate in the presented chain. Chains can be much longer than 2 certificates in length.
  3. The server certificate section is a duplicate of level 0 in the chain. If you’re only looking for the end entity certificate then you can rapidly find it by looking for this section.
  4. No client certificate CAs were sent. If the server was configured to potentially accept client certs the returned data would include a list of “acceptable client CAs”.
  5. Connection was made via TLSv1/SSLv3 and the chosen cipher was RC4-MD5. Incidentally, this typically means that the server you’re connecting to is IIS.

But what if you want to connect to something other than a bog standard webserver on port 443? Well, if you need to use starttls that is also available. As of OpenSSL 0.9.8 you can choose from smtp, pop3, imap, and ftp as starttls options.

openssl s_client -showcerts -starttls imap -connect mail.domain.com:139

If you need to check using a specific SSL version (perhaps to verify if that method is available) you can do that as well. -ssl2, -ssl3, -tls1, and -dtls1 are all choices here.2

openssl s_client -showcerts -ssl2 -connect www.domain.com:443

You can also present a client certificate if you are attempting to debug issues with a connection that requires one.3

openssl s_client -showcerts -cert cert.cer -key cert.key -connect www.domain.com:443

And for those who really enjoy playing with SSL handshakes, you can even specify acceptable ciphers.4

openssl s_client -showcerts -cipher DHE-RSA-AES256-SHA -connect www.domain.com:443

The cipher used above should work for almost any Apache server, but will fail on IIS since it doesn’t support 256-bit AES encryption.

  1. The s_client command we’re using opens an interactive socket and does not automatically return to the shell prompt, so remember you will have to hit control-c or type something and hit return to terminate the process.
  2. This example shows an attempted SSLv2 only connection. SSLv2 should be disabled on any web server you control. It has a variety of flaws and has been superseded by SSLv3/TLSv1 for over a decade.
  3. This example expects the certificate and private key in PEM form. You can provide them in DER if you add -certform DER and -keyform DER (OpenSSL 0.9.8 or newer only)
  4. A list of available ciphers can be found by typing “openssl ciphers”, but there are also myriad ways to sort by type and strength. See the ciphers man page for more details.

Generating (Very) Large Primes

Have you ever wondered how big the “large primes” that RSA encryption is based on really are? What exactly does a “1024-bit” key mean anyway? And if the difficulty of RSA is partially based on factoring large numbers, how do we create these large primes without determining primality via factorization?

The easiest way to demonstrate these concepts is with a simple script, so let’s take a look at a large random number generator I wrote1 using Python. As is typical for this blog, you’ll note that the random numbers are not cryptographically secure. To make these examples simple I don’t want to introduce external dependencies, but please keep that issue in mind for any serious applications of the code presented here.

import random
import math
import sys
 
def rabinMiller(n):
     s = n-1
     t = 0
     while s&1 == 0:
         s = s/2
         t +=1
     k = 0
     while k<128:
         a = random.randrange(2,n-1)
         #a^s is computationally infeasible.  we need a more intelligent approach
         #v = (a**s)%n
         #python's core math module can do modular exponentiation
         v = pow(a,s,n) #where values are (num,exp,mod)
         if v != 1:
             i=0
             while v != (n-1):
                 if i == t-1:
                     return False
                 else:
                     i = i+1
                     v = (v**2)%n
         k+=2
     return True
 
def isPrime(n):
     #lowPrimes is all primes (sans 2, which is covered by the bitwise and operator) 
     #under 1000. taking n modulo each lowPrime allows us to remove a huge chunk 
     #of composite numbers from our potential pool without resorting to Rabin-Miller
     lowPrimes =   [3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
                   ,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179
                   ,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269
                   ,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367
                   ,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461
                   ,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571
                   ,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661
                   ,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773
                   ,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883
                   ,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]
     if (n >= 3):
         if (n&1 != 0):
             for p in lowPrimes:
                 if (n % p == 0):
                     return False
             return rabinMiller(n)
     return False
 
def generateLargePrime(k):
     #k is the desired bit length
     r=100*(math.log(k,2)+1) #number of attempts max
     r_ = r
     while r>0:
        #randrange is mersenne twister and is completely deterministic
        #unusable for serious crypto purposes
         n = random.randrange(2**(k-1),2**(k))
         r-=1
         if isPrime(n) == True:
             return n
     return "Failure after "+`r_` + " tries."
 
print generateLargePrime(1024)

This code is very slow, but does not represent an entirely naïve approach.2  To generate a prime we first create a random integer in the range (2k-1,2k), then the following rules are applied:

  1. The number (n) must be >=3.  While 2 is a prime number, for our purposes we have no interest in numbers less than 3.
  2. Do a bitwise and (n&1).  If the result is not 0 then we know the number is even and can throw it out.
  3. Check that n%p is 0 (in other words, that n is not divisible evenly by p) for all primes <1000.  This check will eliminate a large quantity of composite numbers and prevent the expense of the next test.
  4. Finally we reach the core test: Rabin-Miller.  This algorithm, if it returns true, states that there is a 75% chance that the number is prime (for the randomly chosen basis a).  To obtain a 2-128 chance that the number is not prime, we must repeatedly run the Rabin-Miller test choosing different number bases. Since each iteration of the test increases our probability by a power of 2 we must iterate 64 times to reach this confidence level.

 
If the number passes all these tests it is returned as a valid prime number. Of course, if you don’t trust the output from this script you can always check it with openssl…

openssl prime 7337488745629403488410174275830423641502142554560856136484326749638755396267050319392266204256751706077766067020335998122952792559058552724477442839630133
8C18E5DC98684E2A15B84535635A95C4A192B73B40A780AB4CB0C58BDB9C31EF970C3AC6D804712B830FB6F1B140693A251E989F89B687EBA62781AD031D5135 is prime

 Click for an example of an 8192-bit prime created with the generateLargePrime() function. You can also check out a 1024-bit prime as well. 1024-bit keys are the minimum size recommended for end entity certificates using RSA (SSL certificates) at this time.3

Of course, a large prime is nice, but it isn’t necessarily an RSA prime. Look for another entry soon explaining the additional restrictions imposed by RSA.

  1. This code is based on the pseudocode provided in Practical Cryptography.
  2. Generation of a 1024-bit prime using this script takes 5-10 seconds, whereas OpenSSL takes 0.1-0.2 seconds.
  3. NIST guidelines suggest migration to 2048-bit keys by 31 Dec 2010)

Re-Signing An Expired CA Certificate

On rare occasions you may find yourself with a self-signed internal CA that has expired while you are still using certificates issued from the CA. One potential solution to this problem is to self-sign a new cert with identical fields using the private key from the old certificate.1

You can fill in almost all the fields using the interactive prompt, but to ensure maximum compatibility be sure every field matches exactly. You will also need to set the serial number of the certificate via the -set_serial parameter (openssl takes this argument in decimal form, not hex)2.

openssl req -new -x509 -key previousprivatekey.pem -set_serial 0000 -out newroot.cer

You now have a new root certificate that will work with your previously issued certificates!

  1. In general this is very bad practice, but this article presupposes that you recognize this and it is still necessary.
  2. If you fail to set the serial identically Microsoft OSes will chain the certificate correctly but OpenSSL will fail.

OpenSSL SAN/UCC Certificate Generation

Signing a CSR containing subjectAltName (SAN/UCC) extensions isn’t hard, but can be a daunting challenge for the OpenSSL neophyte. We’re going to use the OpenSSL Self-Signed CA to accomplish this task in two ways.

Pre-Existing SAN CSR

Either you already have a SAN CSR from another source or you generated one using the tutorial from yesterday. Inside your myca.conf file you’ll need to add the following under the [ myca ] section.

copy_extensions	= copy

Now you can simply sign the CSR using the method specified in the self-signed CA post and you’re all set.

Add SAN/UCC Extensions to Existing CSR

To accomplish this add the following to your myca.conf under the [ myca_extensions ] section.

subjectAltName          = @alt_names

Then add this section at the end of the file.

[alt_names]
DNS.1   = test.domain.com
DNS.2   = other.domain.com
DNS.3   = www.domain.net

Set the DNS entries under alt_names to what you want (adding DNS.4 = if you need more, et cetera). Be sure you do not have the copy_extensions directive present in your conf.
Once you have done this you can sign any CSR you choose with the command specified in the self-signed CA article and it will add the specified subjectAltName attributes to the certificate.

Creating a SubjectAltName (SAN/UCC) CSR

SAN certificates (or as Microsoft and others have taken to calling them, Unified Communications Certificates) are rapidly becoming a popular option for securing multiple domains. In fact, Exchange 2007, OCS 2007, and several other products now require UCC to function. However, this certificate type can proffer some advantages beyond that of a wildcard certificate as well. One such advantage is the ability to secure “domain.com”, “www.domain.com”, “domain.net”, and “someotherdomain.com” all within a single certificate.

SAN CSRs cannot be generated using the interactive prompt in OpenSSL so we’ll need to make a conf:

[ req ]
default_bits        = 1024
default_keyfile     = privkey.pem
distinguished_name  = req_distinguished_name
req_extensions     = req_ext # The extentions to add to the self signed cert
 
[ req_distinguished_name ]
countryName           = Country Name (2 letter code)
countryName_default   = US
stateOrProvinceName   = State or Province Name (full name)
stateOrProvinceName_default = Illinois
localityName          = Locality Name (eg, city)
localityName_default  = Chicago
organizationName          = Organization Name (eg, company)
organizationName_default  = Example, Co.
commonName            = Common Name (eg, YOUR name)
commonName_max        = 64
 
[ req_ext ]
subjectAltName          = @alt_names
 
[alt_names]
DNS.1   = test.domain.com
DNS.2   = other.domain.com
DNS.3   = www.domain.net

You will need to set your alt_names section to the FQDNs you wish to use. If you need more simply add “DNS.4 = whatever.com” and so on. Once you have done that, save the file as “req.conf” and then execute openssl!

openssl req -new -nodes -out myreq.csr -config req.conf
Generating a 1024 bit RSA private key
............................................................++++++
..++++++
writing new private key to 'privkey.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]:US
State or Province Name (full name) [Illinois]:Illinois
Locality Name (eg, city) [Chicago]:Chicago
Organization Name (eg, company) [Example, Co.]:Example, Co.
Common Name (eg, YOUR name) []:www.domain.com

You now have a “myreq.csr” and a “privkey.pem” associated with the CSR. You can now submit this CSR to a CA for signing or sign it with your own self-signed CA. A tutorial to perform the latter will be published in a few days!