Test

Powered by Blogger.

Friday 14 November 2014

A complete guide to Openssl command line programming

  First steps

OpenSSL is a C library that implements the main cryptographic operations like symmetric encryption, public-key encryption, digital signature, hash functions and so on... OpenSSL also implements obviously the famous Secure Socket Layer (SSL) protocol. OpenSSL is avaible for a wide variety of platforms. The source code can be downloaded from www.openssl.org. A windows distribution can be foundhere. This tutorial shows some basics funcionalities of the OpenSSL command line tool. After the installation has been completed you should able to check for the version.

> openssl version OpenSSL 0.9.7e 25 Oct 2004

OpenSSL has got many commands. Here is the way to list them:

> openssl list-standard-commands asn1parse ca ciphers crl crl2pkcs7 ...

Let's see a brief description of each command:

ca To create certificate authorities.dgst To compute hash functions.enc To encrypt/decrypt using secret key algorithms. It is possible to generate using a password or directly a secret key stored in a file.genrsa This command permits to generate a pair of public/private key for the RSA algorithm.password Generation of "hashed passwords".pkcs12 Tools to manage information according to the PKCS #12 standard.pkcs7 Tools to manage information according to the PKCS #7 standard.rand Generation of pseudo-random bit strings.rsa RSA data management.rsautl To encrypt/decrypt or sign/verify signature with RSA.verify Checkings for X509.x509 Data managing for X509.

2  Secret key encryption algorithms

OpenSSL implements numerous secret key algorithms. To see the complete list:

> openssl list-cipher-commands aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc aes-256-ecb base64 ...

The list contains the algorithm base64which is a way to code binary information with alphanumeric characters. It is not really a secret key algorithm as there is no secret key! Let's see an example:

> touch number.txt > echo "123456789" > number.txt > openssl enc -base64 -in number.txt MTIzNDU2Nzg5Cg==

But indeed we really want to use secret key algorithm to protect our information, don't we? So, if I want for example to encrypt the text "I love OpenSSL!" with the AES algorithm using CBC mode and a key of 256 bits, I simply write:

> touch plain.txt > echo "I love OpenSSL!" > plain.txt > openssl enc -aes-256-cbc -in plain.txt -out encrypted.bin enter aes-256-cbc encryption password: hello Verifying - enter aes-256-cbc encryption password: hello

The secret key of 256 bits is computed from the password. Note that of course the choice of password "hello" is really INSECURE! Please take the time to choose a better password to protect your privacy! The output fileencrypted.bin is binary.If I want to decrypt this file I write:

> openssl enc -aes-256-cbc -d -in encrypted.bin -pass pass:hello I love OpenSSL!

3  Public Key Cryptography

To illustrate how OpenSSL manages public key algorithms we are going to use the famous RSA algorithm. Other algorithms exist of course, but the principle remains the same.

3.1  Key generation

First we need to generate a pair of public/private key. In this example we create a pair of RSA key of 1024 bits.

> openssl genrsa -out key.pem 1024 Generating RSA private key, 1024 bit long modulus .............................++++++ ................................................................++++++ e is 65537 (0x10001)

The generated file has got both public and private key. Obviously the private key must be kept in a secure place, or better must be encrypted. But before let's have a look at the file key.pem. The private key is coded using the Privacy Enhanced Email (PEM) standard.

> cat key.pem -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQC7iXTZ+DVO6jzjUMzJKij53vHd0+43ksK7A/gevHpbAGpLyhTE dpqFlcYYjIs6Vi/rFzb2rF3GbEtbOC+FQzMpmCE2ISNp2FgK2lX8nVTY6KQb9tBZ /Nmxyd3Sle2BIe05/ETbOgH7AG7jQiPJTBLen1yfEI/qXRbZWtBj2pLnlQIDAQAB ... IfVV1RrKWZTXFMGHXIXEAM+x1/xsvJcmcpEA9+71Tj45tA== -----END RSA PRIVATE KEY-----

The next line allows to see the details of the RSA key pair (modulus, public and private exponent between others).

> openssl rsa -in key.pem -text -noout Private-Key: (1024 bit) modulus: 00:bb:89:74:d9:f8:35:4e:ea:3c:e3:50:cc:c9:2a: ... 6e:e3:42:23:c9:4c:12:de:9f:5c:9f:10:8f:ea:5d: 16:d9:5a:d0:63:da:92:e7:95 publicExponent: 65537 (0x10001) privateExponent: 00:94:df:e7:ed:69:47:18:60:86:f9:85:99:2c:50: ... 81:ef:b1:28:63:bb:fc:70:de:52:3a:08:69:c9:9e: 75:d8:7e:8b:39:13:ab:24:39 prime1: 00:f2:18:f9:0d:62:fc:af:fb:df:10:23:d9:e4:b4: ... 10:f8:ca:9c:64:a1:42:ec:2f:4a:7f:7c:59:57:1c: be:33:09:95:d3 prime2: 00:c6:4e:66:2a:11:2c:42:fb:69:30:9a:c3:8b:57: ... d0:fc:50:7d:da:8c:51:2d:02:53:5b:d1:e9:4d:cc: 3b:7b:9a:a3:f7 exponent1: 15:be:44:6f:fd:59:f0:7c:50:96:64:81:e7:56:8f: ... 6e:48:d4:2e:fd:84:c3:2d:a4:25:3b:07:d3:19:13: c4:05:b2:5d exponent2: 00:94:59:63:fe:46:58:89:47:50:da:c6:7c:50:8a: ... 05:18:2c:12:ea:62:9b:fb:82:c8:df:60:ba:1a:b4: 15:2f:93:70:e3 coefficient: 00:9f:3c:71:db:ba:2a:20:5f:8a:7a:f0:99:e7:f0: ... c4:00:cf:b1:d7:fc:6c:bc:97:26:72:91:00:f7:ee: f5:4e:3e:39:b4

The -noout option allows to avoid the display of the key in base 64 format. Numbers in hexadecimal format can be seen (except the public exponent by default is always 65537 for 1024 bit keys): the modulus, the public exponent, the private, the two primes that compose the modules and three other numbers that are use to optimize the algorithm.

So now it's time to encrypt the private key:

> openssl rsa -in key.pem -des3 -out enc-key.pem writing RSA key Enter PEM pass phrase: Verifying - Enter PEM pass phrase:

The key file will be encrypted using a secret key algorithm which secret key will be generated by a password provided by the user. In this example the secret key algorithm is triple des (3-des). The private key alone is not of much interest as other users need the public key to be able to send you encrypted messages (or check if a piece of information has been signed by you). So let's extract the public from the filekey.pem

> openssl rsa -in key.pem -pubout -out pub-key.pem

3.2  Encryption

We are ready to perform encryption or produce digital signature.

> openssl rsautl -encrypt -in <input_file> -inkey <llave> \ -out <output_file>

Where:

input_file is the file to encrypt. This file must no be longer that 116 bytes =928 bits because RSA is a block cipher, and this command is low level command, i.e. it does not do the work of cutting your text in piece of 1024 bits (less indeed because a few bits are used for special purposes.)key File that contains the public key. If this file contains only the public key (not both private and public), then the option -pubin must be used.output_file the encrypted file.

To decrypt only replace -encrypt by -decrypt, and invert the input / output file as for decryption the input is the encrypted text, and the output the plain text.

3.3  Digital signatures

The next step is to be create a digital signature and to verify it. It is not very efficient to sign a big file using directly a public key algorithm. That is why first we compute the digest of the information to sign. Note that in practice things are a bit more complex. The security provided by this scheme (hashing and then signing directly using RSA) is not the same (is less in fact) than signing directly the whole document with the RSA algorithm. The scheme used in real application is called RSA-PSS which is efficient and proven to keep the best level of security.

> openssl dgst -<hash_algorithm> -out <digest> <input_file>

Where:

hash_algorithm is the hash algorithm used to compute the digest. Among the available algorithm there are:SHA-1 (option -sha1 which computes a 160 bits digests), MD5(option -md5) with 128 bits output length andRIPEMD160 (option -ripemd160) with 160 bits output length.digest is the file that contains the result of the hash application oninput_file.input_file file that contains the data to be hashed.

This command can be used to check the hash values of some archive files like the openssl source code for example. To compute the signature of the digest:

> openssl rsautl -sign -in <digest> -out <signature> -inkey <key>

To check to validity of a given signature:

> openssl rsautl -verify -in <signature> -out <digest> \ -inkey <key> -pubin

-pubin is used like before when the key is the public one, which is natural as we are verifying a signature.To complete the verification, one needs to compute the digest of the input file and to compare it to the digest obtained in the verification of the digital signature.

4  Public Key Infrastructure

4.1  What is a PKI? (in short)

4.1.1  The Problem: Man in the Middle Attack

