5 #include <openssl/ssl.h>
6 #include <openssl/err.h>
7 #include <openssl/rand.h>
13 #include <sys/types.h>
15 #include "client_crypto.h"
21 int ssl_is_connected = 0;
24 #ifdef THREADED_CLIENT
25 pthread_mutex_t **Critters; /* Things that need locking */
26 #endif /* THREADED_CLIENT */
29 extern int server_is_local;
30 #endif /* HAVE_OPENSSL */
35 * input binary data from encrypted connection
37 void serv_read_ssl(char *buf, int bytes)
44 if (SSL_want_read(ssl)) {
45 if ((SSL_write(ssl, junk, 0)) < 1) {
46 err_printf("SSL_write in serv_read:\n");
47 ERR_print_errors_fp(stderr);
50 rlen = SSL_read(ssl, &buf[len], bytes - len);
54 errval = SSL_get_error(ssl, rlen);
55 if (errval == SSL_ERROR_WANT_READ ||
56 errval == SSL_ERROR_WANT_WRITE) {
60 if (errval == SSL_ERROR_ZERO_RETURN ||
61 errval == SSL_ERROR_SSL) {
63 serv_read(&buf[len], bytes - len);
66 err_printf("SSL_read in serv_read:\n");
67 ERR_print_errors_fp(stderr);
77 * send binary to server encrypted
79 void serv_write_ssl(char *buf, int nbytes)
81 int bytes_written = 0;
85 while (bytes_written < nbytes) {
86 if (SSL_want_write(ssl)) {
87 if ((SSL_read(ssl, junk, 0)) < 1) {
88 err_printf("SSL_read in serv_write:\n");
89 ERR_print_errors_fp(stderr);
92 retval = SSL_write(ssl, &buf[bytes_written],
93 nbytes - bytes_written);
97 errval = SSL_get_error(ssl, retval);
98 if (errval == SSL_ERROR_WANT_READ ||
99 errval == SSL_ERROR_WANT_WRITE) {
103 if (errval == SSL_ERROR_ZERO_RETURN ||
104 errval == SSL_ERROR_SSL) {
106 serv_write(&buf[bytes_written],
107 nbytes - bytes_written);
110 err_printf("SSL_write in serv_write:\n");
111 ERR_print_errors_fp(stderr);
115 bytes_written += retval;
120 void ssl_lock(int mode, int n, const char *file, int line)
122 #ifdef THREADED_CLIENT
123 if (mode & CRYPTO_LOCK)
124 pthread_mutex_lock(Critters[n]);
126 pthread_mutex_unlock(Critters[n]);
127 #endif /* THREADED_CLIENT */
129 #endif /* HAVE_OPENSSL */
131 #if defined(THREADED_CLIENT) && defined(HAVE_OPENSSL)
132 static unsigned long id_callback(void) {
133 return (unsigned long)pthread_self();
138 * starttls() starts SSL/TLS if possible
139 * Returns 1 if the session is encrypted, 0 otherwise
146 SSL_METHOD *ssl_method;
149 /* Figure out whether to encrypt the session based on user options */
150 /* User request to disable encryption */
151 if (arg_encrypt == RC_NO || rc_encrypt == RC_NO) {
154 /* User expressed no preference */
155 else if (rc_encrypt == RC_DEFAULT && arg_encrypt == RC_DEFAULT &&
164 SSL_load_error_strings();
165 SSLeay_add_ssl_algorithms();
167 /* Set up the SSL context in which we will oeprate */
168 ssl_method = SSLv23_client_method();
169 ssl_ctx = SSL_CTX_new(ssl_method);
171 err_printf("SSL_CTX_new failed: %s\n",
172 ERR_reason_error_string(ERR_get_error()));
175 /* Any reasonable cipher we can get */
176 if (!(SSL_CTX_set_cipher_list(ssl_ctx, CIT_CIPHERS))) {
177 err_printf("No ciphers available for encryption\n");
178 SSL_CTX_free(ssl_ctx);
182 SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH);
184 /* Load DH parameters into the context */
187 err_printf("Can't allocate a DH object: %s\n",
188 ERR_reason_error_string(ERR_get_error()));
191 if (!(BN_hex2bn(&(dh->p), DH_P))) {
192 err_printf("Can't assign DH_P: %s\n",
193 ERR_reason_error_string(ERR_get_error()));
196 if (!(BN_hex2bn(&(dh->g), DH_G))) {
197 err_printf("Can't assign DH_G: %s\n",
198 ERR_reason_error_string(ERR_get_error()));
202 SSL_CTX_set_tmp_dh(ssl_ctx, dh);
205 #ifdef THREADED_CLIENT
206 /* OpenSSL requires callbacks for threaded clients */
207 CRYPTO_set_locking_callback(ssl_lock);
208 CRYPTO_set_id_callback(id_callback);
210 /* OpenSSL requires us to do semaphores for threaded clients */
211 Critters = malloc(CRYPTO_num_locks() * sizeof (pthread_mutex_t *));
213 perror("malloc failed");
216 for (a = 0; a < CRYPTO_num_locks(); a++) {
217 Critters[a] = malloc(sizeof (pthread_mutex_t));
219 perror("malloc failed");
222 pthread_mutex_init(Critters[a], NULL);
225 #endif /* THREADED_CLIENT */
228 ssl = SSL_new(ssl_ctx);
230 err_printf("SSL_new failed: %s\n",
231 ERR_reason_error_string(ERR_get_error()));
232 SSL_CTX_free(ssl_ctx);
236 /* Pointless flag waving */
237 #if SSLEAY_VERSION_NUMBER >= 0x0922
238 SSL_set_session_id_context(ssl, "Citadel/UX SID", 14);
241 if (!access("/var/run/egd-pool", F_OK))
242 RAND_egd("/var/run/egd-pool");
244 if (!RAND_status()) {
245 err_printf("PRNG not properly seeded\n");
249 /* Associate network connection with SSL object */
250 if (SSL_set_fd(ssl, serv_sock) < 1) {
251 err_printf("SSL_set_fd failed: %s\n",
252 ERR_reason_error_string(ERR_get_error()));
253 SSL_CTX_free(ssl_ctx);
260 sln_printf("Requesting encryption...\r");
263 /* Ready to start SSL/TLS */
267 err_printf("Server can't start TLS: %s\n", &buf[4]);
271 /* Do SSL/TLS handshake */
272 if ((a = SSL_connect(ssl)) < 1) {
273 err_printf("SSL_connect failed: %s\n",
274 ERR_reason_error_string(ERR_get_error()));
275 SSL_CTX_free(ssl_ctx);
281 BIO_set_close(ssl->rbio, BIO_NOCLOSE);
285 bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), &alg_bits);
286 err_printf("Encrypting with %s cipher %s (%d of %d bits)\n",
287 SSL_CIPHER_get_version(SSL_get_current_cipher(ssl)),
288 SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)),
291 ssl_is_connected = 1;
295 #endif /* HAVE_OPENSSL */
300 * void endtls() - end SSL/TLS session
310 ssl_is_connected = 0;
312 SSL_CTX_free(ssl_ctx);