1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, 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.1.1.1 2008-09-23 16:32:05 hoffman 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
34 Curl_nss_ - prefix for NSS 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 */
64 /* The last #include file should be: */
67 static bool safe_strequal(char* str1
, char* str2
);
69 static bool safe_strequal(char* str1
, char* str2
)
72 /* both pointers point to something then compare them */
73 return (bool)(0 != strequal(str1
, str2
));
75 /* if both pointers are NULL then treat them as equal */
76 return (bool)(!str1
&& !str2
);
80 Curl_ssl_config_matches(struct ssl_config_data
* data
,
81 struct ssl_config_data
* needle
)
83 if((data
->version
== needle
->version
) &&
84 (data
->verifypeer
== needle
->verifypeer
) &&
85 (data
->verifyhost
== needle
->verifyhost
) &&
86 safe_strequal(data
->CApath
, needle
->CApath
) &&
87 safe_strequal(data
->CAfile
, needle
->CAfile
) &&
88 safe_strequal(data
->random_file
, needle
->random_file
) &&
89 safe_strequal(data
->egdsocket
, needle
->egdsocket
) &&
90 safe_strequal(data
->cipher_list
, needle
->cipher_list
))
97 Curl_clone_ssl_config(struct ssl_config_data
*source
,
98 struct ssl_config_data
*dest
)
100 dest
->sessionid
= source
->sessionid
;
101 dest
->verifyhost
= source
->verifyhost
;
102 dest
->verifypeer
= source
->verifypeer
;
103 dest
->version
= source
->version
;
106 dest
->CAfile
= strdup(source
->CAfile
);
112 dest
->CApath
= strdup(source
->CApath
);
117 if(source
->cipher_list
) {
118 dest
->cipher_list
= strdup(source
->cipher_list
);
119 if(!dest
->cipher_list
)
123 if(source
->egdsocket
) {
124 dest
->egdsocket
= strdup(source
->egdsocket
);
129 if(source
->random_file
) {
130 dest
->random_file
= strdup(source
->random_file
);
131 if(!dest
->random_file
)
138 void Curl_free_ssl_config(struct ssl_config_data
* sslc
)
140 Curl_safefree(sslc
->CAfile
);
141 Curl_safefree(sslc
->CApath
);
142 Curl_safefree(sslc
->cipher_list
);
143 Curl_safefree(sslc
->egdsocket
);
144 Curl_safefree(sslc
->random_file
);
149 /* "global" init done? */
150 static bool init_ssl
=FALSE
;
155 * @retval 0 error initializing SSL
156 * @retval 1 SSL initialized successfully
158 int Curl_ssl_init(void)
160 /* make sure this is only done once */
163 init_ssl
= TRUE
; /* never again */
165 return curlssl_init();
170 void Curl_ssl_cleanup(void)
173 /* only cleanup if we did a previous init */
180 Curl_ssl_connect(struct connectdata
*conn
, int sockindex
)
183 /* mark this is being ssl-enabled from here on. */
184 conn
->ssl
[sockindex
].use
= TRUE
;
185 conn
->ssl
[sockindex
].state
= ssl_connection_negotiating
;
187 res
= curlssl_connect(conn
, sockindex
);
190 Curl_pgrsTime(conn
->data
, TIMER_APPCONNECT
); /* SSL is connected */
196 Curl_ssl_connect_nonblocking(struct connectdata
*conn
, int sockindex
,
199 #ifdef curlssl_connect_nonblocking
200 /* mark this is being ssl requested from here on. */
201 conn
->ssl
[sockindex
].use
= TRUE
;
202 return curlssl_connect_nonblocking(conn
, sockindex
, done
);
204 *done
= TRUE
; /* fallback to BLOCKING */
205 conn
->ssl
[sockindex
].use
= TRUE
;
206 return curlssl_connect(conn
, sockindex
);
207 #endif /* non-blocking connect support */
211 * Check if there's a session ID for the given connection in the cache, and if
212 * there's one suitable, it is provided. Returns TRUE when no entry matched.
214 int Curl_ssl_getsessionid(struct connectdata
*conn
,
215 void **ssl_sessionid
,
216 size_t *idsize
) /* set 0 if unknown */
218 struct curl_ssl_session
*check
;
219 struct SessionHandle
*data
= conn
->data
;
222 if(!conn
->ssl_config
.sessionid
)
223 /* session ID re-use is disabled */
226 for(i
=0; i
< data
->set
.ssl
.numsessions
; i
++) {
227 check
= &data
->state
.session
[i
];
228 if(!check
->sessionid
)
229 /* not session ID means blank entry */
231 if(curl_strequal(conn
->host
.name
, check
->name
) &&
232 (conn
->remote_port
== check
->remote_port
) &&
233 Curl_ssl_config_matches(&conn
->ssl_config
, &check
->ssl_config
)) {
234 /* yes, we have a session ID! */
235 data
->state
.sessionage
++; /* increase general age */
236 check
->age
= data
->state
.sessionage
; /* set this as used in this age */
237 *ssl_sessionid
= check
->sessionid
;
239 *idsize
= check
->idsize
;
243 *ssl_sessionid
= NULL
;
248 * Kill a single session ID entry in the cache.
250 static int kill_session(struct curl_ssl_session
*session
)
252 if(session
->sessionid
) {
253 /* defensive check */
255 /* free the ID the SSL-layer specific way */
256 curlssl_session_free(session
->sessionid
);
258 session
->sessionid
=NULL
;
259 session
->age
= 0; /* fresh */
261 Curl_free_ssl_config(&session
->ssl_config
);
263 Curl_safefree(session
->name
);
264 session
->name
= NULL
; /* no name */
273 * Store session id in the session cache. The ID passed on to this function
274 * must already have been extracted and allocated the proper way for the SSL
275 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
278 CURLcode
Curl_ssl_addsessionid(struct connectdata
*conn
,
283 struct SessionHandle
*data
=conn
->data
; /* the mother of all structs */
284 struct curl_ssl_session
*store
= &data
->state
.session
[0];
285 long oldest_age
=data
->state
.session
[0].age
; /* zero if unused */
288 /* Even though session ID re-use might be disabled, that only disables USING
289 IT. We still store it here in case the re-using is again enabled for an
292 clone_host
= strdup(conn
->host
.name
);
294 return CURLE_OUT_OF_MEMORY
; /* bail out */
296 /* Now we should add the session ID and the host name to the cache, (remove
297 the oldest if necessary) */
299 /* find an empty slot for us, or find the oldest */
300 for(i
=1; (i
<data
->set
.ssl
.numsessions
) &&
301 data
->state
.session
[i
].sessionid
; i
++) {
302 if(data
->state
.session
[i
].age
< oldest_age
) {
303 oldest_age
= data
->state
.session
[i
].age
;
304 store
= &data
->state
.session
[i
];
307 if(i
== data
->set
.ssl
.numsessions
)
308 /* cache is full, we must "kill" the oldest entry! */
311 store
= &data
->state
.session
[i
]; /* use this slot */
313 /* now init the session struct wisely */
314 store
->sessionid
= ssl_sessionid
;
315 store
->idsize
= idsize
;
316 store
->age
= data
->state
.sessionage
; /* set current age */
318 /* free it if there's one already present */
320 store
->name
= clone_host
; /* clone host name */
321 store
->remote_port
= conn
->remote_port
; /* port number */
323 if(!Curl_clone_ssl_config(&conn
->ssl_config
, &store
->ssl_config
))
324 return CURLE_OUT_OF_MEMORY
;
330 void Curl_ssl_close_all(struct SessionHandle
*data
)
333 /* kill the session ID cache */
334 if(data
->state
.session
) {
335 for(i
=0; i
< data
->set
.ssl
.numsessions
; i
++)
336 /* the single-killer function handles empty table slots */
337 kill_session(&data
->state
.session
[i
]);
339 /* free the cache data */
340 free(data
->state
.session
);
341 data
->state
.session
= NULL
;
344 curlssl_close_all(data
);
347 void Curl_ssl_close(struct connectdata
*conn
, int sockindex
)
349 DEBUGASSERT((sockindex
<= 1) && (sockindex
>= -1));
350 curlssl_close(conn
, sockindex
);
353 CURLcode
Curl_ssl_shutdown(struct connectdata
*conn
, int sockindex
)
355 if(curlssl_shutdown(conn
, sockindex
))
356 return CURLE_SSL_SHUTDOWN_FAILED
;
358 conn
->ssl
[sockindex
].use
= FALSE
; /* get back to ordinary socket usage */
359 conn
->ssl
[sockindex
].state
= ssl_connection_none
;
364 /* Selects an SSL crypto engine
366 CURLcode
Curl_ssl_set_engine(struct SessionHandle
*data
, const char *engine
)
368 return curlssl_set_engine(data
, engine
);
371 /* Selects the default SSL crypto engine
373 CURLcode
Curl_ssl_set_engine_default(struct SessionHandle
*data
)
375 return curlssl_set_engine_default(data
);
378 /* Return list of OpenSSL crypto engine names. */
379 struct curl_slist
*Curl_ssl_engines_list(struct SessionHandle
*data
)
381 return curlssl_engines_list(data
);
384 /* return number of sent (non-SSL) bytes */
385 ssize_t
Curl_ssl_send(struct connectdata
*conn
,
390 return curlssl_send(conn
, sockindex
, mem
, len
);
393 /* return number of received (decrypted) bytes */
396 * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
397 * a regular CURLcode value.
399 ssize_t
Curl_ssl_recv(struct connectdata
*conn
, /* connection data */
400 int sockindex
, /* socketindex */
401 char *mem
, /* store read data here */
402 size_t len
) /* max amount to read */
407 nread
= curlssl_recv(conn
, sockindex
, mem
, len
, &block
);
410 return 0; /* this is a true error, not EWOULDBLOCK */
420 * This sets up a session ID cache to the specified size. Make sure this code
421 * is agnostic to what underlying SSL technology we use.
423 CURLcode
Curl_ssl_initsessions(struct SessionHandle
*data
, long amount
)
425 struct curl_ssl_session
*session
;
427 if(data
->state
.session
)
428 /* this is just a precaution to prevent multiple inits */
431 session
= (struct curl_ssl_session
*)
432 calloc(sizeof(struct curl_ssl_session
), amount
);
434 return CURLE_OUT_OF_MEMORY
;
436 /* store the info in the SSL section */
437 data
->set
.ssl
.numsessions
= amount
;
438 data
->state
.session
= session
;
439 data
->state
.sessionage
= 1; /* this is brand new */
443 size_t Curl_ssl_version(char *buffer
, size_t size
)
445 return curlssl_version(buffer
, size
);
449 * This function tries to determine connection status.
452 * 1 means the connection is still in place
453 * 0 means the connection has been closed
454 * -1 means the connection status is unknown
456 int Curl_ssl_check_cxn(struct connectdata
*conn
)
458 return curlssl_check_cxn(conn
);
461 bool Curl_ssl_data_pending(const struct connectdata
*conn
,
464 return curlssl_data_pending(conn
, connindex
);