One of the major breakthrough of public key cryptography is to solve the problem of key distribution. Secret key cryptography supposes the participants already agreed on a common secret. But how do they manage this in practice? Sending the key through an encrypted channel seems the more natural and practical solution but once again we need a common secret key to do this. With public key cryptography things are a lot simpler: if I want to send a message to Bob, I only need to find Bob's public key (on his homepage, on a public key directory ...) encrypt the message using this key and send the result to Bob. Then Bob using his own private key can recover the plain text. However a big problem remains. What happens if a malicious person called The Ugly makes me believe that the public key he owns is in fact Bob's one? Simply I will send an encrypted message using The Ugly's public key thinking I'm communicating with Bob. The Ugly will receive the message, decrypt it, and will then encrypt the plaintext with Bob's (real) public key. Bob will receive the encrypted message, will answer probably with another encrypted message using The Ugly's public key (who once again managed to convince Bob, this public key belongs to me). Afterwards The Ugly will decrypt the message, reencrypt it with my public key, so I will really receive the Bob's answer. Indeed I will be communicating with Bob, but without confidentiality. This attack is called "Man in the middle Attack", where the man is of course The Ugly of our little story. So we need a mechanism to associate in a trustworthy way a public key to the identity of a person (name, identity card number ...). One of this mechanism is implemented in PGP. The idea is that every one builds his own net of trust, by having a list of trusted public keys, and by sharing these keys. The other solution is the use of a PKI.

4.1.2  A solution: Public Key Infrastructure

Public Key Infrastructure is a centralized solution to the problem of trust. The idea is to have a trusted entity (organization, corporation) that will do the job of certifying that a given public key belongs really to a given person. This person must be identified by his name, address and other useful information that may allow to know who this person is. Once this work his done, the PKI emits a public certificate for this person. This certificate contains between others:

All the information needed to identify this person (name, birth date,...).The public key of this person.The date of creation of the certificate.The date of revocation of the certificate (a certificate is valid during 1 or 3 years in practice).The digital signature of all this previous information emitted by the PKI.

So now, if I want to send a private message to Bob, I can ask for his certificate. When I received the certificate, I must check the signature of the PKI who emitted it and for the date of revocation. If verifications pass then I can safely use the public key of the certificate to communicate with Bob. Indeed, in practice the way a PKI works is much more complicated. For example sometimes a certificate may be revocated before the date of end of validity has been reached. So a kind of list of revocated certificated has to be maintained and accessed every time you want to use a certificate. The problem of certificate revocation is really difficult in practice.

4.2  My first PKI with OpenSSL

This section will show how to create your own small PKI. Obviously this is only a tutorial and you SHOULD NOT base a real application only on the information contained in this page!

4.2.1  openssl.cnf: let's configure a few things

Before starting to create certificates it is necesarry to configure a few parameters. That can be done editing the file openssl.cnf the is usually located in the bin directory of OpenSSL. This file looks like this:

openssl.cnf

# # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca' and 'req'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = "/home/philippe/openssl" # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. #unique_subject = no # Set to 'no' to allow creation of # several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/crl.pem # The current CRL private_key = $dir/private/cakey.pem # The private key RANDFILE = $dir/private/.rnd # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. # copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crlnumber must also be commented out to leave a V1 CRL. # crl_extensions = crl_ext default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional ....

If you want to simplify your work you should use the default openssl.cnf file with the demoCA directory (also in the bindirectory of OpenSSL) that contains all the necesarry files. You should ensure that all the directories are valid ones, and that the private key that will be created in the next section (cakey.pem) is well linked. Also check of the presence of a file .rand or .rnd that will bee created with cakey.pem. For the certificates database you can create an empty file index.txt. Also create a serial file serial with the text for example011E. 011E is the serial number for the next certificate.

4.2.2  PKI creation

First we must create a certificate for the PKI that will contain a pair of public / private key. The private key will be used to sign the certificates.

> openssl req -new -x509 -keyout cakey.pem -out cacert.pem

The pair of keys will be in cakey.pem and the certificate (which does NOT contain the private key, only the public) is saved in cacert.pem. During the execution you will be asked for many informations about your organization (name, country, and so on ...). The private key contained in cakey.pem is encrypted with a password. This file should be put in a very secure place (although it is encrypted). -x509 refers to a standard that defines how information of the certificate is coded. It can be useful to export the certificate of the PKI in DER format as to be able to load it into your browser.

> openssl x509 -in cacert.pem -outform DER -out cacert.der

4.2.3  Creation of a user certificate

Now the PKI has got its own pair of keys and certificate, let's suppose a user wants to get a certificate from the PKI. To do so he must create a certificate request, that will contain all the information needed for the certificate (name, country, ... and the public key of the user of course). This certificate request is sent to the PKI.

> openssl req -new -keyout userkey.pem -out usercert-req.pem

Note this command will create the pair of keys and the certificate request. The pair of keys is saved in userkey.pem and the certificate request in usercert-req.pem. The PKI is ready for the next step: signing the certificate request to obtain the user's certificate.

> openssl ca -in usercert-req.pem -out usercert.pem Using configuration from /usr/local/bin/openssl/openssl.cnf Loading 'screen' into random state - done Enter pass phrase for demoCA/private/cakey.pem: Check that the request matches the signature Signature ok Certificate Details: Serial Number: 286 (0x11e) Validity Not Before: Jan 19 12:52:37 2008 GMT Not After : Jan 18 12:52:37 2009 GMT Subject: countryName = CL stateOrProvinceName = RM organizationName = littlecryptographer commonName = John Smith emailAddress = jsmith@hello.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 34:F0:61:38:87:68:C7:25:93:86:90:35:32:40:4F:... X509v3 Authority Key Identifier: keyid:FE:CB:56:0B:28:EB:2A:E9:C7:9C:EA:E5:3A:... Certificate is to be certified until Jan 18 12:52:37 2009 GMT (365 days) Sign the certificate? [y/n]:y

usercert.pem is the public certificate signed by the PKI. If you want to import this certificate into your browser you need to convert it in PKCS12 format:

> openssl pkcs12 -export -in usercert.pem -inkey userkey.pem > usercert.p12

Hands on OPENSSL programming APIs

This section demonstrates the implementation of a simple SSL client and server program using OpenSSL APIs.

Although SSL client and server programs might differ in their setup and configuration, their common internal procedures can be summarized in Figure 4-8 " Overview of SSL Application with OpenSSL APIs". These procedures are discussed in the following sections.

Figure 4-8  Overview of SSL Application with OpenSSL APIs

Initializing the SSL Library

Before you can call any other OpenSSL APIs in the SSL application programs, you must perform initialization using the following SSL APIs.

SSL_library_init(); /* load encryption & hash algorithms for SSL */
SSL_load_error_strings(); /* load the error strings for good error reporting */

The SSL_library_init() API registers all ciphers and hash algorithms used in SSL APIs. The encryption algorithms loaded with this API are DES-CBC, DES-EDE3-CBC, RC2 and RC4 (IDEA and RC5 are not available in HP SSL for OpenVMS); and the hash algorithms are MD2, MD5, and SHA. TheSSL_library_init() API has a return value that is always 1 (integer).

SSL applications should call theSSL_load_error_strings() API. This API loads error strings for SSL APIs as well as for Crypto APIs. Both SSL and Crypto error strings need to be loaded because many SSL applications call some Crypto APIs as well as SSL APIs.

Creating and Setting Up the SSL Context Structure (SSL_CTX)

The first step after the intialization is to choose an SSL/TLS protocol version. Do this by creating anSSL_METHOD structure with one of the following APIs. The SSL_METHOD structure is then used to create anSSL_CTX structure with the SSL_CTX_new() API.

For every SSL/TLS version, there are three types of APIs to create an SSL_METHOD structure: one for both client and server, one for server only, and one for client only. SSLv2, SSLv3, and TLSv1 APIs correspond with the same name protocols. Table 4-2 " Types of APIs for SSL_METHOD Creation" shows the types of APIs.

Table 4-2  Types of APIs for SSL_METHOD Creation

Protocol typeFor combined client and serverFor a dedicated serverFor a dedicated clientSSLv2SSLv2_method()SSLv2_server_ method()SSLv2_client_ method()SSLv3SSLv3_method()SSLv3_server_ method()SSLv3_client_ method()TLSv1TLSv1_method()TLSv1_server_ method()TLSv1_client_ method()SSLv23SSLv23_method()SSLv23_server_ method()SSLv23_client_ method()

 NOTE: There is no SSL protocol version named SSLv23. The SSLv23_method() API and its variants choose SSLv2, SSLv3, or TLSv1 for compatibility with the peer.

Consider the incompatibility among the SSL/TLS versions when you develop SSL client/server applications. For example, a TLSv1 server cannot understand a client-hello message from an SSLv2 or SSLv3 client. The SSLv2 client/server recognizes messages from only an SSLv2 peer. TheSSLv23_method() API and its variants may be used when the compatibility with the peer is important. An SSL server with the SSLv23 method can understand any of the SSLv2, SSLv3, and TLSv1 hello messages. However, the SSL client using the SSLv23 method cannot establish connection with the SSL server with the SSLv3/TLSv1 method because SSLv2 hello message is sent by the client.

The SSL_CTX_new() API takes the SSL_METHODstructure as an argument and creates an SSL_CTXstructure.

In the following example, an SSL_METHOD structure that can be used for either an SSLv3 client or SSLv3 server is created and passed to SSL_CTX_new(). TheSSL_CTX structure is initialized for SSLv3 client and server.

meth = SSLv3_method();
ctx = SSL_CTX_new(meth);

