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"
16 #include "citadel_ipc.h"
22 int ssl_is_connected = 0;
25 #ifdef THREADED_CLIENT
26 pthread_mutex_t **Critters; /* Things that need locking */
27 #endif /* THREADED_CLIENT */
30 extern int server_is_local;
31 #endif /* HAVE_OPENSSL */
34 static void (*status_hook)(char *s) = NULL;
36 void setCryptoStatusHook(void (*hook)(char *s)) {
43 * input binary data from encrypted connection
45 void serv_read_ssl(char *buf, int bytes)
52 if (SSL_want_read(ssl)) {
53 if ((SSL_write(ssl, junk, 0)) < 1) {
54 error_printf("SSL_write in serv_read:\n");
55 ERR_print_errors_fp(stderr);
58 rlen = SSL_read(ssl, &buf[len], bytes - len);
62 errval = SSL_get_error(ssl, rlen);
63 if (errval == SSL_ERROR_WANT_READ ||
64 errval == SSL_ERROR_WANT_WRITE) {
68 if (errval == SSL_ERROR_ZERO_RETURN ||
69 errval == SSL_ERROR_SSL) {
71 serv_read(&buf[len], bytes - len);
74 error_printf("SSL_read in serv_read:\n");
75 ERR_print_errors_fp(stderr);
85 * send binary to server encrypted
87 void serv_write_ssl(char *buf, int nbytes)
89 int bytes_written = 0;
93 while (bytes_written < nbytes) {
94 if (SSL_want_write(ssl)) {
95 if ((SSL_read(ssl, junk, 0)) < 1) {
96 error_printf("SSL_read in serv_write:\n");
97 ERR_print_errors_fp(stderr);
100 retval = SSL_write(ssl, &buf[bytes_written],
101 nbytes - bytes_written);
105 errval = SSL_get_error(ssl, retval);
106 if (errval == SSL_ERROR_WANT_READ ||
107 errval == SSL_ERROR_WANT_WRITE) {
111 if (errval == SSL_ERROR_ZERO_RETURN ||
112 errval == SSL_ERROR_SSL) {
114 serv_write(&buf[bytes_written],
115 nbytes - bytes_written);
118 error_printf("SSL_write in serv_write:\n");
119 ERR_print_errors_fp(stderr);
123 bytes_written += retval;
128 void ssl_lock(int mode, int n, const char *file, int line)
130 #ifdef THREADED_CLIENT
131 if (mode & CRYPTO_LOCK)
132 pthread_mutex_lock(Critters[n]);
134 pthread_mutex_unlock(Critters[n]);
135 #endif /* THREADED_CLIENT */
137 #endif /* HAVE_OPENSSL */
139 #if defined(THREADED_CLIENT) && defined(HAVE_OPENSSL)
140 static unsigned long id_callback(void) {
141 return (unsigned long)pthread_self();
146 * starttls() starts SSL/TLS if possible
147 * Returns 1 if the session is encrypted, 0 otherwise
153 /* int r; */ /* IPC response code */
155 SSL_METHOD *ssl_method;
158 /* Figure out whether to encrypt the session based on user options */
159 /* User request to disable encryption */
160 if (arg_encrypt == RC_NO || rc_encrypt == RC_NO) {
163 /* User expressed no preference */
164 else if (rc_encrypt == RC_DEFAULT && arg_encrypt == RC_DEFAULT &&
173 SSL_load_error_strings();
174 SSLeay_add_ssl_algorithms();
176 /* Set up the SSL context in which we will oeprate */
177 ssl_method = SSLv23_client_method();
178 ssl_ctx = SSL_CTX_new(ssl_method);
180 error_printf("SSL_CTX_new failed: %s\n",
181 ERR_reason_error_string(ERR_get_error()));
184 /* Any reasonable cipher we can get */
185 if (!(SSL_CTX_set_cipher_list(ssl_ctx, CIT_CIPHERS))) {
186 error_printf("No ciphers available for encryption\n");
187 SSL_CTX_free(ssl_ctx);
191 SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH);
193 /* Load DH parameters into the context */
196 error_printf("Can't allocate a DH object: %s\n",
197 ERR_reason_error_string(ERR_get_error()));
200 if (!(BN_hex2bn(&(dh->p), DH_P))) {
201 error_printf("Can't assign DH_P: %s\n",
202 ERR_reason_error_string(ERR_get_error()));
205 if (!(BN_hex2bn(&(dh->g), DH_G))) {
206 error_printf("Can't assign DH_G: %s\n",
207 ERR_reason_error_string(ERR_get_error()));
211 SSL_CTX_set_tmp_dh(ssl_ctx, dh);
214 #ifdef THREADED_CLIENT
215 /* OpenSSL requires callbacks for threaded clients */
216 CRYPTO_set_locking_callback(ssl_lock);
217 CRYPTO_set_id_callback(id_callback);
219 /* OpenSSL requires us to do semaphores for threaded clients */
220 Critters = malloc(CRYPTO_num_locks() * sizeof (pthread_mutex_t *));
222 perror("malloc failed");
225 for (a = 0; a < CRYPTO_num_locks(); a++) {
226 Critters[a] = malloc(sizeof (pthread_mutex_t));
228 perror("malloc failed");
231 pthread_mutex_init(Critters[a], NULL);
234 #endif /* THREADED_CLIENT */
237 ssl = SSL_new(ssl_ctx);
239 error_printf("SSL_new failed: %s\n",
240 ERR_reason_error_string(ERR_get_error()));
241 SSL_CTX_free(ssl_ctx);
245 /* Pointless flag waving */
246 #if SSLEAY_VERSION_NUMBER >= 0x0922
247 SSL_set_session_id_context(ssl, "Citadel/UX SID", 14);
250 if (!access("/var/run/egd-pool", F_OK))
251 RAND_egd("/var/run/egd-pool");
253 if (!RAND_status()) {
254 error_printf("PRNG not properly seeded\n");
258 /* Associate network connection with SSL object */
259 if (SSL_set_fd(ssl, serv_sock) < 1) {
260 error_printf("SSL_set_fd failed: %s\n",
261 ERR_reason_error_string(ERR_get_error()));
262 SSL_CTX_free(ssl_ctx);
269 if (status_hook != NULL)
270 status_hook("Requesting encryption...\r");
272 /* Ready to start SSL/TLS */
276 error_printf("Server can't start TLS: %s\n", buf);
281 r = CtdlIPCStartEncryption(buf);
283 error_printf("Server can't start TLS: %s\n", buf);
288 /* Do SSL/TLS handshake */
289 if ((a = SSL_connect(ssl)) < 1) {
290 error_printf("SSL_connect failed: %s\n",
291 ERR_reason_error_string(ERR_get_error()));
292 SSL_CTX_free(ssl_ctx);
298 BIO_set_close(ssl->rbio, BIO_NOCLOSE);
302 bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), &alg_bits);
303 error_printf("Encrypting with %s cipher %s (%d of %d bits)\n",
304 SSL_CIPHER_get_version(SSL_get_current_cipher(ssl)),
305 SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)),
308 ssl_is_connected = 1;
312 #endif /* HAVE_OPENSSL */
317 * void endtls() - end SSL/TLS session
327 ssl_is_connected = 0;
329 SSL_CTX_free(ssl_ctx);