1 /***************************************************************************
3 * Project ___| | | | _ \| |
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
43 #ifdef HAVE_SYS_TYPES_H
44 #include <sys/types.h>
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
52 #include "sslgen.h" /* generic SSL protos etc */
53 #include "ssluse.h" /* OpenSSL versions */
54 #include "gtls.h" /* GnuTLS versions */
59 /* The last #include file should be: */
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
)
70 /* both pointers point to something then compare them */
71 return (bool)(0 != strequal(str1
, str2
));
73 /* if both pointers are NULL then treat them as equal */
74 return (bool)(!str1
&& !str2
);
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
))
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
;
103 dest
->CAfile
= strdup(source
->CAfile
);
109 dest
->CApath
= strdup(source
->CApath
);
114 if(source
->cipher_list
) {
115 dest
->cipher_list
= strdup(source
->cipher_list
);
116 if(!dest
->cipher_list
)
120 if(source
->egdsocket
) {
121 dest
->egdsocket
= strdup(source
->egdsocket
);
126 if(source
->random_file
) {
127 dest
->random_file
= strdup(source
->random_file
);
128 if(!dest
->random_file
)
135 void Curl_free_ssl_config(struct ssl_config_data
* sslc
)
143 if(sslc
->cipher_list
)
144 free(sslc
->cipher_list
);
147 free(sslc
->egdsocket
);
149 if(sslc
->random_file
)
150 free(sslc
->random_file
);
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 */
164 init_ssl
= TRUE
; /* never again */
167 return Curl_ossl_init();
170 return Curl_gtls_init();
174 #endif /* USE_GNUTLS */
175 #endif /* USE_SSLEAY */
180 void Curl_ssl_cleanup(void)
183 /* only cleanup if we did a previous init */
189 #endif /* USE_GNUTLS */
190 #endif /* USE_SSLEAY */
196 Curl_ssl_connect(struct connectdata
*conn
, int sockindex
)
199 /* mark this is being ssl enabled from here on. */
200 conn
->ssl
[sockindex
].use
= TRUE
;
203 return Curl_ossl_connect(conn
, sockindex
);
206 return Curl_gtls_connect(conn
, sockindex
);
207 #endif /* USE_GNUTLS */
208 #endif /* USE_SSLEAY */
219 Curl_ssl_connect_nonblocking(struct connectdata
*conn
, int sockindex
,
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
);
229 fallback to BLOCKING call. */
231 return Curl_ssl_connect(conn
, sockindex
);
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
;
249 if(!conn
->ssl_config
.sessionid
)
250 /* session ID re-use is disabled */
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 */
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
;
266 *idsize
= check
->idsize
;
270 *ssl_sessionid
= NULL
;
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 */
284 Curl_ossl_session_free(session
->sessionid
);
286 Curl_gtls_session_free(session
->sessionid
);
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 */
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
308 CURLcode
Curl_ssl_addsessionid(struct connectdata
*conn
,
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 */
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
322 clone_host
= strdup(conn
->host
.name
);
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! */
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
;
359 void Curl_ssl_close_all(struct SessionHandle
*data
)
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
;
374 Curl_ossl_close_all(data
);
377 Curl_gtls_close_all(data
);
378 #endif /* USE_GNUTLS */
379 #endif /* USE_SSLEAY */
385 void Curl_ssl_close(struct connectdata
*conn
)
387 if(conn
->ssl
[FIRSTSOCKET
].use
) {
389 Curl_ossl_close(conn
);
392 Curl_gtls_close(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
) {
404 if(Curl_ossl_shutdown(conn
, sockindex
))
405 return CURLE_SSL_SHUTDOWN_FAILED
;
408 if(Curl_gtls_shutdown(conn
, sockindex
))
409 return CURLE_SSL_SHUTDOWN_FAILED
;
413 #endif /* USE_GNUTLS */
414 #endif /* USE_SSLEAY */
419 /* Selects an (Open)SSL crypto engine
421 CURLcode
Curl_ssl_set_engine(struct SessionHandle
*data
, const char *engine
)
424 return Curl_ossl_set_engine(data
, engine
);
427 /* FIX: add code here */
430 return CURLE_FAILED_INIT
;
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
)
445 return Curl_ossl_set_engine_default(data
);
448 /* FIX: add code here */
450 return CURLE_FAILED_INIT
;
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
)
463 return Curl_ossl_engines_list(data
);
466 /* FIX: add code here? */
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
,
483 return Curl_ossl_send(conn
, sockindex
, mem
, len
);
486 return Curl_gtls_send(conn
, sockindex
, mem
, len
);
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 */
513 nread
= Curl_ossl_recv(conn
, sockindex
, mem
, len
, &block
);
516 nread
= Curl_gtls_recv(conn
, sockindex
, mem
, len
, &block
);
517 #endif /* USE_GNUTLS */
518 #endif /* USE_SSLEAY */
521 return 0; /* this is a true error, not EWOULDBLOCK */
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
)
545 struct curl_ssl_session
*session
;
547 if(data
->state
.session
)
548 /* this is just a precaution to prevent multiple inits */
551 session
= (struct curl_ssl_session
*)
552 calloc(sizeof(struct curl_ssl_session
), amount
);
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 */
561 /* without SSL, do nothing */
569 size_t Curl_ssl_version(char *buffer
, size_t size
)
572 return Curl_ossl_version(buffer
, size
);
575 return Curl_gtls_version(buffer
, size
);
579 return 0; /* no SSL support */
580 #endif /* USE_GNUTLS */
581 #endif /* USE_SSLEAY */
586 * This function tries to determine connection status.
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
)
596 return Curl_ossl_check_cxn(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
,
608 /* OpenSSL-specific */
609 if(conn
->ssl
[connindex
].handle
)
611 return SSL_pending(conn
->ssl
[connindex
].handle
);
616 return FALSE
; /* nothing pending */