Setting Up the Certificate and Key

"Certificates for SSL Applications" discussed how the SSL client and server programs require you to set up appropriate certificates. This setup is done by loading the certificates and keys into the SSL_CTX or SSL structures. The mandatory and optional certificates are as follows:

For the SSL server:

Server's own certificate (mandatory)CA certificate (optional)

For the SSL client:

CA certificate (mandatory)Client's own certificate (optional)

=

Loading a Certificate (Client/Server Certificate)

Use the SSL_CTX_use_certificate_file() API to load a certificate into an SSL_CTX structure. Use theSSL_use_certificate_file() API to load a certificate into an SSL structure. When the SSLstructure is created, the SSL structure automatically loads the same certificate that is contained in theSSL_CTX structure. Therefore, you onlyneed to call theSSL_use_certificate_file() API for the SSLstructure only if it needs to load a different certificate than the default certificate contained in the SSL_CTXstructure.

Loading a Private Key

The next step is to set a private key that corresponds to the server or client certificate. In the SSL handshake, a certificate (which contains the public key) is transmitted to allow the peer to use it for encryption. The encrypted message sent from the peer can be decrypted only using the private key. You must preload the private key that was created with the public key into the SSLstructure.

The following APIs load a private key into an SSL orSSL_CTX structure:

SSL_CTX_use_PrivateKey()

SSL_CTX_use_PrivateKey_ASN1()

SSL_CTX_use_PrivateKey_file()

SSL_CTX_use_RSAPrivateKey()

SSL_CTX_use_RSAPrivateKey_ASN1()

SSL_CTX_use_RSAPrivateKey_file()

SSL_use_PrivateKey()

SSL_use_PrivateKey_ASN1()

SSL_use_PrivateKey_file()

SSL_use_RSAPrivateKey()

SSL_use_RSAPrivateKey_ASN1()

SSL_use_RSAPrivateKey_file()

Loading a CA Certificate

To verify a certificate, you must first load a CA certificate (because the peer certificate is verified against a CA certificate). TheSSL_CTX_load_verify_locations() API loads a CA certificate into the SSL_CTX structure.

The prototype of this API is as follows:

int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
const char *CApath);

The first argument, ctx, points to an SSL_CTX structure into which the CA certificate is loaded. The second and third arguments, CAfile and CApath, are used to specify the location of the CA certificate. When looking up CA certificates, the OpenSSL library first searches the certificates in CAfile, then those in CApath.

The following rules apply to the CAfile and CApatharguments:

If the certificate is specified by CAfile (the certificate must exist in the same directory as the SSL application), specify NULL for CApath.

To use the third argument, CApath, specify NULL for CAfile. You must also hash the CA certificates in the directory specified by CApath. Use the Certificate Tool (described in Chapter 3) to perform the hashing operation.

Setting Up Peer Certificate Verification

The CA certificate loaded in the SSL_CTX structure is used for peer certificate verification. For example, peer certificate verification on the SSL client is performed by checking the relationships between the CA certificate (loaded in the SSL client) and the server certificate.

For successful verification, the peer certificate must be signed with the CA certificate directly or indirectly (a proper certificate chain exists). The certificate chain length from the CA certificate to the peer certificate can be set in the verify_depth field of the SSL_CTXandSSL structures. (The value in SSL is inherited fromSSL_CTX when you create an SSL structure using theSSL_new() API). Setting verify_depth to 1 means that the peer certificate must be directly signed by the CA certificate.

The SSL_CTX_set_verify() API allows you to set the verification flags in the SSL_CTX structure and a callback function for customized verification as its third argument. (Setting NULL to the callback function means the built-in default verification function is used.) In the second argument of SSL_CTX_set_verify(), you can set the following macros:

SSL_VERIFY_NONE

ì

SSL_VERIFY_PEER

SSL_VERIFY_FAIL_IF_NO_PEER_CERT

SSL_VERIFY_CLIENT_ONCE

The SSL_VERIFY_PEER macro can be used on both SSL client and server to enable the verification. However, the subsequent behaviors depend on whether the macro is set on a client or a server. For example:

/* Set a callback function (verify_callback) for peer certificate */
/* verification */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
/* Set the verification depth to 1 */
SSL_CTX_set_verify_depth(ctx,1);

You can verify a peer certificate in another, less common way - by using theSSL_get_verify_result() API. This method allows you to obtain the peer certificate verification result without using the SSL_CTX_set_verify() API.

Call the following two APIs before you call theSSL_get_verify_result() API:

Call SSL_connect() (in the client) or SSL_accept() (in the server) to perform the SSL handshake. Certificate verification is performed during the handshake. SSL_get_verify_result() cannot obtain the result before the verification process.

Call SSL_get_peer_certificate() to explicitly obtain the peer certificate. The X509_V_OK macro value is returned when a peer certificate is not presented as well as when the verification succeeds.

The following code shows how to useSSL_get_verify_result() in the SSL client:

SSL_CTX_set_verify_depth(ctx, 1);
err = SSL_connect(ssl);
if(SSL_get_peer_certificate(ssl) != NULL)
{
if(SSL_get_verify_result(ssl) == X509_V_OK) BIO_printf(bio_c_out, "client verification with SSL_get_verify_result()
succeeded.\n");
else{

BIO_printf(bio_err, "client verification with SSL_get_verify_result()
failed.\n");

exit(1);
}
}
else
BIO_printf(bio_c_out, -the peer certificate was not presented.\n-);

Example 1: Setting Up Certificates for the SSL Server

The SSL protocol requires that the server set its own certificate and key. If you want the server to conduct client authentication with the client certificate, the server must load a CA certificate so that it can verify the client-s certificate.

The following example shows how to set up certificates for the SSL server:

/* Load server certificate into the SSL context */
if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT,
SSL_FILETYPE_PEM) <= 0) } ERR_print_errors(bio_err); /* ==
ERR_print_errors_fp(stderr); */
exit(1);
}

/* Load the server private-key into the SSL context */
if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY,
SSL_FILETYPE_PEM) <= 0) { ERR_print_errors(bio_err); /* ==
ERR_print_errors_fp(stderr); */
exit(1);
}

/* Load trusted CA. */
if (!SSL_CTX_load_verify_locations(ctx,CA_CERT,NULL)) {
ERR_print_errors(bio_err); /* ==
ERR_print_errors_fp(stderr); */
exit(1);
}

/* Set to require peer (client) certificate verification */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
/* Set the verification depth to 1 */
SSL_CTX_set_verify_depth(ctx,1);

Example 2: Setting Up Certificates for the SSL Client

Generally, the SSL client verifies the server certificate in the process of the SSL handshake. This verification requires the SSL client to set up its trusting CA certificate. The server certificate must be signed with the CA certificate loaded in the SSL client in order for the server certificate verification to succeed.

The following example shows how to set up certificates for the SSL client:

/*----- Load a client certificate into the SSL_CTX structure -----*/
if(SSL_CTX_use_certificate_file(ctx,CLIENT_CERT,
SSL_FILETYPE_PEM) <= 0){
ERR_print_errors_fp(stderr);
exit(1);
}

/*----- Load a private-key into the SSL_CTX structure -----*/
if(SSL_CTX_use_PrivateKey_file(ctx,CLIENT_KEY,
SSL_FILETYPE_PEM) <= 0){
ERR_print_errors_fp(stderr);
exit(1);
}

/* Load trusted CA. */
if (!SSL_CTX_load_verify_locations(ctx,CA_CERT,NULL)) {
ERR_print_errors_fp(stderr);
exit(1);
}

Creating and Setting Up the SSL Structure

Call SSL_new() to create an SSL structure. Information for an SSL connection is stored in the SSL structure. The protocol for the SSL_new() API is as follows:

ssl = SSL_new(ctx);

A newly created SSL structure inherits information from the SSL_CTX structure. This information includes types of connection methods, options, verification settings, and timeout settings. No additional settings are required for the SSL structure if the appropriate initialization and configuration have been done for theSSL_CTX structure.

You can modify the default values in the SSL structure using SSL APIs. To do this, use variants of the APIs that set attributes of the SSL_CTX structure. For example, you can use SSL_CTX_use_certificate() to load a certificate into an SSL_CTX structure, and you can useSSL_use_certificate() to load a certificate into anSSL structure.

Setting Up the TCP/IP Connection

Although SSL works with some other reliable protocols, TCP/IP is the most common transport protocol used with SSL.

The following sections describe how to set up TCP/IP for the SSL APIs. This configuration is the same as in many other TCP/IP client/server application programs; it is not specific to SSL API applications. In these sections, TCP/IP is set up with the ordinary socket APIs, although it is also possible to use OpenVMS system services.

Creating and Setting Up the Listening Socket (on the SSL Server)

The SSL server needs two sockets as an ordinary TCP/IP server—one for the SSL connection, the other for detecting an incoming connection request from the SSL client.

In the following code, the socket() function creates a listening socket. After the address and port are assigned to the listening socket with bind(), thelisten() function allows the listening socket to handle an incoming TCP/IP connection request from the client.

listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
CHK_ERR(listen_sock, "socket");

