Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / sslgen.c
blob1880b657f318df4de32c5786c1e20d5d62051ead
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, 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 * $Id: sslgen.c,v 1.2 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
24 /* This file is for "generic" SSL functions that all libcurl internals should
25 use. It is responsible for calling the proper 'ossl' function in ssluse.c
26 (OpenSSL based) or the 'gtls' function in gtls.c (GnuTLS based).
28 SSL-functions in libcurl should call functions in this source file, and not
29 to any specific SSL-layer.
31 Curl_ssl_ - prefix for generic ones
32 Curl_ossl_ - prefix for OpenSSL ones
33 Curl_gtls_ - prefix for GnuTLS ones
35 "SSL/TLS Strong Encryption: An Introduction"
36 http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
39 #include "setup.h"
40 #include <string.h>
41 #include <stdlib.h>
42 #include <ctype.h>
43 #ifdef HAVE_SYS_TYPES_H
44 #include <sys/types.h>
45 #endif
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
48 #endif
50 #include "urldata.h"
51 #define SSLGEN_C
52 #include "sslgen.h" /* generic SSL protos etc */
53 #include "ssluse.h" /* OpenSSL versions */
54 #include "gtls.h" /* GnuTLS versions */
55 #include "sendf.h"
56 #include "strequal.h"
57 #include "url.h"
58 #include "memory.h"
59 /* The last #include file should be: */
60 #include "memdebug.h"
62 /* "global" init done? */
63 static bool init_ssl=FALSE;
65 static bool safe_strequal(char* str1, char* str2);
67 static bool safe_strequal(char* str1, char* str2)
69 if(str1 && str2)
70 /* both pointers point to something then compare them */
71 return (bool)(0 != strequal(str1, str2));
72 else
73 /* if both pointers are NULL then treat them as equal */
74 return (bool)(!str1 && !str2);
77 bool
78 Curl_ssl_config_matches(struct ssl_config_data* data,
79 struct ssl_config_data* needle)
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;
91 return FALSE;
94 bool
95 Curl_clone_ssl_config(struct ssl_config_data *source,
96 struct ssl_config_data *dest)
98 dest->verifyhost = source->verifyhost;
99 dest->verifypeer = source->verifypeer;
100 dest->version = source->version;
102 if(source->CAfile) {
103 dest->CAfile = strdup(source->CAfile);
104 if(!dest->CAfile)
105 return FALSE;
108 if(source->CApath) {
109 dest->CApath = strdup(source->CApath);
110 if(!dest->CApath)
111 return FALSE;
114 if(source->cipher_list) {
115 dest->cipher_list = strdup(source->cipher_list);
116 if(!dest->cipher_list)
117 return FALSE;
120 if(source->egdsocket) {
121 dest->egdsocket = strdup(source->egdsocket);
122 if(!dest->egdsocket)
123 return FALSE;
126 if(source->random_file) {
127 dest->random_file = strdup(source->random_file);
128 if(!dest->random_file)
129 return FALSE;
132 return TRUE;
135 void Curl_free_ssl_config(struct ssl_config_data* sslc)
137 if(sslc->CAfile)
138 free(sslc->CAfile);
140 if(sslc->CApath)
141 free(sslc->CApath);
143 if(sslc->cipher_list)
144 free(sslc->cipher_list);
146 if(sslc->egdsocket)
147 free(sslc->egdsocket);
149 if(sslc->random_file)
150 free(sslc->random_file);
154 * Global SSL init
156 * @retval 0 error initializing SSL
157 * @retval 1 SSL initialized successfully
159 int Curl_ssl_init(void)
161 /* make sure this is only done once */
162 if(init_ssl)
163 return 1;
164 init_ssl = TRUE; /* never again */
166 #ifdef USE_SSLEAY
167 return Curl_ossl_init();
168 #else
169 #ifdef USE_GNUTLS
170 return Curl_gtls_init();
171 #else
172 /* no SSL support */
173 return 1;
174 #endif /* USE_GNUTLS */
175 #endif /* USE_SSLEAY */
179 /* Global cleanup */
180 void Curl_ssl_cleanup(void)
182 if(init_ssl) {
183 /* only cleanup if we did a previous init */
184 #ifdef USE_SSLEAY
185 Curl_ossl_cleanup();
186 #else
187 #ifdef USE_GNUTLS
188 Curl_gtls_cleanup();
189 #endif /* USE_GNUTLS */
190 #endif /* USE_SSLEAY */
191 init_ssl = FALSE;
195 CURLcode
196 Curl_ssl_connect(struct connectdata *conn, int sockindex)
198 #ifdef USE_SSL
199 /* mark this is being ssl enabled from here on. */
200 conn->ssl[sockindex].use = TRUE;
202 #ifdef USE_SSLEAY
203 return Curl_ossl_connect(conn, sockindex);
204 #else
205 #ifdef USE_GNUTLS
206 return Curl_gtls_connect(conn, sockindex);
207 #endif /* USE_GNUTLS */
208 #endif /* USE_SSLEAY */
210 #else
211 /* without SSL */
212 (void)conn;
213 (void)sockindex;
214 return CURLE_OK;
215 #endif /* USE_SSL */
218 CURLcode
219 Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
220 bool *done)
222 #if defined(USE_SSL) && defined(USE_SSLEAY)
223 /* mark this is being ssl enabled from here on. */
224 conn->ssl[sockindex].use = TRUE;
225 return Curl_ossl_connect_nonblocking(conn, sockindex, done);
227 #else
228 /* not implemented!
229 fallback to BLOCKING call. */
230 *done = TRUE;
231 return Curl_ssl_connect(conn, sockindex);
232 #endif
235 #ifdef USE_SSL
238 * Check if there's a session ID for the given connection in the cache, and if
239 * there's one suitable, it is provided. Returns TRUE when no entry matched.
241 int Curl_ssl_getsessionid(struct connectdata *conn,
242 void **ssl_sessionid,
243 size_t *idsize) /* set 0 if unknown */
245 struct curl_ssl_session *check;
246 struct SessionHandle *data = conn->data;
247 long i;
249 if(!conn->ssl_config.sessionid)
250 /* session ID re-use is disabled */
251 return TRUE;
253 for(i=0; i< data->set.ssl.numsessions; i++) {
254 check = &data->state.session[i];
255 if(!check->sessionid)
256 /* not session ID means blank entry */
257 continue;
258 if(curl_strequal(conn->host.name, check->name) &&
259 (conn->remote_port == check->remote_port) &&
260 Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
261 /* yes, we have a session ID! */
262 data->state.sessionage++; /* increase general age */
263 check->age = data->state.sessionage; /* set this as used in this age */
264 *ssl_sessionid = check->sessionid;
265 if(idsize)
266 *idsize = check->idsize;
267 return FALSE;
270 *ssl_sessionid = NULL;
271 return TRUE;
275 * Kill a single session ID entry in the cache.
277 static int kill_session(struct curl_ssl_session *session)
279 if(session->sessionid) {
280 /* defensive check */
282 /* free the ID the SSL-layer specific way */
283 #ifdef USE_SSLEAY
284 Curl_ossl_session_free(session->sessionid);
285 #else
286 Curl_gtls_session_free(session->sessionid);
287 #endif
288 session->sessionid=NULL;
289 session->age = 0; /* fresh */
291 Curl_free_ssl_config(&session->ssl_config);
293 Curl_safefree(session->name);
294 session->name = NULL; /* no name */
296 return 0; /* ok */
298 else
299 return 1;
303 * Store session id in the session cache. The ID passed on to this function
304 * must already have been extracted and allocated the proper way for the SSL
305 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
306 * later on.
308 CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
309 void *ssl_sessionid,
310 size_t idsize)
312 int i;
313 struct SessionHandle *data=conn->data; /* the mother of all structs */
314 struct curl_ssl_session *store = &data->state.session[0];
315 long oldest_age=data->state.session[0].age; /* zero if unused */
316 char *clone_host;
318 /* Even though session ID re-use might be disabled, that only disables USING
319 IT. We still store it here in case the re-using is again enabled for an
320 upcoming transfer */
322 clone_host = strdup(conn->host.name);
323 if(!clone_host)
324 return CURLE_OUT_OF_MEMORY; /* bail out */
326 /* Now we should add the session ID and the host name to the cache, (remove
327 the oldest if necessary) */
329 /* find an empty slot for us, or find the oldest */
330 for(i=1; (i<data->set.ssl.numsessions) &&
331 data->state.session[i].sessionid; i++) {
332 if(data->state.session[i].age < oldest_age) {
333 oldest_age = data->state.session[i].age;
334 store = &data->state.session[i];
337 if(i == data->set.ssl.numsessions)
338 /* cache is full, we must "kill" the oldest entry! */
339 kill_session(store);
340 else
341 store = &data->state.session[i]; /* use this slot */
343 /* now init the session struct wisely */
344 store->sessionid = ssl_sessionid;
345 store->idsize = idsize;
346 store->age = data->state.sessionage; /* set current age */
347 store->name = clone_host; /* clone host name */
348 store->remote_port = conn->remote_port; /* port number */
350 if (!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config))
351 return CURLE_OUT_OF_MEMORY;
353 return CURLE_OK;
357 #endif
359 void Curl_ssl_close_all(struct SessionHandle *data)
361 #ifdef USE_SSL
362 int i;
363 /* kill the session ID cache */
364 if(data->state.session) {
365 for(i=0; i< data->set.ssl.numsessions; i++)
366 /* the single-killer function handles empty table slots */
367 kill_session(&data->state.session[i]);
369 /* free the cache data */
370 free(data->state.session);
371 data->state.session = NULL;
373 #ifdef USE_SSLEAY
374 Curl_ossl_close_all(data);
375 #else
376 #ifdef USE_GNUTLS
377 Curl_gtls_close_all(data);
378 #endif /* USE_GNUTLS */
379 #endif /* USE_SSLEAY */
380 #else /* USE_SSL */
381 (void)data;
382 #endif /* USE_SSL */
385 void Curl_ssl_close(struct connectdata *conn)
387 if(conn->ssl[FIRSTSOCKET].use) {
388 #ifdef USE_SSLEAY
389 Curl_ossl_close(conn);
390 #else
391 #ifdef USE_GNUTLS
392 Curl_gtls_close(conn);
393 #else
394 (void)conn;
395 #endif /* USE_GNUTLS */
396 #endif /* USE_SSLEAY */
400 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
402 if(conn->ssl[sockindex].use) {
403 #ifdef USE_SSLEAY
404 if(Curl_ossl_shutdown(conn, sockindex))
405 return CURLE_SSL_SHUTDOWN_FAILED;
406 #else
407 #ifdef USE_GNUTLS
408 if(Curl_gtls_shutdown(conn, sockindex))
409 return CURLE_SSL_SHUTDOWN_FAILED;
410 #else
411 (void)conn;
412 (void)sockindex;
413 #endif /* USE_GNUTLS */
414 #endif /* USE_SSLEAY */
416 return CURLE_OK;
419 /* Selects an (Open)SSL crypto engine
421 CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
423 #ifdef USE_SSLEAY
424 return Curl_ossl_set_engine(data, engine);
425 #else
426 #ifdef USE_GNUTLS
427 /* FIX: add code here */
428 (void)data;
429 (void)engine;
430 return CURLE_FAILED_INIT;
431 #else
432 /* no SSL layer */
433 (void)data;
434 (void)engine;
435 return CURLE_FAILED_INIT;
436 #endif /* USE_GNUTLS */
437 #endif /* USE_SSLEAY */
440 /* Selects an (Open?)SSL crypto engine
442 CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
444 #ifdef USE_SSLEAY
445 return Curl_ossl_set_engine_default(data);
446 #else
447 #ifdef USE_GNUTLS
448 /* FIX: add code here */
449 (void)data;
450 return CURLE_FAILED_INIT;
451 #else
452 /* No SSL layer */
453 (void)data;
454 return CURLE_FAILED_INIT;
455 #endif /* USE_GNUTLS */
456 #endif /* USE_SSLEAY */
459 /* Return list of OpenSSL crypto engine names. */
460 struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
462 #ifdef USE_SSLEAY
463 return Curl_ossl_engines_list(data);
464 #else
465 #ifdef USE_GNUTLS
466 /* FIX: add code here? */
467 (void)data;
468 return NULL;
469 #else
470 (void)data;
471 return NULL;
472 #endif /* USE_GNUTLS */
473 #endif /* USE_SSLEAY */
476 /* return number of sent (non-SSL) bytes */
477 ssize_t Curl_ssl_send(struct connectdata *conn,
478 int sockindex,
479 void *mem,
480 size_t len)
482 #ifdef USE_SSLEAY
483 return Curl_ossl_send(conn, sockindex, mem, len);
484 #else
485 #ifdef USE_GNUTLS
486 return Curl_gtls_send(conn, sockindex, mem, len);
487 #else
488 (void)conn;
489 (void)sockindex;
490 (void)mem;
491 (void)len;
492 return 0;
493 #endif /* USE_GNUTLS */
494 #endif /* USE_SSLEAY */
497 /* return number of received (decrypted) bytes */
500 * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
501 * a regular CURLcode value.
503 ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */
504 int sockindex, /* socketindex */
505 char *mem, /* store read data here */
506 size_t len) /* max amount to read */
508 #ifdef USE_SSL
509 ssize_t nread;
510 bool block = FALSE;
512 #ifdef USE_SSLEAY
513 nread = Curl_ossl_recv(conn, sockindex, mem, len, &block);
514 #else
515 #ifdef USE_GNUTLS
516 nread = Curl_gtls_recv(conn, sockindex, mem, len, &block);
517 #endif /* USE_GNUTLS */
518 #endif /* USE_SSLEAY */
519 if(nread == -1) {
520 if(!block)
521 return 0; /* this is a true error, not EWOULDBLOCK */
522 else
523 return -1;
526 return (int)nread;
528 #else /* USE_SSL */
529 (void)conn;
530 (void)sockindex;
531 (void)mem;
532 (void)len;
533 return 0;
534 #endif /* USE_SSL */
539 * This sets up a session ID cache to the specified size. Make sure this code
540 * is agnostic to what underlying SSL technology we use.
542 CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount)
544 #ifdef USE_SSL
545 struct curl_ssl_session *session;
547 if(data->state.session)
548 /* this is just a precaution to prevent multiple inits */
549 return CURLE_OK;
551 session = (struct curl_ssl_session *)
552 calloc(sizeof(struct curl_ssl_session), amount);
553 if(!session)
554 return CURLE_OUT_OF_MEMORY;
556 /* store the info in the SSL section */
557 data->set.ssl.numsessions = amount;
558 data->state.session = session;
559 data->state.sessionage = 1; /* this is brand new */
560 #else
561 /* without SSL, do nothing */
562 (void)data;
563 (void)amount;
564 #endif
566 return CURLE_OK;
569 size_t Curl_ssl_version(char *buffer, size_t size)
571 #ifdef USE_SSLEAY
572 return Curl_ossl_version(buffer, size);
573 #else
574 #ifdef USE_GNUTLS
575 return Curl_gtls_version(buffer, size);
576 #else
577 (void)buffer;
578 (void)size;
579 return 0; /* no SSL support */
580 #endif /* USE_GNUTLS */
581 #endif /* USE_SSLEAY */
586 * This function tries to determine connection status.
588 * Return codes:
589 * 1 means the connection is still in place
590 * 0 means the connection has been closed
591 * -1 means the connection status is unknown
593 int Curl_ssl_check_cxn(struct connectdata *conn)
595 #ifdef USE_SSLEAY
596 return Curl_ossl_check_cxn(conn);
597 #else
598 (void)conn;
599 /* TODO: we lack implementation of this for GnuTLS */
600 return -1; /* connection status unknown */
601 #endif /* USE_SSLEAY */
604 bool Curl_ssl_data_pending(struct connectdata *conn,
605 int connindex)
607 #ifdef USE_SSLEAY
608 /* OpenSSL-specific */
609 if(conn->ssl[connindex].handle)
610 /* SSL is in use */
611 return SSL_pending(conn->ssl[connindex].handle);
612 #else
613 (void)conn;
614 (void)connindex;
615 #endif
616 return FALSE; /* nothing pending */