Security OpenSSL SSL Roberta Daidone roberta.daidone@iet.unipi.it
What are we going to do? Use BIO objects to create SSL connections. Create an SSL connection. Let the client authenticate the server and the server authenticate the client by means of certificates and CRLs. Use the SSL connection to send/receive a file on a secure channel.
SSL data structures #include <openssl/ssl.h> #include <openssl/x509v3.h> SSL connections rely on three relevant objects: SSL_METHOD implements an SSL functionality (i.e. the SSL protocol version) SSL_CTX a factory producing SSL connections SSL object created by an SSL_CTX object
SSL data structures OpenSSL provides the following well-known SSL_METHOD objects Format SSLv2_method SSLv2_client_method SSLv2_server_method SSLv3_method SSLv3_client_method SSLv3_server_method SSLv23_method SSLv23_client_method SSLv23_server_method TLSv1_method TLSv1_client_method TLSv1_server_method Comments Generic SSL Version 2 peer (unsafe) Generic SSL Version 2 client (unsafe) Generic SSL Version 2 server (unsafe) Generic SSL Version 3 peer (unsafe) Generic SSL Version 3 client (unsafe) Generic SSL Version 3 server (unsafe) Generic SSL/TLS peer (for compatibility) SSL/TLS client (for compatibility) SSL/TLS server (for compatibility) Generic TLS Version 1 peer (for UDP) TLS Version 1 client (for UDP) TLS Version 1 server (for UDP)
SSL data structures In order to make things work do NOT forget to call the following before the SSL_CTX_new(): int SSL_library_init(); int SSL_load_error_strings(); By using one of these SSL_METHOD objects we create an SSL_CTX object: SSL_CTX* SSL_CTX_new(); Just one context for all the SSL connections we make One to rule them all SSL_CTX allows to: set SSL protocol version set certificate info set certification verification requirements
SSL certificates preparation The certificates chain of trust can be incorporated in an SSL_CTX object by calling: int SSL_CTX_use_certificate_chain_file(SSL_CTX* ctx, const char* filename); This function loads the chain of certificates from the provided filename and loads it into the SSL_CTX. Returns 1 on success, 0 otherwise.
SSL certificates preparation The SSL_CTX must include the application s private key, which is the counterpart of the public key associated to the certificate we send to a peer when it asks for it. int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* filename, int type); 1 parameter is the SSL_CTX to be associated with the private key; 2 parameter is the name of the file containing the private key; 3 parameter is the format of the file containing the private key. SSL_FILETYPE_PEM is the best option for type, because it stores the encrypted version of the private key.
SSL certificates preparation Do NOT forget to setup the passphrase retrieval callback before the SSL_CTX_use_PrivateKey_file(); void SSL_CTX_set_default_passwd_cb(SSL_CTX* ctx, pem_password_cb* cb); void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX* ctx, void* input); If you specify NULL as cb, input can be your passphrase (DANGER!! Use it for toy exercises only).
SSL peer authentication setup We need to load in each verifying agent (i.e. client or server) a list of CAs we trust. As a consequence, we authenticate the peer if and only if his certificate is signed by a CA we trust. To load such a list we call the following: int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* CAfile, const char* CApath); Call this function with either 2 nd or 3 rd argument as NULL, but NOT both!! Since the CApath has some constraints about filenames and extensions, it is recommended to set it NULL and use CAfile instead.
SSL peer authentication setup The following sets the default path where the application looks for certificates if they are not in the current directory. It is the best way to store system-wide certificates: int SSL_CTX_set_default_verify_path(SSL_CTX* ctx); The default path for this function is the /usr/local/openssl directory. Last step for peer authentication setup is to load and verify CRLs. This step is supported by OpenSSL version >= 0.97. Please open a command prompt and do the following to verify you have a version that supports them: $openssl >version OpenSSL 0.98o 01 Jun 2010 >quit
SSL peer authentication setup Even if your OpenSSL manages CRLs, there is no documentation on how to do this. I would recommend you to use the following to retrieve the X509_STORE from the SSL_CTX and set it using the classical X509v3 functions we have studied for digital signature verification X509_STORE* SSL_CTX_get_cert_store(SSL_CTX* ctx); So you get a certificate store to be set to verify CRLs: retrieved from a certain file searched by a certain lookup method according to some verification policies
SSL peer authentication setup Once we have all info set in the SSL_CTX, we can set policies and functions to be used to verify SSL peers: void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, int (* verifiy_callback) (int, X509_STORE_CTX*)); It is OK to specify NULL as 3 rd possible values for mode: argument. The following are SSL_VERIFY_NONE ctx in server mode: no request for a certificate will be sent to the client. ctx in client mode: any certificate received from the server will be verified, but failure will not terminate the handshake. This flag should only be used by itself (i.e. not combined with other flags).
SSL peer authentication setup The following are possible values for mode: SSL_VERIFY_PEER ctx in server mode: a request for a certificate will be sent to the client. The client may opt to ignore the request, but if a certificate is sent back, it will be verified. If the verification fails, the handshake will be terminated immediately. ctx in client mode: if the server sends a certificate, it will be verified. If the verification fails, the handshake will be terminated immediately. Any other flags combined with this one in client mode are ignored. SSL_VERIFY_FAIL_IF_NO_PEER_CERT ctx in server mode: if SSL_VERIFY_PEER is set, this flag will cause the handshake to terminate immediately if no certificate is provided by the client. ctx NOT in server mode or SSL_VERIFY_PEER is NOT set: this flag is ignored.
SSL peer authentication setup The following is the last possible value for mode: SSL_VERIFY_CLIENT_ONCE ctx is in server mode: if SSL_VERIFY_PEER is set, this flag will prevent the server from requesting a certificate from the client in the case of a renegotiation. A certificate will still be requested during the initial handshake. ctx is NOT in server mode, or SSL_VERIFY_PEER is NOT set: this flag is ignored.
SSL peer authentication setup Finally we specify the maximum depth SSL can go into the certificates chain to verify a peer. In other words, how many certificates can there be between the provided certificate and the root CA I trust? void SSL_set_verify_depth(SSL_CTX* ctx, int depth); Now we can rely on our SSL_CTX settings to create SSL connections.
BIO objects BIO is a package that provides a powerful handling I/O. abstraction for #include<openssl/bio.h> BIO can be attached together in chains, read, written and mixed in a flexible manner. The following is to create a BIO: BIO* BIO_new(BIO_METHOD* type); The BIO_METHOD specifies for what purposes the BIO is used. The following is to change the BIO_METHOD of a BIO: int BIO_set(BIO* bio, BIO_METHOD* type);
BIO objects The following is to destroy a BIO: void BIO_free(BIO* bio); The following is to destroy a chain of a BIO objects: void BIO_free_all(BIO* bio); There are two kinds of BIO: SOURCE BIO are used for reading SINK BIO are used for writing Both of them need to be attached to a real I/O medium, a socket in our case: int BIO_set_fd (BIO* bio, int socket, int* method); Remember to specify BIO_s_socket() as BIO_METHOD in the BIO_new(). 3 rd argument can be either BIO_CLOSE or BIO_NOCLOSE
SSL connection setup Once you have SSL_CTX and a BIO connected to a socket, you just need to create an SSL connection, providing the context as input: SSL* SSL_new(SSL_CTX* ctx); Then you attach the newly created SSL object to the BIO: void SSL_set_bio(SSL* ssl, BIO* read_bio, BIO* write_bio); In this way we attach the ssl SSL connection to read_bio for reading and to write_bio for writing. Finally, we setup connection with the following: int SSL_accept(SSL* ssl); int SSL_connect(SSL* ssl); // for server // for clients
SSL usage The certificate of the peer is automatically sent through the socket (if you set the SSL_CTX behavior correctly). The following function is to retrieve the certificate provided by the peer: X509* SSL_get_peer_certificate(const SSL* ssl); Then you can verify it by means of classical methods you know. If certificate verification returns the X509_V_OK status, we can use the SSL connection for secure read and write: int SSL_read(SSL* ssl, void* buffer, int size); int SSL_write(SSL* ssl, void* buffer, int size); These functions rely on the SSL record size, which is 16KB. Insert these calls in a loop if you want to read contents of any size (i.e. greater than 16 KB).
To close an SSL connection: SSL usage int SSL_shutdown(SSL* ssl); int SSL_clear(SSL* ssl); // no errors happened // errors happened When compiling source code including SSL methods, use the lssl linking option: $ gcc Wall o <filename> <filename.ext> -lssl
Exercise File exchange through SSL connection. Client: Wants to upload some sensitive data to a server Creates an SSL connection with the server Authenticates the server, checking certificates and CRLs Server: Creates an SSL connection with each client Authenticates the client, checking certificates and CRLs The client uses the SSL connection to send a file to the server. The server receives and stores it. Remember to use BIOs and to connect them to a socket and an SSL object.