memset(&sa_serv, 0, sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons(s_port); /* Server Port number */

err = bind(listen_sock, (struct sockaddr*)&sa_serv,sizeof(sa_serv));
CHK_ERR(err, "bind");

/* Receive a TCP connection. */
err = listen(listen_sock, 5);
CHK_ERR(err, "listen");

Creating and Setting Up the Socket (on the SSL Client)

On the client, you must create a TCP/IP socket and attempt to connect to the server with this socket. To establish a connection to the specified server, the TCP/IP connect() function is used. If the function succeeds, the socket passed to the connect() function as a first argument can be used for data communication over the connection.

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
CHK_ERR(sock, "socket"); memset (&server_addr, '\0', sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(s_port); /* Server Port number */
server_addr.sin_addr.s_addr = inet_addr(s_ipaddr); /* Server IP */

err = connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr));
CHK_ERR(err, "connect");

Establishing a TCP/IP Connection (on the SSL Server)

To accept an incoming connection request and to establish a TCP/IP connection, the SSL server needs to call the accept() function. The socket created with this function is used for the data communication between the SSL client and server. For example:

sock = accept(listen_sock, (struct sockaddr*)&sa_cli, &client_len);
BIO_printf(bio_c_out, "Connection from %lx, port %x\n",
sa_cli.sin_addr.s_addr, sa_cli.sin_port);c

Setting Up the Socket/Socket BIO in the SSL Structure

After you create the SSL structure and the TCP/IP socket (sock), you must configure them so that SSL data communication with the SSL structure can be performed automatically through the socket.

The following code fragments show the various ways to assign sock to ssl. The simplest way is to set the socket directly into the SSL structure, as follows:

SSL_set_fd(ssl, sock);

A better way is to use a BIO structure, which is the I/O abstraction provided by OpenSSL. This way is preferable because BIO hides details of an underlying I/O. As long as a BIO structure is set up properly, you can establish SSL connections over any I/O.

The following two examples demonstrate how to create a socket BIO and set it into the SSL structure.

sbio=BIO_new(BIO_s_socket());
BIO_set_fd(sbio, sock, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);

In the following example, the BIO_new_socket() API creates a socket BIO in which the TCP/IP socket is assigned, and the SSL_set_bio() API assigns the socket BIO into the SSL structure. The following two lines of code are equivalent to the preceding three lines:

sbio = BIO_new_socket(socket, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);NOTE: If there is already a BIO connected to sslBIO_free() is called (for both the reading and writing side, if different).

SSL Handshake

The SSL handshake is a complicated process that involves significant cryptographic key exchanges. However, the handshake can be completed by callingSSL_accept() on the SSL server and SSL_connect() on the SSL client.

SSL Handshake on the SSL Server

The SSL_accept() API waits for an SSL handshake initiation from the SSL client. Successful completion of this API means that the SSL handshake has been completed.

err = SSL_accept(ssl);

SSL Handshake on the SSL Client

The SSL client calls the SSL_connect() API to initiate an SSL handshake. If this API returns a value of 1, the handshake has completed successfully. The data can now be transmitted securely over this connection.

err = SSL_connect(ssl);

Performing an SSL Handshake with SSL_read and SSL_write (Optional)

Optionally, you can call SSL_write() and SSL_read() to complete the SSL handshake as well as perform SSL data exchange. With this approach, you must callSSL_set_accept_state() before you callSSL_read() on the SSL server. You must also callSSL_set_connect_state()before you callSSL_write() on the client. For example:

/* When SSL_accept() is not called, SSL_set_accept_state() */
/* must be called prior to SSL_read() */
SSL_set_accept_state(ssl);

/* When SSL_connect() is not called, SSL_set_connect_state() */
/* must be called prior to X SSL_write() */
SSL_set_connect_state(ssl);

Obtaining a Peer Certificate (Optional)

Optionally, after the SSL handshake, you can obtain a peer certificate by callingSSL_get_peer_certificate(). This API is often used for straight certificate verification, such as checking certificate information (for example, the common name and expiration date).

peer_cert = SSL_get_peer_certificate(ssl);

Transmitting SSL Data

After the SSL handshake is completed, data can be transmitted securely over the established SSL connection. SSL_write() and SSL_read() are used for SSL data transmission, just as write() and read() orsend() and recv() are used for an ordinary TCP/IP connection.

Sending Data

To send data over the SSL connection, callSSL_write(). The data to be sent is stored in the buffer specified as a second argument. For example:

err = SSL_write(ssl, wbuf, strlen(wbuf));

Receiving Data

To read data sent from the peer over the SSL connection, call SSL_read(). The received data is stored in the buffer specified as a second argument. For example:

err = SSL_read(ssl, rbuf, sizeof(rbuf)-1);

Using BIOs for SSL Data Transmission (Optional)

Instead of using SSL_write() and SSL_read(), you can transmit data by calling BIO_puts() andBIO_gets(), and BIO_write() and BIO_read(), provided that a buffer BIO is created and set up as follows:

BIO *buf_io, *ssl_bio;
char rbuf[READBUF_SIZE];
char wbuf[WRITEBUF_SIZE]

buf_io = BIO_new(BIO_f_buffer()); /* create a buffer BIO */
ssl_bio = BIO_new(BIO_f_ssl()); /* create an ssl BIO */
BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE); /* assign the ssl BIO to SSL */
BIO_push(buf_io, ssl_bio); /* add ssl_bio to buf_io */

ret = BIO_puts(buf_io, wbuf);
/* Write contents of wbuf[] into buf_io */
ret = BIO_write(buf_io, wbuf, wlen);
/* Write wlen-byte contents of wbuf[] into buf_io */

ret = BIO_gets(buf_io, rbuf, READBUF_SIZE);
/* Read data from buf_io and store in rbuf[] */
ret = BIO_read(buf_io, rbuf, rlen);
/* Read rlen-byte data from buf_io and store rbuf[] */

Closing an SSL Connection

When you close an SSL connection, the SSL client and server send close_notify messages to notify each other of the SSL closure. You use the SSL_shutdown() API to send the close_notify alert to the peer.

The shutdown procedure consists of two steps:

Sending a close_notify shutdown alert

Receiving a close_notify shutdown alert from the peer

The following rules apply to closing an SSL connection:

Either party can initiate a close by sending aclose_notify alert.

Any data received after sending a closure alert is ignored.

Each party is required to send a close_notifyalert before closing the write side of the connection.

The other party is required both to respond with aclose_notify alert of its own and to close down the connection immediately, discarding any pending writes.

The initiator of the close is not required to wait for the responding close_notify alert before closing the read side of the connection.

The SSL client or server that initiates the SSL closure calls SSL_shutdown() either once or twice. If it calls the API twice, one call sends the close_notify alert and one call receives the response from the peer. If the initator calls the API only once, the initiator does not receive the close_notify alert from the peer. (The initiator is not required to wait for the responding alert.)

The peer that receives the alert calls SSL_shutdown() once to send the alert to the initiating party.

Resuming an SSL Connection

You can reuse the information from an already established SSL session to create a new SSL connection. Because the new SSL connection is reusing the same master secret, the SSL handshake can be performed more quickly. As a result, SSL session resumption can reduce the load of a server that is accepting many SSL connections.

Perform the following steps to resume an SSL session on the SSL client:

Start the first SSL connection. This also creates an SSL session.

ret = SSL_connect(ssl)
(Use SSL_read() / SSL_write() for data communication
over the SSL connection)

Save the SSL session information.

sess = SSL_get1_session(ssl);
/* sess is an SSL_SESSION, and ssl is an SSL */

Shut down the first SSL connection.

SSL_shutdown(ssl);

Create a new SSL structure.

ssl = SSL_new(ctx);

Set the SSL session to a new SSL session before calling SSL_connect().

SSL_set_session(ssl, sess);
err = SSL_connect(ssl);

Start the second SSL connection with resumption of the session.

ret = SSL_connect(ssl)
(Use SSL_read() / SSL_write() for data communication
over the SSL connection)

If the SSL client calls SSL_get1_session() andSSL_set_session(), the SSL server can accept a new SSL connection using the same session without calling special APIs to resume the session. The server does this by following the steps discussed in "Creating and Setting Up the SSL Structure ""Setting Up the TCP/IP Connection""Setting Up the Socket/Socket BIO in the SSL Structure""SSL Handshake", and "Transmitting SSL Data".

NOTE: Calling SSL_free() results in the failure of the SSL session to resume, even if you saved the SSL session with SSL_get1_session().

Renegotiating the SSL Handshake

SSL renegotiation is a new SSL handshake over an already established SSL connection. Because the renegotiation messages (including types of ciphers and encryption keys) are encrypted and then sent over the existing SSL connection, SSL renegotiation can establish another SSL session securely. SSL renegotiation is useful in the following situations, once you have established an ordinary SSL session:

When you require client authentication

When you are using a different set of encryption and decryption keys

When you are using a different set of encryption and hashing algorithms

SSL renegotiation can be initiated by either the SSL client or the SSL server. Initiating an SSL renegotiation on the client requires a different set of APIs (on both the initiating SSL client and the accepting server) from the APIs required for the initiation on the SSL server (in this case, on the initiating SSL server and the accepting SSL client).

RSS

Categories

Followers

Blog Archive

rTechIndia

