Universita' di Bologna, II Facolta' di Ingegneria Reti di Calcolatori Materiale didattico: annesso alla Lezione 1y OpenSSL - Tutorial N.B.: questo tutorial e' stato ottenuto per cut-and-paste di materiale contenuto nel sito: http://www.openssl.org/. At first the OpenSSL library must be initialized; see SSL_library_init(3). int SSL_library_init(void); SSL_library_init() initializes the SSL library by registering algorithms (the available ciphers and digests). A typical TLS/SSL application will start with the library initialization, will provide readable error messages and will seed the PRNG. #include <openssl/ssl.h> #define BUFSIZE . . . char buf[BUFSIZE]; /* inizializza buf */ SSL_load_error_strings(); SSL_library_init(); RAND_seed(buf, BUFSIZE); /* readable error messages */ /* initialize library */ SSL_library_init() only registers ciphers. Another important initialization is the seeding of the PRNG (Pseudo Random Number Generator), which has (may have) to be performed separately. void RAND_seed(const void *buf, int num); RAND_seed() mixes the num bytes at buf into the PRNG state. Thus, if the data at buf are unpredictable to an adversary, this increases the uncertainty about the state and makes the PRNG output less predictable. On systems that provide /dev/urandom, the randomness device is used to seed the PRNG transparently. Then an SSL_CTX object is created as a framework to establish TLS/SSL enabled connections (see SSL_CTX_new(3)). Various options regarding certificates, algorithms etc. can be set in this object. SSL_CTX *SSL_CTX_new(SSL_METHOD *method); SSL_CTX_new() creates a new SSL_CTX object as framework to establish TLS/SSL enabled connections. The SSL_CTX object uses method as connection method. The methods exist in a generic type (for client and server use), a server only type, and a client only type. In case you use TLSv1method can be of the following types: OpenSSL - Tutorial 1 Universita' di Bologna, II Facolta' di Ingegneria Reti di Calcolatori Materiale didattico: annesso alla Lezione 1y TLSv1_method(void), TLSv1_server_method(void), TLSv1_client_method(void) A TLS/SSL connection established with these methods will only understand the TLSv1 protocol. A client will send out TLSv1 client hello messages and will indicate that it only understands TLSv1. A server will only understand TLSv1 client hello messages. This especially means, that it will not understand SSLv2 client hello messages, which are widely used for compatibility reasons, and SSLv3 client hello messages. SSL_CTX *sslContext = SSL_CTX_new(TLSv1_method); if (sslContext == NULL) { /* errore */ } When a network connection has been created, it can be assigned to an SSL object. After the SSL object has been created using SSL_new(3), SSL_set_fd(3) can be used to associate the network connection with the object. SSL *SSL_new(SSL_CTX *ctx); SSL_new() creates a new SSL structure which is needed to hold the data for a TLS/SSL connection. The new structure inherits the settings of the underlying context ctx: connection method (SSLv2/v3/TLSv1), options, verification settings, timeout settings. SSL *sslConnection = SSL_new(sslContext); if (sslConnection == NULL) { /* errore */ } int SSL_set_fd(SSL *ssl, int fd); SSL_set_fd() sets the file descriptor fd as the input/output facility for the TLS/SSL (encrypted) side of ssl. fd will typically be the socket file descriptor of a network connection. SSL_set_fd() returns 0 if the operation failed, 1 otherwise. Then the TLS/SSL handshake is performed using SSL_accept(3) or SSL_connect(3) respectively. int SSL_connect(SSL *ssl); SSL_connect() initiates the TLS/SSL handshake with a server. The communication channel must already have been set and assigned to the ssl. SSL_connect() returns 1 if the TLS/SSL handshake was successfully completed, and a TLS/SSL connection has been established, a value 0 otherwise. int SSL_accept(SSL *ssl); SSL_accept() waits for a TLS/SSL client to initiate the TLS/SSL handshake. The communication channel must already have been set and assigned to the ssl. OpenSSL - Tutorial 2 Universita' di Bologna, II Facolta' di Ingegneria Reti di Calcolatori Materiale didattico: annesso alla Lezione 1y SSL_accept() returns 1 if the TLS/SSL handshake was successfully completed, and a TLS/SSL connection has been established, a value 0 otherwise. SSL_read(3) and SSL_write(3) are used to read and write data on the TLS/SSL connection. int SSL_read(SSL *ssl, void *buf, int num); SSL_read() tries to read num bytes from the specified ssl into the buffer buf. SSL_read() works based on the SSL/TLS records. The data are received in records (with a maximum record size of 16kB for SSLv3/TLSv1). Only when a record has been completely received, it can be processed (decryption and check of integrity). Therefore data that was not retrieved at the last call of SSL_read() can still be buffered inside the SSL layer and will be retrieved on the next call to SSL_read(). If num is higher than the number of bytes buffered, SSL_read() will return with the bytes buffered. If no more bytes are in the buffer, SSL_read() will trigger the processing of the next record. Only when the record has been received and processed completely, SSL_read() will return reporting success. At most the contents of the record will be returned. As the size of an SSL/TLS record may exceed the maximum packet size of the underlying transport (e.g. TCP), it may be necessary to read several packets from the transport layer before the record is complete and SSL_read() can succeed. If a value 0 is returned, the read operation was successful and the return value is the number of bytes actually read from the TLS/SSL connection. Otherwise, a value 0 is returned: the reason may be a clean shutdown due to a "close notify'' alert sent by the peer (in which case the SSL_RECEIVED_SHUTDOWN flag in the ssl shutdown state is set ); it is also possible, that the peer simply shut down the underlying transport and the shutdown is incomplete. int SSL_write(SSL *ssl, const void *buf, int num); SSL_write() writes num bytes from the buffer buf into the specified ssl connection. SSL_write() will only return with success, when the complete contents of buf of length num has been written. This default behaviour can be changed with the SSL_MODE_ENABLE_PARTIAL_WRITE option of SSL_CTX_set_mode. When this flag is set, SSL_write() will also return with success, when a partial write has been successfully completed. In this case the SSL_write() operation is considered completed. The bytes are sent and a new SSL_write() operation with a new buffer (with the already sent bytes removed) must be started. When calling SSL_write() with num=0 bytes to be sent the behaviour is undefined. If a value 0 is returned, the write operation was successful and the return value is the number of bytes actually written to the TLS/SSL connection. Otherwise, a value 0 is returned. SSL_shutdown(3) can be used to shut down the TLS/SSL connection. int SSL_shutdown(SSL *ssl); SSL_shutdown() shuts down an active TLS/SSL connection. It sends the "close notify'' shutdown alert to the peer. OpenSSL - Tutorial 3 Universita' di Bologna, II Facolta' di Ingegneria Reti di Calcolatori Materiale didattico: annesso alla Lezione 1y SSL_shutdown() tries to send the "close notify'' shutdown alert to the peer. Whether the operation succeeds or not, the SSL_SENT_SHUTDOWN flag is set and a currently open session is considered closed and good and will be kept in the session cache for further reuse. The shutdown procedure consists of 2 steps: the sending of the "close notify'' shutdown alert and the reception of the peer's "close notify'' shutdown alert. According to the TLS standard, it is acceptable for an application to only send its shutdown alert and then close the underlying connection without waiting for the peer's response (this way resources can be saved, as the process can already terminate or serve another connection). When the underlying connection shall be used for more communications, the complete shutdown procedure (bidirectional "close notify'' alerts) must be performed, so that the peers stay synchronized. SSL_shutdown() supports both uni- and bidirectional shutdown by its 2 step behaviour. When the application is the first party to send the "close notify" alert, SSL_shutdown() will only send the alert and the set the SSL_SENT_SHUTDOWN flag (so that the session is considered good and will be kept in cache). SSL_shutdown() will then return with 0. If a unidirectional shutdown is enough (the underlying connection shall be closed anyway), this first call to SSL_shutdown() is sufficient. In order to complete the bidirectional shutdown handshake, SSL_shutdown() must be called again. The second call will make SSL_shutdown() wait for the peer's "close notify" shutdown alert. On success, the second call to SSL_shutdown() will return with 1. If the peer already sent the "close notify" alert and it was already processed implicitly inside another function (SSL_read(3)), the SSL_RECEIVED_SHUTDOWN flag is set. SSL_shutdown() will send the "close notify" alert, set the SSL_SENT_SHUTDOWN flag and will immediately return with 1. Whether SSL_RECEIVED_SHUTDOWN is already set can be checked using the SSL_get_shutdown(). It is therefore recommended, to check the return value of SSL_shutdown() and call SSL_shutdown() again, if the bidirectional shutdown is not yet complete (return value of the first call is 0). The following return values can occur: 1: The shutdown was successfully completed. The "close notify'' alert was sent and the peer's "close notify'' alert was received. 0: The shutdown is not yet finished. Call SSL_shutdown() for a second time, if a bidirectional shutdown shall be performed. The output of SSL_get_error(3) may be misleading, as an erroneous SSL_ERROR_SYSCALL may be flagged even though no error occurred. -1: The shutdown was not successful because a fatal error occurred either at the protocol level or a connection failure occurred. OpenSSL - Tutorial 4