1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
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.
13 *
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.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * $Id: sslgen.c,v 1.45 2009-02-25 12:51:39 bagder Exp $
22 ***************************************************************************/
23
24 /* This file is for implementing all "generic" SSL functions that all libcurl
25 internals should use. It is then responsible for calling the proper
26 "backend" function.
27
28 SSL-functions in libcurl should call functions in this source file, and not
29 to any specific SSL-layer.
30
31 Curl_ssl_ - prefix for generic ones
32 Curl_ossl_ - prefix for OpenSSL ones
33 Curl_gtls_ - prefix for GnuTLS ones
34 Curl_nss_ - prefix for NSS ones
35
36 Note that this source code uses curlssl_* functions, and they are all
37 defines/macros #defined by the lib-specific header files.
38
39 "SSL/TLS Strong Encryption: An Introduction"
40 http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
41 */
42
43 #include "setup.h"
44
45 #include <string.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 #ifdef HAVE_SYS_SOCKET_H
49 #include <sys/socket.h>
50 #endif
51
52 #include "urldata.h"
53 #define SSLGEN_C
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 "sendf.h"
60 #include "rawstr.h"
61 #include "url.h"
62 #include "memory.h"
63 #include "progress.h"
64 /* The last #include file should be: */
65 #include "memdebug.h"
66
safe_strequal(char * str1,char * str2)67 static bool safe_strequal(char* str1, char* str2)
68 {
69 if(str1 && str2)
70 /* both pointers point to something then compare them */
71 return (bool)(0 != Curl_raw_equal(str1, str2));
72 else
73 /* if both pointers are NULL then treat them as equal */
74 return (bool)(!str1 && !str2);
75 }
76
77 bool
Curl_ssl_config_matches(struct ssl_config_data * data,struct ssl_config_data * needle)78 Curl_ssl_config_matches(struct ssl_config_data* data,
79 struct ssl_config_data* needle)
80 {
81 if((data->version == needle->version) &&
82 (data->verifypeer == needle->verifypeer) &&
83 (data->verifyhost == needle->verifyhost) &&
84 safe_strequal(data->CApath, needle->CApath) &&
85 safe_strequal(data->CAfile, needle->CAfile) &&
86 safe_strequal(data->random_file, needle->random_file) &&
87 safe_strequal(data->egdsocket, needle->egdsocket) &&
88 safe_strequal(data->cipher_list, needle->cipher_list))
89 return TRUE;
90
91 return FALSE;
92 }
93
94 bool
Curl_clone_ssl_config(struct ssl_config_data * source,struct ssl_config_data * dest)95 Curl_clone_ssl_config(struct ssl_config_data *source,
96 struct ssl_config_data *dest)
97 {
98 dest->sessionid = source->sessionid;
99 dest->verifyhost = source->verifyhost;
100 dest->verifypeer = source->verifypeer;
101 dest->version = source->version;
102
103 if(source->CAfile) {
104 dest->CAfile = strdup(source->CAfile);
105 if(!dest->CAfile)
106 return FALSE;
107 }
108
109 if(source->CApath) {
110 dest->CApath = strdup(source->CApath);
111 if(!dest->CApath)
112 return FALSE;
113 }
114
115 if(source->cipher_list) {
116 dest->cipher_list = strdup(source->cipher_list);
117 if(!dest->cipher_list)
118 return FALSE;
119 }
120
121 if(source->egdsocket) {
122 dest->egdsocket = strdup(source->egdsocket);
123 if(!dest->egdsocket)
124 return FALSE;
125 }
126
127 if(source->random_file) {
128 dest->random_file = strdup(source->random_file);
129 if(!dest->random_file)
130 return FALSE;
131 }
132
133 return TRUE;
134 }
135
Curl_free_ssl_config(struct ssl_config_data * sslc)136 void Curl_free_ssl_config(struct ssl_config_data* sslc)
137 {
138 Curl_safefree(sslc->CAfile);
139 Curl_safefree(sslc->CApath);
140 Curl_safefree(sslc->cipher_list);
141 Curl_safefree(sslc->egdsocket);
142 Curl_safefree(sslc->random_file);
143 }
144
145 #ifdef USE_SSL
146
147 /* "global" init done? */
148 static bool init_ssl=FALSE;
149
150 /**
151 * Global SSL init
152 *
153 * @retval 0 error initializing SSL
154 * @retval 1 SSL initialized successfully
155 */
Curl_ssl_init(void)156 int Curl_ssl_init(void)
157 {
158 /* make sure this is only done once */
159 if(init_ssl)
160 return 1;
161 init_ssl = TRUE; /* never again */
162
163 return curlssl_init();
164 }
165
166
167 /* Global cleanup */
Curl_ssl_cleanup(void)168 void Curl_ssl_cleanup(void)
169 {
170 if(init_ssl) {
171 /* only cleanup if we did a previous init */
172 curlssl_cleanup();
173 init_ssl = FALSE;
174 }
175 }
176
177 CURLcode
Curl_ssl_connect(struct connectdata * conn,int sockindex)178 Curl_ssl_connect(struct connectdata *conn, int sockindex)
179 {
180 CURLcode res;
181 /* mark this is being ssl-enabled from here on. */
182 conn->ssl[sockindex].use = TRUE;
183 conn->ssl[sockindex].state = ssl_connection_negotiating;
184
185 res = curlssl_connect(conn, sockindex);
186
187 if(!res)
188 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
189
190 return res;
191 }
192
193 CURLcode
Curl_ssl_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)194 Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
195 bool *done)
196 {
197 #ifdef curlssl_connect_nonblocking
198 /* mark this is being ssl requested from here on. */
199 conn->ssl[sockindex].use = TRUE;
200 return curlssl_connect_nonblocking(conn, sockindex, done);
201 #else
202 *done = TRUE; /* fallback to BLOCKING */
203 conn->ssl[sockindex].use = TRUE;
204 return curlssl_connect(conn, sockindex);
205 #endif /* non-blocking connect support */
206 }
207
208 /*
209 * Check if there's a session ID for the given connection in the cache, and if
210 * there's one suitable, it is provided. Returns TRUE when no entry matched.
211 */
Curl_ssl_getsessionid(struct connectdata * conn,void ** ssl_sessionid,size_t * idsize)212 int Curl_ssl_getsessionid(struct connectdata *conn,
213 void **ssl_sessionid,
214 size_t *idsize) /* set 0 if unknown */
215 {
216 struct curl_ssl_session *check;
217 struct SessionHandle *data = conn->data;
218 long i;
219
220 if(!conn->ssl_config.sessionid)
221 /* session ID re-use is disabled */
222 return TRUE;
223
224 for(i=0; i< data->set.ssl.numsessions; i++) {
225 check = &data->state.session[i];
226 if(!check->sessionid)
227 /* not session ID means blank entry */
228 continue;
229 if(Curl_raw_equal(conn->host.name, check->name) &&
230 (conn->remote_port == check->remote_port) &&
231 Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
232 /* yes, we have a session ID! */
233 data->state.sessionage++; /* increase general age */
234 check->age = data->state.sessionage; /* set this as used in this age */
235 *ssl_sessionid = check->sessionid;
236 if(idsize)
237 *idsize = check->idsize;
238 return FALSE;
239 }
240 }
241 *ssl_sessionid = NULL;
242 return TRUE;
243 }
244
245 /*
246 * Kill a single session ID entry in the cache.
247 */
kill_session(struct curl_ssl_session * session)248 static int kill_session(struct curl_ssl_session *session)
249 {
250 if(session->sessionid) {
251 /* defensive check */
252
253 /* free the ID the SSL-layer specific way */
254 curlssl_session_free(session->sessionid);
255
256 session->sessionid=NULL;
257 session->age = 0; /* fresh */
258
259 Curl_free_ssl_config(&session->ssl_config);
260
261 Curl_safefree(session->name);
262 session->name = NULL; /* no name */
263
264 return 0; /* ok */
265 }
266 else
267 return 1;
268 }
269
270 /*
271 * Store session id in the session cache. The ID passed on to this function
272 * must already have been extracted and allocated the proper way for the SSL
273 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
274 * later on.
275 */
Curl_ssl_addsessionid(struct connectdata * conn,void * ssl_sessionid,size_t idsize)276 CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
277 void *ssl_sessionid,
278 size_t idsize)
279 {
280 long i;
281 struct SessionHandle *data=conn->data; /* the mother of all structs */
282 struct curl_ssl_session *store = &data->state.session[0];
283 long oldest_age=data->state.session[0].age; /* zero if unused */
284 char *clone_host;
285
286 /* Even though session ID re-use might be disabled, that only disables USING
287 IT. We still store it here in case the re-using is again enabled for an
288 upcoming transfer */
289
290 clone_host = strdup(conn->host.name);
291 if(!clone_host)
292 return CURLE_OUT_OF_MEMORY; /* bail out */
293
294 /* Now we should add the session ID and the host name to the cache, (remove
295 the oldest if necessary) */
296
297 /* find an empty slot for us, or find the oldest */
298 for(i=1; (i<data->set.ssl.numsessions) &&
299 data->state.session[i].sessionid; i++) {
300 if(data->state.session[i].age < oldest_age) {
301 oldest_age = data->state.session[i].age;
302 store = &data->state.session[i];
303 }
304 }
305 if(i == data->set.ssl.numsessions)
306 /* cache is full, we must "kill" the oldest entry! */
307 kill_session(store);
308 else
309 store = &data->state.session[i]; /* use this slot */
310
311 /* now init the session struct wisely */
312 store->sessionid = ssl_sessionid;
313 store->idsize = idsize;
314 store->age = data->state.sessionage; /* set current age */
315 if (store->name)
316 /* free it if there's one already present */
317 free(store->name);
318 store->name = clone_host; /* clone host name */
319 store->remote_port = conn->remote_port; /* port number */
320
321 if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config))
322 return CURLE_OUT_OF_MEMORY;
323
324 return CURLE_OK;
325 }
326
327
Curl_ssl_close_all(struct SessionHandle * data)328 void Curl_ssl_close_all(struct SessionHandle *data)
329 {
330 long i;
331 /* kill the session ID cache */
332 if(data->state.session) {
333 for(i=0; i< data->set.ssl.numsessions; i++)
334 /* the single-killer function handles empty table slots */
335 kill_session(&data->state.session[i]);
336
337 /* free the cache data */
338 free(data->state.session);
339 data->state.session = NULL;
340 }
341
342 curlssl_close_all(data);
343 }
344
Curl_ssl_close(struct connectdata * conn,int sockindex)345 void Curl_ssl_close(struct connectdata *conn, int sockindex)
346 {
347 DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
348 curlssl_close(conn, sockindex);
349 }
350
Curl_ssl_shutdown(struct connectdata * conn,int sockindex)351 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
352 {
353 if(curlssl_shutdown(conn, sockindex))
354 return CURLE_SSL_SHUTDOWN_FAILED;
355
356 conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
357 conn->ssl[sockindex].state = ssl_connection_none;
358
359 return CURLE_OK;
360 }
361
362 /* Selects an SSL crypto engine
363 */
Curl_ssl_set_engine(struct SessionHandle * data,const char * engine)364 CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
365 {
366 return curlssl_set_engine(data, engine);
367 }
368
369 /* Selects the default SSL crypto engine
370 */
Curl_ssl_set_engine_default(struct SessionHandle * data)371 CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
372 {
373 return curlssl_set_engine_default(data);
374 }
375
376 /* Return list of OpenSSL crypto engine names. */
Curl_ssl_engines_list(struct SessionHandle * data)377 struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
378 {
379 return curlssl_engines_list(data);
380 }
381
382 /* return number of sent (non-SSL) bytes */
Curl_ssl_send(struct connectdata * conn,int sockindex,const void * mem,size_t len)383 ssize_t Curl_ssl_send(struct connectdata *conn,
384 int sockindex,
385 const void *mem,
386 size_t len)
387 {
388 return curlssl_send(conn, sockindex, mem, len);
389 }
390
391 /* return number of received (decrypted) bytes */
392
393 /*
394 * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
395 * a regular CURLcode value.
396 */
Curl_ssl_recv(struct connectdata * conn,int sockindex,char * mem,size_t len)397 ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */
398 int sockindex, /* socketindex */
399 char *mem, /* store read data here */
400 size_t len) /* max amount to read */
401 {
402 ssize_t nread;
403 bool block = FALSE;
404
405 nread = curlssl_recv(conn, sockindex, mem, len, &block);
406 if(nread == -1) {
407 if(!block)
408 return 0; /* this is a true error, not EWOULDBLOCK */
409 else
410 return -1;
411 }
412
413 return nread;
414 }
415
416
417 /*
418 * This sets up a session ID cache to the specified size. Make sure this code
419 * is agnostic to what underlying SSL technology we use.
420 */
Curl_ssl_initsessions(struct SessionHandle * data,long amount)421 CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount)
422 {
423 struct curl_ssl_session *session;
424
425 if(data->state.session)
426 /* this is just a precaution to prevent multiple inits */
427 return CURLE_OK;
428
429 session = calloc(sizeof(struct curl_ssl_session), amount);
430 if(!session)
431 return CURLE_OUT_OF_MEMORY;
432
433 /* store the info in the SSL section */
434 data->set.ssl.numsessions = amount;
435 data->state.session = session;
436 data->state.sessionage = 1; /* this is brand new */
437 return CURLE_OK;
438 }
439
Curl_ssl_version(char * buffer,size_t size)440 size_t Curl_ssl_version(char *buffer, size_t size)
441 {
442 return curlssl_version(buffer, size);
443 }
444
445 /*
446 * This function tries to determine connection status.
447 *
448 * Return codes:
449 * 1 means the connection is still in place
450 * 0 means the connection has been closed
451 * -1 means the connection status is unknown
452 */
Curl_ssl_check_cxn(struct connectdata * conn)453 int Curl_ssl_check_cxn(struct connectdata *conn)
454 {
455 return curlssl_check_cxn(conn);
456 }
457
Curl_ssl_data_pending(const struct connectdata * conn,int connindex)458 bool Curl_ssl_data_pending(const struct connectdata *conn,
459 int connindex)
460 {
461 return curlssl_data_pending(conn, connindex);
462 }
463
Curl_ssl_free_certinfo(struct SessionHandle * data)464 void Curl_ssl_free_certinfo(struct SessionHandle *data)
465 {
466 int i;
467 struct curl_certinfo *ci = &data->info.certs;
468 if(ci->num_of_certs) {
469 /* free all individual lists used */
470 for(i=0; i<ci->num_of_certs; i++)
471 curl_slist_free_all(ci->certinfo[i]);
472 free(ci->certinfo); /* free the actual array too */
473 ci->num_of_certs = 0;
474 }
475 }
476 #endif /* USE_SSL */
477