RtechIndia->technology ahead

rtech

rtechindia

RtechIndia

Go rtechindia

Go rtechindia

RtechIndia

Friday 14 November 2014

A complete guide to Openssl command line programming

  First steps

OpenSSL is a C library that implements the main cryptographic operations like symmetric encryption, public-key encryption, digital signature, hash functions and so on... OpenSSL also implements obviously the famous Secure Socket Layer (SSL) protocol. OpenSSL is avaible for a wide variety of platforms. The source code can be downloaded from www.openssl.org. A windows distribution can be foundhere. This tutorial shows some basics funcionalities of the OpenSSL command line tool. After the installation has been completed you should able to check for the version.

> openssl version OpenSSL 0.9.7e 25 Oct 2004

OpenSSL has got many commands. Here is the way to list them:

> openssl list-standard-commands asn1parse ca ciphers crl crl2pkcs7 ...

Let's see a brief description of each command:

ca To create certificate authorities.dgst To compute hash functions.enc To encrypt/decrypt using secret key algorithms. It is possible to generate using a password or directly a secret key stored in a file.genrsa This command permits to generate a pair of public/private key for the RSA algorithm.password Generation of "hashed passwords".pkcs12 Tools to manage information according to the PKCS #12 standard.pkcs7 Tools to manage information according to the PKCS #7 standard.rand Generation of pseudo-random bit strings.rsa RSA data management.rsautl To encrypt/decrypt or sign/verify signature with RSA.verify Checkings for X509.x509 Data managing for X509.

2  Secret key encryption algorithms

OpenSSL implements numerous secret key algorithms. To see the complete list:

> openssl list-cipher-commands aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc aes-256-ecb base64 ...

The list contains the algorithm base64which is a way to code binary information with alphanumeric characters. It is not really a secret key algorithm as there is no secret key! Let's see an example:

> touch number.txt > echo "123456789" > number.txt > openssl enc -base64 -in number.txt MTIzNDU2Nzg5Cg==

But indeed we really want to use secret key algorithm to protect our information, don't we? So, if I want for example to encrypt the text "I love OpenSSL!" with the AES algorithm using CBC mode and a key of 256 bits, I simply write:

> touch plain.txt > echo "I love OpenSSL!" > plain.txt > openssl enc -aes-256-cbc -in plain.txt -out encrypted.bin enter aes-256-cbc encryption password: hello Verifying - enter aes-256-cbc encryption password: hello

The secret key of 256 bits is computed from the password. Note that of course the choice of password "hello" is really INSECURE! Please take the time to choose a better password to protect your privacy! The output fileencrypted.bin is binary.If I want to decrypt this file I write:

> openssl enc -aes-256-cbc -d -in encrypted.bin -pass pass:hello I love OpenSSL!

3  Public Key Cryptography

To illustrate how OpenSSL manages public key algorithms we are going to use the famous RSA algorithm. Other algorithms exist of course, but the principle remains the same.

3.1  Key generation

First we need to generate a pair of public/private key. In this example we create a pair of RSA key of 1024 bits.

> openssl genrsa -out key.pem 1024 Generating RSA private key, 1024 bit long modulus .............................++++++ ................................................................++++++ e is 65537 (0x10001)

The generated file has got both public and private key. Obviously the private key must be kept in a secure place, or better must be encrypted. But before let's have a look at the file key.pem. The private key is coded using the Privacy Enhanced Email (PEM) standard.

> cat key.pem -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQC7iXTZ+DVO6jzjUMzJKij53vHd0+43ksK7A/gevHpbAGpLyhTE dpqFlcYYjIs6Vi/rFzb2rF3GbEtbOC+FQzMpmCE2ISNp2FgK2lX8nVTY6KQb9tBZ /Nmxyd3Sle2BIe05/ETbOgH7AG7jQiPJTBLen1yfEI/qXRbZWtBj2pLnlQIDAQAB ... IfVV1RrKWZTXFMGHXIXEAM+x1/xsvJcmcpEA9+71Tj45tA== -----END RSA PRIVATE KEY-----

The next line allows to see the details of the RSA key pair (modulus, public and private exponent between others).

> openssl rsa -in key.pem -text -noout Private-Key: (1024 bit) modulus: 00:bb:89:74:d9:f8:35:4e:ea:3c:e3:50:cc:c9:2a: ... 6e:e3:42:23:c9:4c:12:de:9f:5c:9f:10:8f:ea:5d: 16:d9:5a:d0:63:da:92:e7:95 publicExponent: 65537 (0x10001) privateExponent: 00:94:df:e7:ed:69:47:18:60:86:f9:85:99:2c:50: ... 81:ef:b1:28:63:bb:fc:70:de:52:3a:08:69:c9:9e: 75:d8:7e:8b:39:13:ab:24:39 prime1: 00:f2:18:f9:0d:62:fc:af:fb:df:10:23:d9:e4:b4: ... 10:f8:ca:9c:64:a1:42:ec:2f:4a:7f:7c:59:57:1c: be:33:09:95:d3 prime2: 00:c6:4e:66:2a:11:2c:42:fb:69:30:9a:c3:8b:57: ... d0:fc:50:7d:da:8c:51:2d:02:53:5b:d1:e9:4d:cc: 3b:7b:9a:a3:f7 exponent1: 15:be:44:6f:fd:59:f0:7c:50:96:64:81:e7:56:8f: ... 6e:48:d4:2e:fd:84:c3:2d:a4:25:3b:07:d3:19:13: c4:05:b2:5d exponent2: 00:94:59:63:fe:46:58:89:47:50:da:c6:7c:50:8a: ... 05:18:2c:12:ea:62:9b:fb:82:c8:df:60:ba:1a:b4: 15:2f:93:70:e3 coefficient: 00:9f:3c:71:db:ba:2a:20:5f:8a:7a:f0:99:e7:f0: ... c4:00:cf:b1:d7:fc:6c:bc:97:26:72:91:00:f7:ee: f5:4e:3e:39:b4

The -noout option allows to avoid the display of the key in base 64 format. Numbers in hexadecimal format can be seen (except the public exponent by default is always 65537 for 1024 bit keys): the modulus, the public exponent, the private, the two primes that compose the modules and three other numbers that are use to optimize the algorithm.

So now it's time to encrypt the private key:

> openssl rsa -in key.pem -des3 -out enc-key.pem writing RSA key Enter PEM pass phrase: Verifying - Enter PEM pass phrase:

The key file will be encrypted using a secret key algorithm which secret key will be generated by a password provided by the user. In this example the secret key algorithm is triple des (3-des). The private key alone is not of much interest as other users need the public key to be able to send you encrypted messages (or check if a piece of information has been signed by you). So let's extract the public from the filekey.pem

> openssl rsa -in key.pem -pubout -out pub-key.pem

3.2  Encryption

We are ready to perform encryption or produce digital signature.

> openssl rsautl -encrypt -in <input_file> -inkey <llave> \ -out <output_file>

Where:

input_file is the file to encrypt. This file must no be longer that 116 bytes =928 bits because RSA is a block cipher, and this command is low level command, i.e. it does not do the work of cutting your text in piece of 1024 bits (less indeed because a few bits are used for special purposes.)key File that contains the public key. If this file contains only the public key (not both private and public), then the option -pubin must be used.output_file the encrypted file.

To decrypt only replace -encrypt by -decrypt, and invert the input / output file as for decryption the input is the encrypted text, and the output the plain text.

3.3  Digital signatures

The next step is to be create a digital signature and to verify it. It is not very efficient to sign a big file using directly a public key algorithm. That is why first we compute the digest of the information to sign. Note that in practice things are a bit more complex. The security provided by this scheme (hashing and then signing directly using RSA) is not the same (is less in fact) than signing directly the whole document with the RSA algorithm. The scheme used in real application is called RSA-PSS which is efficient and proven to keep the best level of security.

> openssl dgst -<hash_algorithm> -out <digest> <input_file>

Where:

hash_algorithm is the hash algorithm used to compute the digest. Among the available algorithm there are:SHA-1 (option -sha1 which computes a 160 bits digests), MD5(option -md5) with 128 bits output length andRIPEMD160 (option -ripemd160) with 160 bits output length.digest is the file that contains the result of the hash application oninput_file.input_file file that contains the data to be hashed.

This command can be used to check the hash values of some archive files like the openssl source code for example. To compute the signature of the digest:

> openssl rsautl -sign -in <digest> -out <signature> -inkey <key>

To check to validity of a given signature:

> openssl rsautl -verify -in <signature> -out <digest> \ -inkey <key> -pubin

-pubin is used like before when the key is the public one, which is natural as we are verifying a signature.To complete the verification, one needs to compute the digest of the input file and to compare it to the digest obtained in the verification of the digital signature.

4  Public Key Infrastructure

4.1  What is a PKI? (in short)

4.1.1  The Problem: Man in the Middle Attack

