1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 /* This file is for implementing all "generic" SSL functions that all libcurl
24 internals should use. It is then responsible for calling the proper
27 SSL-functions in libcurl should call functions in this source file, and not
28 to any specific SSL-layer.
30 Curl_ssl_ - prefix for generic ones
31 Curl_ossl_ - prefix for OpenSSL ones
32 Curl_gtls_ - prefix for GnuTLS ones
33 Curl_nss_ - prefix for NSS ones
34 Curl_polarssl_ - prefix for PolarSSL ones
36 Note that this source code uses curlssl_* functions, and they are all
37 defines/macros #defined by the lib-specific header files.
39 "SSL/TLS Strong Encryption: An Introduction"
40 http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
48 #ifdef HAVE_SYS_SOCKET_H
49 #include <sys/socket.h>
54 #include "sslgen.h" /* generic SSL protos etc */
55 #include "ssluse.h" /* OpenSSL versions */
56 #include "gtls.h" /* GnuTLS versions */
57 #include "nssg.h" /* NSS versions */
58 #include "qssl.h" /* QSOSSL versions */
59 #include "polarssl.h" /* PolarSSL versions */
63 #include "curl_memory.h"
65 /* The last #include file should be: */
68 static bool safe_strequal(char* str1, char* str2)
71 /* both pointers point to something then compare them */
72 return (bool)(0 != Curl_raw_equal(str1, str2));
74 /* if both pointers are NULL then treat them as equal */
75 return (bool)(!str1 && !str2);
79 Curl_ssl_config_matches(struct ssl_config_data* data,
80 struct ssl_config_data* needle)
82 if((data->version == needle->version) &&
83 (data->verifypeer == needle->verifypeer) &&
84 (data->verifyhost == needle->verifyhost) &&
85 safe_strequal(data->CApath, needle->CApath) &&
86 safe_strequal(data->CAfile, needle->CAfile) &&
87 safe_strequal(data->random_file, needle->random_file) &&
88 safe_strequal(data->egdsocket, needle->egdsocket) &&
89 safe_strequal(data->cipher_list, needle->cipher_list))
96 Curl_clone_ssl_config(struct ssl_config_data *source,
97 struct ssl_config_data *dest)
99 dest->sessionid = source->sessionid;
100 dest->verifyhost = source->verifyhost;
101 dest->verifypeer = source->verifypeer;
102 dest->version = source->version;
105 dest->CAfile = strdup(source->CAfile);
113 dest->CApath = strdup(source->CApath);
120 if(source->cipher_list) {
121 dest->cipher_list = strdup(source->cipher_list);
122 if(!dest->cipher_list)
126 dest->cipher_list = NULL;
128 if(source->egdsocket) {
129 dest->egdsocket = strdup(source->egdsocket);
134 dest->egdsocket = NULL;
136 if(source->random_file) {
137 dest->random_file = strdup(source->random_file);
138 if(!dest->random_file)
142 dest->random_file = NULL;
147 void Curl_free_ssl_config(struct ssl_config_data* sslc)
149 Curl_safefree(sslc->CAfile);
150 Curl_safefree(sslc->CApath);
151 Curl_safefree(sslc->cipher_list);
152 Curl_safefree(sslc->egdsocket);
153 Curl_safefree(sslc->random_file);
158 /* "global" init done? */
159 static bool init_ssl=FALSE;
164 * @retval 0 error initializing SSL
165 * @retval 1 SSL initialized successfully
167 int Curl_ssl_init(void)
169 /* make sure this is only done once */
172 init_ssl = TRUE; /* never again */
174 return curlssl_init();
179 void Curl_ssl_cleanup(void)
182 /* only cleanup if we did a previous init */
189 Curl_ssl_connect(struct connectdata *conn, int sockindex)
192 /* mark this is being ssl-enabled from here on. */
193 conn->ssl[sockindex].use = TRUE;
194 conn->ssl[sockindex].state = ssl_connection_negotiating;
196 res = curlssl_connect(conn, sockindex);
199 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
205 Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
208 #ifdef curlssl_connect_nonblocking
210 /* mark this is being ssl requested from here on. */
211 conn->ssl[sockindex].use = TRUE;
212 res = curlssl_connect_nonblocking(conn, sockindex, done);
213 if(!res && *done == TRUE)
214 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
217 *done = TRUE; /* fallback to BLOCKING */
218 conn->ssl[sockindex].use = TRUE;
219 return curlssl_connect(conn, sockindex);
220 #endif /* non-blocking connect support */
224 * Check if there's a session ID for the given connection in the cache, and if
225 * there's one suitable, it is provided. Returns TRUE when no entry matched.
227 int Curl_ssl_getsessionid(struct connectdata *conn,
228 void **ssl_sessionid,
229 size_t *idsize) /* set 0 if unknown */
231 struct curl_ssl_session *check;
232 struct SessionHandle *data = conn->data;
235 if(!conn->ssl_config.sessionid)
236 /* session ID re-use is disabled */
239 for(i=0; i< data->set.ssl.numsessions; i++) {
240 check = &data->state.session[i];
241 if(!check->sessionid)
242 /* not session ID means blank entry */
244 if(Curl_raw_equal(conn->host.name, check->name) &&
245 (conn->remote_port == check->remote_port) &&
246 Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
247 /* yes, we have a session ID! */
248 data->state.sessionage++; /* increase general age */
249 check->age = data->state.sessionage; /* set this as used in this age */
250 *ssl_sessionid = check->sessionid;
252 *idsize = check->idsize;
256 *ssl_sessionid = NULL;
261 * Kill a single session ID entry in the cache.
263 static int kill_session(struct curl_ssl_session *session)
265 if(session->sessionid) {
266 /* defensive check */
268 /* free the ID the SSL-layer specific way */
269 curlssl_session_free(session->sessionid);
271 session->sessionid=NULL;
272 session->age = 0; /* fresh */
274 Curl_free_ssl_config(&session->ssl_config);
276 Curl_safefree(session->name);
277 session->name = NULL; /* no name */
286 * Delete the given session ID from the cache.
288 void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
291 for(i=0; i< conn->data->set.ssl.numsessions; i++) {
292 struct curl_ssl_session *check = &conn->data->state.session[i];
294 if (check->sessionid == ssl_sessionid) {
302 * Store session id in the session cache. The ID passed on to this function
303 * must already have been extracted and allocated the proper way for the SSL
304 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
307 CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
312 struct SessionHandle *data=conn->data; /* the mother of all structs */
313 struct curl_ssl_session *store = &data->state.session[0];
314 long oldest_age=data->state.session[0].age; /* zero if unused */
317 /* Even though session ID re-use might be disabled, that only disables USING
318 IT. We still store it here in case the re-using is again enabled for an
321 clone_host = strdup(conn->host.name);
323 return CURLE_OUT_OF_MEMORY; /* bail out */
325 /* Now we should add the session ID and the host name to the cache, (remove
326 the oldest if necessary) */
328 /* find an empty slot for us, or find the oldest */
329 for(i=1; (i<data->set.ssl.numsessions) &&
330 data->state.session[i].sessionid; i++) {
331 if(data->state.session[i].age < oldest_age) {
332 oldest_age = data->state.session[i].age;
333 store = &data->state.session[i];
336 if(i == data->set.ssl.numsessions)
337 /* cache is full, we must "kill" the oldest entry! */
340 store = &data->state.session[i]; /* use this slot */
342 /* now init the session struct wisely */
343 store->sessionid = ssl_sessionid;
344 store->idsize = idsize;
345 store->age = data->state.sessionage; /* set current age */
347 /* free it if there's one already present */
349 store->name = clone_host; /* clone host name */
350 store->remote_port = conn->remote_port; /* port number */
352 if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config))
353 return CURLE_OUT_OF_MEMORY;
359 void Curl_ssl_close_all(struct SessionHandle *data)
362 /* kill the session ID cache */
363 if(data->state.session) {
364 for(i=0; i< data->set.ssl.numsessions; i++)
365 /* the single-killer function handles empty table slots */
366 kill_session(&data->state.session[i]);
368 /* free the cache data */
369 free(data->state.session);
370 data->state.session = NULL;
373 curlssl_close_all(data);
376 void Curl_ssl_close(struct connectdata *conn, int sockindex)
378 DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
379 curlssl_close(conn, sockindex);
382 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
384 if(curlssl_shutdown(conn, sockindex))
385 return CURLE_SSL_SHUTDOWN_FAILED;
387 conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
388 conn->ssl[sockindex].state = ssl_connection_none;
393 /* Selects an SSL crypto engine
395 CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
397 return curlssl_set_engine(data, engine);
400 /* Selects the default SSL crypto engine
402 CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
404 return curlssl_set_engine_default(data);
407 /* Return list of OpenSSL crypto engine names. */
408 struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
410 return curlssl_engines_list(data);
414 * This sets up a session ID cache to the specified size. Make sure this code
415 * is agnostic to what underlying SSL technology we use.
417 CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount)
419 struct curl_ssl_session *session;
421 if(data->state.session)
422 /* this is just a precaution to prevent multiple inits */
425 session = calloc(amount, sizeof(struct curl_ssl_session));
427 return CURLE_OUT_OF_MEMORY;
429 /* store the info in the SSL section */
430 data->set.ssl.numsessions = amount;
431 data->state.session = session;
432 data->state.sessionage = 1; /* this is brand new */
436 size_t Curl_ssl_version(char *buffer, size_t size)
438 return curlssl_version(buffer, size);
442 * This function tries to determine connection status.
445 * 1 means the connection is still in place
446 * 0 means the connection has been closed
447 * -1 means the connection status is unknown
449 int Curl_ssl_check_cxn(struct connectdata *conn)
451 return curlssl_check_cxn(conn);
454 bool Curl_ssl_data_pending(const struct connectdata *conn,
457 return curlssl_data_pending(conn, connindex);
460 void Curl_ssl_free_certinfo(struct SessionHandle *data)
463 struct curl_certinfo *ci = &data->info.certs;
464 if(ci->num_of_certs) {
465 /* free all individual lists used */
466 for(i=0; i<ci->num_of_certs; i++)
467 curl_slist_free_all(ci->certinfo[i]);
468 free(ci->certinfo); /* free the actual array too */
469 ci->num_of_certs = 0;