10 #include "citadel_ipc.h"
13 static SSL_CTX *ssl_ctx;
16 #ifdef THREADED_CLIENT
17 pthread_mutex_t **Critters; /* Things that need locking */
18 #endif /* THREADED_CLIENT */
20 #endif /* HAVE_OPENSSL */
23 static void (*status_hook)(char *s) = NULL;
25 void setCryptoStatusHook(void (*hook)(char *s)) {
32 * input binary data from encrypted connection
34 void serv_read_ssl(CtdlIPC* ipc, char *buf, int bytes)
41 if (SSL_want_read(ipc->ssl)) {
42 if ((SSL_write(ipc->ssl, junk, 0)) < 1) {
43 error_printf("SSL_write in serv_read:\n");
44 ERR_print_errors_fp(stderr);
47 rlen = SSL_read(ipc->ssl, &buf[len], bytes - len);
51 errval = SSL_get_error(ipc->ssl, rlen);
52 if (errval == SSL_ERROR_WANT_READ ||
53 errval == SSL_ERROR_WANT_WRITE) {
57 if (errval == SSL_ERROR_ZERO_RETURN ||
58 errval == SSL_ERROR_SSL) {
59 serv_read(ipc, &buf[len], bytes - len);
62 error_printf("SSL_read in serv_read:\n");
63 ERR_print_errors_fp(stderr);
73 * send binary to server encrypted
75 void serv_write_ssl(CtdlIPC *ipc, const char *buf, int nbytes)
77 int bytes_written = 0;
81 while (bytes_written < nbytes) {
82 if (SSL_want_write(ipc->ssl)) {
83 if ((SSL_read(ipc->ssl, junk, 0)) < 1) {
84 error_printf("SSL_read in serv_write:\n");
85 ERR_print_errors_fp(stderr);
88 retval = SSL_write(ipc->ssl, &buf[bytes_written],
89 nbytes - bytes_written);
93 errval = SSL_get_error(ipc->ssl, retval);
94 if (errval == SSL_ERROR_WANT_READ ||
95 errval == SSL_ERROR_WANT_WRITE) {
99 if (errval == SSL_ERROR_ZERO_RETURN ||
100 errval == SSL_ERROR_SSL) {
101 serv_write(ipc, &buf[bytes_written],
102 nbytes - bytes_written);
105 error_printf("SSL_write in serv_write:\n");
106 ERR_print_errors_fp(stderr);
110 bytes_written += retval;
115 void ssl_lock(int mode, int n, const char *file, int line)
117 #ifdef THREADED_CLIENT
118 if (mode & CRYPTO_LOCK)
119 pthread_mutex_lock(Critters[n]);
121 pthread_mutex_unlock(Critters[n]);
122 #endif /* THREADED_CLIENT */
124 #endif /* HAVE_OPENSSL */
126 #if defined(THREADED_CLIENT) && defined(HAVE_OPENSSL)
127 static unsigned long id_callback(void) {
128 return (unsigned long)pthread_self();
132 /* FIXME: per application not per ipc */
134 * starttls() starts SSL/TLS if possible
135 * Returns 1 if the session is encrypted, 0 otherwise
137 int starttls(CtdlIPC *ipc)
141 int r; /* IPC response code */
143 SSL_METHOD *ssl_method;
146 /* Figure out whether to encrypt the session based on user options */
147 /* User request to disable encryption */
148 if (arg_encrypt == RC_NO || rc_encrypt == RC_NO) {
151 /* User expressed no preference */
152 else if (rc_encrypt == RC_DEFAULT && arg_encrypt == RC_DEFAULT &&
161 SSL_load_error_strings();
162 SSLeay_add_ssl_algorithms();
164 /* Set up the SSL context in which we will oeprate */
165 ssl_method = SSLv23_client_method();
166 ssl_ctx = SSL_CTX_new(ssl_method);
168 error_printf("SSL_CTX_new failed: %s\n",
169 ERR_reason_error_string(ERR_get_error()));
172 /* Any reasonable cipher we can get */
173 if (!(SSL_CTX_set_cipher_list(ssl_ctx, CIT_CIPHERS))) {
174 error_printf("No ciphers available for encryption\n");
178 SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH);
180 /* Load DH parameters into the context */
183 error_printf("Can't allocate a DH object: %s\n",
184 ERR_reason_error_string(ERR_get_error()));
188 if (!(BN_hex2bn(&(dh->p), DH_P))) {
189 error_printf("Can't assign DH_P: %s\n",
190 ERR_reason_error_string(ERR_get_error()));
195 if (!(BN_hex2bn(&(dh->g), DH_G))) {
196 error_printf("Can't assign DH_G: %s\n",
197 ERR_reason_error_string(ERR_get_error()));
203 SSL_CTX_set_tmp_dh(ssl_ctx, dh);
206 #ifdef THREADED_CLIENT
207 /* OpenSSL requires callbacks for threaded clients */
208 CRYPTO_set_locking_callback(ssl_lock);
209 CRYPTO_set_id_callback(id_callback);
211 /* OpenSSL requires us to do semaphores for threaded clients */
212 Critters = malloc(CRYPTO_num_locks() * sizeof (pthread_mutex_t *));
214 perror("malloc failed");
217 for (a = 0; a < CRYPTO_num_locks(); a++) {
218 Critters[a] = malloc(sizeof (pthread_mutex_t));
220 perror("malloc failed");
223 pthread_mutex_init(Critters[a], NULL);
226 #endif /* THREADED_CLIENT */
229 ipc->ssl = SSL_new(ssl_ctx);
231 error_printf("SSL_new failed: %s\n",
232 ERR_reason_error_string(ERR_get_error()));
236 /* Pointless flag waving */
237 #if SSLEAY_VERSION_NUMBER >= 0x0922
238 SSL_set_session_id_context(ipc->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 error_printf("PRNG not properly seeded\n");
250 /* Associate network connection with SSL object */
251 if (SSL_set_fd(ipc->ssl, ipc->sock) < 1) {
252 error_printf("SSL_set_fd failed: %s\n",
253 ERR_reason_error_string(ERR_get_error()));
258 if (status_hook != NULL)
259 status_hook("Requesting encryption...\r");
261 /* Ready to start SSL/TLS */
263 CtdlIPC_putline(ipc, "STLS");
264 CtdlIPC_getline(ipc, buf);
266 error_printf("Server can't start TLS: %s\n", buf);
272 * We can't have ipc->ssl set when we call StartEncryption()
273 * because the connection isn't yet encrypted. So we fake it.
279 r = CtdlIPCStartEncryption(ipc, buf);
282 error_printf("Server can't start TLS: %s\n", buf);
287 /* Do SSL/TLS handshake */
288 if ((a = SSL_connect(ipc->ssl)) < 1) {
289 error_printf("SSL_connect failed: %s\n",
290 ERR_reason_error_string(ERR_get_error()));
294 BIO_set_close(ipc->ssl->rbio, BIO_NOCLOSE);
298 bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ipc->ssl), &alg_bits);
299 error_printf("Encrypting with %s cipher %s (%d of %d bits)\n",
300 SSL_CIPHER_get_version(SSL_get_current_cipher(ipc->ssl)),
301 SSL_CIPHER_get_name(SSL_get_current_cipher(ipc->ssl)),
307 #endif /* HAVE_OPENSSL */
312 * void endtls() - end SSL/TLS session
314 void endtls(CtdlIPC *ipc)
318 SSL_shutdown(ipc->ssl);