One of the major breakthrough of public key cryptography is to solve the problem of key distribution. Secret key cryptography supposes the participants already agreed on a common secret. But how do they manage this in practice? Sending the key through an encrypted channel seems the more natural and practical solution but once again we need a common secret key to do this. With public key cryptography things are a lot simpler: if I want to send a message to Bob, I only need to find Bob's public key (on his homepage, on a public key directory ...) encrypt the message using this key and send the result to Bob. Then Bob using his own private key can recover the plain text. However a big problem remains. What happens if a malicious person called The Ugly makes me believe that the public key he owns is in fact Bob's one? Simply I will send an encrypted message using The Ugly's public key thinking I'm communicating with Bob. The Ugly will receive the message, decrypt it, and will then encrypt the plaintext with Bob's (real) public key. Bob will receive the encrypted message, will answer probably with another encrypted message using The Ugly's public key (who once again managed to convince Bob, this public key belongs to me). Afterwards The Ugly will decrypt the message, reencrypt it with my public key, so I will really receive the Bob's answer. Indeed I will be communicating with Bob, but without confidentiality. This attack is called "Man in the middle Attack", where the man is of course The Ugly of our little story. So we need a mechanism to associate in a trustworthy way a public key to the identity of a person (name, identity card number ...). One of this mechanism is implemented in PGP. The idea is that every one builds his own net of trust, by having a list of trusted public keys, and by sharing these keys. The other solution is the use of a PKI.

4.1.2  A solution: Public Key Infrastructure

Public Key Infrastructure is a centralized solution to the problem of trust. The idea is to have a trusted entity (organization, corporation) that will do the job of certifying that a given public key belongs really to a given person. This person must be identified by his name, address and other useful information that may allow to know who this person is. Once this work his done, the PKI emits a public certificate for this person. This certificate contains between others:

All the information needed to identify this person (name, birth date,...).The public key of this person.The date of creation of the certificate.The date of revocation of the certificate (a certificate is valid during 1 or 3 years in practice).The digital signature of all this previous information emitted by the PKI.

So now, if I want to send a private message to Bob, I can ask for his certificate. When I received the certificate, I must check the signature of the PKI who emitted it and for the date of revocation. If verifications pass then I can safely use the public key of the certificate to communicate with Bob. Indeed, in practice the way a PKI works is much more complicated. For example sometimes a certificate may be revocated before the date of end of validity has been reached. So a kind of list of revocated certificated has to be maintained and accessed every time you want to use a certificate. The problem of certificate revocation is really difficult in practice.

4.2  My first PKI with OpenSSL

This section will show how to create your own small PKI. Obviously this is only a tutorial and you SHOULD NOT base a real application only on the information contained in this page!

4.2.1  openssl.cnf: let's configure a few things

Before starting to create certificates it is necesarry to configure a few parameters. That can be done editing the file openssl.cnf the is usually located in the bin directory of OpenSSL. This file looks like this:

openssl.cnf

# # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca' and 'req'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = "/home/philippe/openssl" # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. #unique_subject = no # Set to 'no' to allow creation of # several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/crl.pem # The current CRL private_key = $dir/private/cakey.pem # The private key RANDFILE = $dir/private/.rnd # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. # copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crlnumber must also be commented out to leave a V1 CRL. # crl_extensions = crl_ext default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional ....

If you want to simplify your work you should use the default openssl.cnf file with the demoCA directory (also in the bindirectory of OpenSSL) that contains all the necesarry files. You should ensure that all the directories are valid ones, and that the private key that will be created in the next section (cakey.pem) is well linked. Also check of the presence of a file .rand or .rnd that will bee created with cakey.pem. For the certificates database you can create an empty file index.txt. Also create a serial file serial with the text for example011E. 011E is the serial number for the next certificate.

4.2.2  PKI creation

First we must create a certificate for the PKI that will contain a pair of public / private key. The private key will be used to sign the certificates.

> openssl req -new -x509 -keyout cakey.pem -out cacert.pem

The pair of keys will be in cakey.pem and the certificate (which does NOT contain the private key, only the public) is saved in cacert.pem. During the execution you will be asked for many informations about your organization (name, country, and so on ...). The private key contained in cakey.pem is encrypted with a password. This file should be put in a very secure place (although it is encrypted). -x509 refers to a standard that defines how information of the certificate is coded. It can be useful to export the certificate of the PKI in DER format as to be able to load it into your browser.

> openssl x509 -in cacert.pem -outform DER -out cacert.der

4.2.3  Creation of a user certificate

Now the PKI has got its own pair of keys and certificate, let's suppose a user wants to get a certificate from the PKI. To do so he must create a certificate request, that will contain all the information needed for the certificate (name, country, ... and the public key of the user of course). This certificate request is sent to the PKI.

> openssl req -new -keyout userkey.pem -out usercert-req.pem

Note this command will create the pair of keys and the certificate request. The pair of keys is saved in userkey.pem and the certificate request in usercert-req.pem. The PKI is ready for the next step: signing the certificate request to obtain the user's certificate.

> openssl ca -in usercert-req.pem -out usercert.pem Using configuration from /usr/local/bin/openssl/openssl.cnf Loading 'screen' into random state - done Enter pass phrase for demoCA/private/cakey.pem: Check that the request matches the signature Signature ok Certificate Details: Serial Number: 286 (0x11e) Validity Not Before: Jan 19 12:52:37 2008 GMT Not After : Jan 18 12:52:37 2009 GMT Subject: countryName = CL stateOrProvinceName = RM organizationName = littlecryptographer commonName = John Smith emailAddress = jsmith@hello.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 34:F0:61:38:87:68:C7:25:93:86:90:35:32:40:4F:... X509v3 Authority Key Identifier: keyid:FE:CB:56:0B:28:EB:2A:E9:C7:9C:EA:E5:3A:... Certificate is to be certified until Jan 18 12:52:37 2009 GMT (365 days) Sign the certificate? [y/n]:y

usercert.pem is the public certificate signed by the PKI. If you want to import this certificate into your browser you need to convert it in PKCS12 format:

> openssl pkcs12 -export -in usercert.pem -inkey userkey.pem > usercert.p12

Hands on OPENSSL programming APIs

This section demonstrates the implementation of a simple SSL client and server program using OpenSSL APIs.

Although SSL client and server programs might differ in their setup and configuration, their common internal procedures can be summarized in Figure 4-8 " Overview of SSL Application with OpenSSL APIs". These procedures are discussed in the following sections.

Figure 4-8  Overview of SSL Application with OpenSSL APIs

Initializing the SSL Library

Before you can call any other OpenSSL APIs in the SSL application programs, you must perform initialization using the following SSL APIs.

SSL_library_init(); /* load encryption & hash algorithms for SSL */
SSL_load_error_strings(); /* load the error strings for good error reporting */

The SSL_library_init() API registers all ciphers and hash algorithms used in SSL APIs. The encryption algorithms loaded with this API are DES-CBC, DES-EDE3-CBC, RC2 and RC4 (IDEA and RC5 are not available in HP SSL for OpenVMS); and the hash algorithms are MD2, MD5, and SHA. TheSSL_library_init() API has a return value that is always 1 (integer).

SSL applications should call theSSL_load_error_strings() API. This API loads error strings for SSL APIs as well as for Crypto APIs. Both SSL and Crypto error strings need to be loaded because many SSL applications call some Crypto APIs as well as SSL APIs.

Creating and Setting Up the SSL Context Structure (SSL_CTX)

The first step after the intialization is to choose an SSL/TLS protocol version. Do this by creating anSSL_METHOD structure with one of the following APIs. The SSL_METHOD structure is then used to create anSSL_CTX structure with the SSL_CTX_new() API.

For every SSL/TLS version, there are three types of APIs to create an SSL_METHOD structure: one for both client and server, one for server only, and one for client only. SSLv2, SSLv3, and TLSv1 APIs correspond with the same name protocols. Table 4-2 " Types of APIs for SSL_METHOD Creation" shows the types of APIs.

Table 4-2  Types of APIs for SSL_METHOD Creation

Protocol typeFor combined client and serverFor a dedicated serverFor a dedicated clientSSLv2SSLv2_method()SSLv2_server_ method()SSLv2_client_ method()SSLv3SSLv3_method()SSLv3_server_ method()SSLv3_client_ method()TLSv1TLSv1_method()TLSv1_server_ method()TLSv1_client_ method()SSLv23SSLv23_method()SSLv23_server_ method()SSLv23_client_ method()

 NOTE: There is no SSL protocol version named SSLv23. The SSLv23_method() API and its variants choose SSLv2, SSLv3, or TLSv1 for compatibility with the peer.

Consider the incompatibility among the SSL/TLS versions when you develop SSL client/server applications. For example, a TLSv1 server cannot understand a client-hello message from an SSLv2 or SSLv3 client. The SSLv2 client/server recognizes messages from only an SSLv2 peer. TheSSLv23_method() API and its variants may be used when the compatibility with the peer is important. An SSL server with the SSLv23 method can understand any of the SSLv2, SSLv3, and TLSv1 hello messages. However, the SSL client using the SSLv23 method cannot establish connection with the SSL server with the SSLv3/TLSv1 method because SSLv2 hello message is sent by the client.

The SSL_CTX_new() API takes the SSL_METHODstructure as an argument and creates an SSL_CTXstructure.

In the following example, an SSL_METHOD structure that can be used for either an SSLv3 client or SSLv3 server is created and passed to SSL_CTX_new(). TheSSL_CTX structure is initialized for SSLv3 client and server.

meth = SSLv3_method();
ctx = SSL_CTX_new(meth);

Setting Up the Certificate and Key

"Certificates for SSL Applications" discussed how the SSL client and server programs require you to set up appropriate certificates. This setup is done by loading the certificates and keys into the SSL_CTX or SSL structures. The mandatory and optional certificates are as follows:

For the SSL server:

Server's own certificate (mandatory)CA certificate (optional)

For the SSL client:

CA certificate (mandatory)Client's own certificate (optional)

=

Loading a Certificate (Client/Server Certificate)

Use the SSL_CTX_use_certificate_file() API to load a certificate into an SSL_CTX structure. Use theSSL_use_certificate_file() API to load a certificate into an SSL structure. When the SSLstructure is created, the SSL structure automatically loads the same certificate that is contained in theSSL_CTX structure. Therefore, you onlyneed to call theSSL_use_certificate_file() API for the SSLstructure only if it needs to load a different certificate than the default certificate contained in the SSL_CTXstructure.

Loading a Private Key

The next step is to set a private key that corresponds to the server or client certificate. In the SSL handshake, a certificate (which contains the public key) is transmitted to allow the peer to use it for encryption. The encrypted message sent from the peer can be decrypted only using the private key. You must preload the private key that was created with the public key into the SSLstructure.

The following APIs load a private key into an SSL orSSL_CTX structure:

SSL_CTX_use_PrivateKey()

SSL_CTX_use_PrivateKey_ASN1()

SSL_CTX_use_PrivateKey_file()

SSL_CTX_use_RSAPrivateKey()

SSL_CTX_use_RSAPrivateKey_ASN1()

SSL_CTX_use_RSAPrivateKey_file()

SSL_use_PrivateKey()

SSL_use_PrivateKey_ASN1()

SSL_use_PrivateKey_file()

SSL_use_RSAPrivateKey()

SSL_use_RSAPrivateKey_ASN1()

SSL_use_RSAPrivateKey_file()

Loading a CA Certificate

To verify a certificate, you must first load a CA certificate (because the peer certificate is verified against a CA certificate). TheSSL_CTX_load_verify_locations() API loads a CA certificate into the SSL_CTX structure.

The prototype of this API is as follows:

int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
const char *CApath);

The first argument, ctx, points to an SSL_CTX structure into which the CA certificate is loaded. The second and third arguments, CAfile and CApath, are used to specify the location of the CA certificate. When looking up CA certificates, the OpenSSL library first searches the certificates in CAfile, then those in CApath.

The following rules apply to the CAfile and CApatharguments:

If the certificate is specified by CAfile (the certificate must exist in the same directory as the SSL application), specify NULL for CApath.

To use the third argument, CApath, specify NULL for CAfile. You must also hash the CA certificates in the directory specified by CApath. Use the Certificate Tool (described in Chapter 3) to perform the hashing operation.

Setting Up Peer Certificate Verification

The CA certificate loaded in the SSL_CTX structure is used for peer certificate verification. For example, peer certificate verification on the SSL client is performed by checking the relationships between the CA certificate (loaded in the SSL client) and the server certificate.

For successful verification, the peer certificate must be signed with the CA certificate directly or indirectly (a proper certificate chain exists). The certificate chain length from the CA certificate to the peer certificate can be set in the verify_depth field of the SSL_CTXandSSL structures. (The value in SSL is inherited fromSSL_CTX when you create an SSL structure using theSSL_new() API). Setting verify_depth to 1 means that the peer certificate must be directly signed by the CA certificate.

The SSL_CTX_set_verify() API allows you to set the verification flags in the SSL_CTX structure and a callback function for customized verification as its third argument. (Setting NULL to the callback function means the built-in default verification function is used.) In the second argument of SSL_CTX_set_verify(), you can set the following macros:

SSL_VERIFY_NONE

ì

SSL_VERIFY_PEER

SSL_VERIFY_FAIL_IF_NO_PEER_CERT

SSL_VERIFY_CLIENT_ONCE

The SSL_VERIFY_PEER macro can be used on both SSL client and server to enable the verification. However, the subsequent behaviors depend on whether the macro is set on a client or a server. For example:

/* Set a callback function (verify_callback) for peer certificate */
/* verification */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
/* Set the verification depth to 1 */
SSL_CTX_set_verify_depth(ctx,1);

You can verify a peer certificate in another, less common way - by using theSSL_get_verify_result() API. This method allows you to obtain the peer certificate verification result without using the SSL_CTX_set_verify() API.

Call the following two APIs before you call theSSL_get_verify_result() API:

Call SSL_connect() (in the client) or SSL_accept() (in the server) to perform the SSL handshake. Certificate verification is performed during the handshake. SSL_get_verify_result() cannot obtain the result before the verification process.

Call SSL_get_peer_certificate() to explicitly obtain the peer certificate. The X509_V_OK macro value is returned when a peer certificate is not presented as well as when the verification succeeds.

The following code shows how to useSSL_get_verify_result() in the SSL client:

SSL_CTX_set_verify_depth(ctx, 1);
err = SSL_connect(ssl);
if(SSL_get_peer_certificate(ssl) != NULL)
{
if(SSL_get_verify_result(ssl) == X509_V_OK) BIO_printf(bio_c_out, "client verification with SSL_get_verify_result()
succeeded.\n");
else{

BIO_printf(bio_err, "client verification with SSL_get_verify_result()
failed.\n");

exit(1);
}
}
else
BIO_printf(bio_c_out, -the peer certificate was not presented.\n-);

Example 1: Setting Up Certificates for the SSL Server

The SSL protocol requires that the server set its own certificate and key. If you want the server to conduct client authentication with the client certificate, the server must load a CA certificate so that it can verify the client-s certificate.

The following example shows how to set up certificates for the SSL server:

/* Load server certificate into the SSL context */
if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT,
SSL_FILETYPE_PEM) <= 0) } ERR_print_errors(bio_err); /* ==
ERR_print_errors_fp(stderr); */
exit(1);
}

/* Load the server private-key into the SSL context */
if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY,
SSL_FILETYPE_PEM) <= 0) { ERR_print_errors(bio_err); /* ==
ERR_print_errors_fp(stderr); */
exit(1);
}

/* Load trusted CA. */
if (!SSL_CTX_load_verify_locations(ctx,CA_CERT,NULL)) {
ERR_print_errors(bio_err); /* ==
ERR_print_errors_fp(stderr); */
exit(1);
}

/* Set to require peer (client) certificate verification */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
/* Set the verification depth to 1 */
SSL_CTX_set_verify_depth(ctx,1);

Example 2: Setting Up Certificates for the SSL Client

Generally, the SSL client verifies the server certificate in the process of the SSL handshake. This verification requires the SSL client to set up its trusting CA certificate. The server certificate must be signed with the CA certificate loaded in the SSL client in order for the server certificate verification to succeed.

The following example shows how to set up certificates for the SSL client:

/*----- Load a client certificate into the SSL_CTX structure -----*/
if(SSL_CTX_use_certificate_file(ctx,CLIENT_CERT,
SSL_FILETYPE_PEM) <= 0){
ERR_print_errors_fp(stderr);
exit(1);
}

/*----- Load a private-key into the SSL_CTX structure -----*/
if(SSL_CTX_use_PrivateKey_file(ctx,CLIENT_KEY,
SSL_FILETYPE_PEM) <= 0){
ERR_print_errors_fp(stderr);
exit(1);
}

/* Load trusted CA. */
if (!SSL_CTX_load_verify_locations(ctx,CA_CERT,NULL)) {
ERR_print_errors_fp(stderr);
exit(1);
}

Creating and Setting Up the SSL Structure

Call SSL_new() to create an SSL structure. Information for an SSL connection is stored in the SSL structure. The protocol for the SSL_new() API is as follows:

ssl = SSL_new(ctx);

A newly created SSL structure inherits information from the SSL_CTX structure. This information includes types of connection methods, options, verification settings, and timeout settings. No additional settings are required for the SSL structure if the appropriate initialization and configuration have been done for theSSL_CTX structure.

You can modify the default values in the SSL structure using SSL APIs. To do this, use variants of the APIs that set attributes of the SSL_CTX structure. For example, you can use SSL_CTX_use_certificate() to load a certificate into an SSL_CTX structure, and you can useSSL_use_certificate() to load a certificate into anSSL structure.

Setting Up the TCP/IP Connection

Although SSL works with some other reliable protocols, TCP/IP is the most common transport protocol used with SSL.

The following sections describe how to set up TCP/IP for the SSL APIs. This configuration is the same as in many other TCP/IP client/server application programs; it is not specific to SSL API applications. In these sections, TCP/IP is set up with the ordinary socket APIs, although it is also possible to use OpenVMS system services.

Creating and Setting Up the Listening Socket (on the SSL Server)

The SSL server needs two sockets as an ordinary TCP/IP server—one for the SSL connection, the other for detecting an incoming connection request from the SSL client.

In the following code, the socket() function creates a listening socket. After the address and port are assigned to the listening socket with bind(), thelisten() function allows the listening socket to handle an incoming TCP/IP connection request from the client.

listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
CHK_ERR(listen_sock, "socket");

memset(&sa_serv, 0, sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons(s_port); /* Server Port number */

err = bind(listen_sock, (struct sockaddr*)&sa_serv,sizeof(sa_serv));
CHK_ERR(err, "bind");

/* Receive a TCP connection. */
err = listen(listen_sock, 5);
CHK_ERR(err, "listen");

Creating and Setting Up the Socket (on the SSL Client)

On the client, you must create a TCP/IP socket and attempt to connect to the server with this socket. To establish a connection to the specified server, the TCP/IP connect() function is used. If the function succeeds, the socket passed to the connect() function as a first argument can be used for data communication over the connection.

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
CHK_ERR(sock, "socket"); memset (&server_addr, '\0', sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(s_port); /* Server Port number */
server_addr.sin_addr.s_addr = inet_addr(s_ipaddr); /* Server IP */

err = connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr));
CHK_ERR(err, "connect");

Establishing a TCP/IP Connection (on the SSL Server)

To accept an incoming connection request and to establish a TCP/IP connection, the SSL server needs to call the accept() function. The socket created with this function is used for the data communication between the SSL client and server. For example:

sock = accept(listen_sock, (struct sockaddr*)&sa_cli, &client_len);
BIO_printf(bio_c_out, "Connection from %lx, port %x\n",
sa_cli.sin_addr.s_addr, sa_cli.sin_port);c

Setting Up the Socket/Socket BIO in the SSL Structure

After you create the SSL structure and the TCP/IP socket (sock), you must configure them so that SSL data communication with the SSL structure can be performed automatically through the socket.

The following code fragments show the various ways to assign sock to ssl. The simplest way is to set the socket directly into the SSL structure, as follows:

SSL_set_fd(ssl, sock);

A better way is to use a BIO structure, which is the I/O abstraction provided by OpenSSL. This way is preferable because BIO hides details of an underlying I/O. As long as a BIO structure is set up properly, you can establish SSL connections over any I/O.

The following two examples demonstrate how to create a socket BIO and set it into the SSL structure.

sbio=BIO_new(BIO_s_socket());
BIO_set_fd(sbio, sock, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);

In the following example, the BIO_new_socket() API creates a socket BIO in which the TCP/IP socket is assigned, and the SSL_set_bio() API assigns the socket BIO into the SSL structure. The following two lines of code are equivalent to the preceding three lines:

sbio = BIO_new_socket(socket, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);NOTE: If there is already a BIO connected to sslBIO_free() is called (for both the reading and writing side, if different).

SSL Handshake

The SSL handshake is a complicated process that involves significant cryptographic key exchanges. However, the handshake can be completed by callingSSL_accept() on the SSL server and SSL_connect() on the SSL client.

SSL Handshake on the SSL Server

The SSL_accept() API waits for an SSL handshake initiation from the SSL client. Successful completion of this API means that the SSL handshake has been completed.

err = SSL_accept(ssl);

SSL Handshake on the SSL Client

The SSL client calls the SSL_connect() API to initiate an SSL handshake. If this API returns a value of 1, the handshake has completed successfully. The data can now be transmitted securely over this connection.

err = SSL_connect(ssl);

Performing an SSL Handshake with SSL_read and SSL_write (Optional)

Optionally, you can call SSL_write() and SSL_read() to complete the SSL handshake as well as perform SSL data exchange. With this approach, you must callSSL_set_accept_state() before you callSSL_read() on the SSL server. You must also callSSL_set_connect_state()before you callSSL_write() on the client. For example:

/* When SSL_accept() is not called, SSL_set_accept_state() */
/* must be called prior to SSL_read() */
SSL_set_accept_state(ssl);

/* When SSL_connect() is not called, SSL_set_connect_state() */
/* must be called prior to X SSL_write() */
SSL_set_connect_state(ssl);

Obtaining a Peer Certificate (Optional)

Optionally, after the SSL handshake, you can obtain a peer certificate by callingSSL_get_peer_certificate(). This API is often used for straight certificate verification, such as checking certificate information (for example, the common name and expiration date).

peer_cert = SSL_get_peer_certificate(ssl);

Transmitting SSL Data

After the SSL handshake is completed, data can be transmitted securely over the established SSL connection. SSL_write() and SSL_read() are used for SSL data transmission, just as write() and read() orsend() and recv() are used for an ordinary TCP/IP connection.

Sending Data

To send data over the SSL connection, callSSL_write(). The data to be sent is stored in the buffer specified as a second argument. For example:

err = SSL_write(ssl, wbuf, strlen(wbuf));

Receiving Data

To read data sent from the peer over the SSL connection, call SSL_read(). The received data is stored in the buffer specified as a second argument. For example:

err = SSL_read(ssl, rbuf, sizeof(rbuf)-1);

Using BIOs for SSL Data Transmission (Optional)

Instead of using SSL_write() and SSL_read(), you can transmit data by calling BIO_puts() andBIO_gets(), and BIO_write() and BIO_read(), provided that a buffer BIO is created and set up as follows:

BIO *buf_io, *ssl_bio;
char rbuf[READBUF_SIZE];
char wbuf[WRITEBUF_SIZE]

buf_io = BIO_new(BIO_f_buffer()); /* create a buffer BIO */
ssl_bio = BIO_new(BIO_f_ssl()); /* create an ssl BIO */
BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE); /* assign the ssl BIO to SSL */
BIO_push(buf_io, ssl_bio); /* add ssl_bio to buf_io */

ret = BIO_puts(buf_io, wbuf);
/* Write contents of wbuf[] into buf_io */
ret = BIO_write(buf_io, wbuf, wlen);
/* Write wlen-byte contents of wbuf[] into buf_io */

ret = BIO_gets(buf_io, rbuf, READBUF_SIZE);
/* Read data from buf_io and store in rbuf[] */
ret = BIO_read(buf_io, rbuf, rlen);
/* Read rlen-byte data from buf_io and store rbuf[] */

Closing an SSL Connection

When you close an SSL connection, the SSL client and server send close_notify messages to notify each other of the SSL closure. You use the SSL_shutdown() API to send the close_notify alert to the peer.

The shutdown procedure consists of two steps:

Sending a close_notify shutdown alert

Receiving a close_notify shutdown alert from the peer

The following rules apply to closing an SSL connection:

Either party can initiate a close by sending aclose_notify alert.

Any data received after sending a closure alert is ignored.

Each party is required to send a close_notifyalert before closing the write side of the connection.

The other party is required both to respond with aclose_notify alert of its own and to close down the connection immediately, discarding any pending writes.

The initiator of the close is not required to wait for the responding close_notify alert before closing the read side of the connection.

The SSL client or server that initiates the SSL closure calls SSL_shutdown() either once or twice. If it calls the API twice, one call sends the close_notify alert and one call receives the response from the peer. If the initator calls the API only once, the initiator does not receive the close_notify alert from the peer. (The initiator is not required to wait for the responding alert.)

The peer that receives the alert calls SSL_shutdown() once to send the alert to the initiating party.

Resuming an SSL Connection

You can reuse the information from an already established SSL session to create a new SSL connection. Because the new SSL connection is reusing the same master secret, the SSL handshake can be performed more quickly. As a result, SSL session resumption can reduce the load of a server that is accepting many SSL connections.

Perform the following steps to resume an SSL session on the SSL client:

Start the first SSL connection. This also creates an SSL session.

ret = SSL_connect(ssl)
(Use SSL_read() / SSL_write() for data communication
over the SSL connection)

Save the SSL session information.

sess = SSL_get1_session(ssl);
/* sess is an SSL_SESSION, and ssl is an SSL */

Shut down the first SSL connection.

SSL_shutdown(ssl);

Create a new SSL structure.

ssl = SSL_new(ctx);

Set the SSL session to a new SSL session before calling SSL_connect().

SSL_set_session(ssl, sess);
err = SSL_connect(ssl);

Start the second SSL connection with resumption of the session.

ret = SSL_connect(ssl)
(Use SSL_read() / SSL_write() for data communication
over the SSL connection)

If the SSL client calls SSL_get1_session() andSSL_set_session(), the SSL server can accept a new SSL connection using the same session without calling special APIs to resume the session. The server does this by following the steps discussed in "Creating and Setting Up the SSL Structure ""Setting Up the TCP/IP Connection""Setting Up the Socket/Socket BIO in the SSL Structure""SSL Handshake", and "Transmitting SSL Data".

NOTE: Calling SSL_free() results in the failure of the SSL session to resume, even if you saved the SSL session with SSL_get1_session().

Renegotiating the SSL Handshake

SSL renegotiation is a new SSL handshake over an already established SSL connection. Because the renegotiation messages (including types of ciphers and encryption keys) are encrypted and then sent over the existing SSL connection, SSL renegotiation can establish another SSL session securely. SSL renegotiation is useful in the following situations, once you have established an ordinary SSL session:

When you require client authentication

When you are using a different set of encryption and decryption keys

When you are using a different set of encryption and hashing algorithms

SSL renegotiation can be initiated by either the SSL client or the SSL server. Initiating an SSL renegotiation on the client requires a different set of APIs (on both the initiating SSL client and the accepting server) from the APIs required for the initiation on the SSL server (in this case, on the initiating SSL server and the accepting SSL client).