1 /* SSL support - wrappers for SSL routines */
8 #include <openssl/ssl.h>
9 #include <openssl/rand.h>
11 #elif defined(CONFIG_NSS_COMPAT_OSSL)
12 #include <nss_compat_ossl/nss_compat_ossl.h>
14 #elif defined(CONFIG_GNUTLS)
16 #include <gnutls/gnutls.h>
17 #include <gnutls/x509.h>
19 #error "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And then you want exactly *what* from me?"
28 #include "intl/gettext/libintl.h"
29 #include "main/module.h"
30 #include "network/connection.h"
31 #include "network/socket.h"
32 #include "network/ssl/ssl.h"
33 #include "util/conv.h"
34 #include "util/error.h"
35 #include "util/string.h"
36 #include "util/random.h"
39 /* FIXME: As you can see, SSL is currently implemented in very, erm,
40 * decentralized manner. */
45 #define PATH_MAX 256 /* according to my /usr/include/bits/posix1_lim.h */
48 static SSL_CTX
*context
= NULL
;
49 int socket_SSL_ex_data_idx
= -1;
51 /** Prevent SSL_dup() if the SSL is associated with struct socket.
52 * We cannot copy struct socket and it doesn't have a reference count
55 socket_SSL_ex_data_dup(CRYPTO_EX_DATA
*to
, CRYPTO_EX_DATA
*from
,
56 void *from_d
, int idx
, long argl
, void *argp
)
58 /* The documentation of from_d in RSA_get_ex_new_index(3)
59 * is a bit unclear. The caller does something like:
61 * void *data = CRYPTO_get_ex_data(from, idx);
62 * socket_SSL_dup(to, from, &data, idx, argl, argp);
63 * CRYPTO_set_ex_data(to, idx, data);
65 * i.e., from_d always points to a pointer, even though
66 * it is just a void * in the prototype. */
67 struct socket
*socket
= *(void **) from_d
;
69 assert(idx
== socket_SSL_ex_data_idx
);
70 if_assert_failed
return 0;
73 return 0; /* prevent SSL_dup() */
75 return 1; /* allow SSL_dup() */
79 init_openssl(struct module
*module
)
81 unsigned char f_randfile
[PATH_MAX
];
83 /* In a nutshell, on OS's without a /dev/urandom, the OpenSSL library
84 * cannot initialize the PRNG and so every attempt to use SSL fails.
85 * It's actually an OpenSSL FAQ, and according to them, it's up to the
86 * application coders to seed the RNG. -- William Yodlowsky */
87 RAND_file_name(f_randfile
, sizeof(f_randfile
));
89 if (RAND_egd(f_randfile
) < 0) {
90 /* Not an EGD, so read and write to it */
92 if (RAND_load_file(f_randfile
, -1))
93 RAND_write_file(f_randfile
);
98 SSLeay_add_ssl_algorithms();
99 context
= SSL_CTX_new(SSLv23_client_method());
100 SSL_CTX_set_options(context
, SSL_OP_ALL
);
101 SSL_CTX_set_default_verify_paths(context
);
102 socket_SSL_ex_data_idx
= SSL_get_ex_new_index(0, NULL
,
104 socket_SSL_ex_data_dup
,
109 done_openssl(struct module
*module
)
111 if (context
) SSL_CTX_free(context
);
112 /* There is no function that undoes SSL_get_ex_new_index. */
115 static union option_info openssl_options
[] = {
116 INIT_OPT_BOOL("connection.ssl", N_("Verify certificates"),
118 N_("Verify the peer's SSL certificate. Note that this "
119 "needs extensive configuration of OpenSSL by the user.")),
121 INIT_OPT_TREE("connection.ssl", N_("Client Certificates"),
122 "client_cert", OPT_SORT
,
123 N_("X509 client certificate options.")),
125 INIT_OPT_BOOL("connection.ssl.client_cert", N_("Enable"),
127 N_("Enable or not the sending of X509 client certificates "
128 "to servers which request them.")),
130 #ifdef CONFIG_NSS_COMPAT_OSSL
131 INIT_OPT_STRING("connection.ssl.client_cert", N_("Certificate nickname"),
133 N_("The nickname of the client certificate stored in NSS "
134 "database. If this value is unset, the nickname from "
135 "the X509_CLIENT_CERT variable is used instead. If you "
136 "have a PKCS#12 file containing client certificate, you "
137 "can import it into your NSS database with:\n"
139 "$ pk12util -i mycert.p12 -d /path/to/database\n"
141 "The NSS database location can be changed by SSL_DIR "
142 "environment variable. The database can be also shared "
143 "with Mozilla browsers.")),
145 INIT_OPT_STRING("connection.ssl.client_cert", N_("Certificate File"),
147 N_("The location of a file containing the client certificate "
148 "and unencrypted private key in PEM format. If unset, the "
149 "file pointed to by the X509_CLIENT_CERT variable is used "
156 static struct module openssl_module
= struct_module(
157 /* name: */ "OpenSSL",
158 /* options: */ openssl_options
,
160 /* submodules: */ NULL
,
162 /* init: */ init_openssl
,
163 /* done: */ done_openssl
166 #elif defined(CONFIG_GNUTLS)
168 static gnutls_anon_client_credentials_t anon_cred
= NULL
;
169 static gnutls_certificate_credentials_t xcred
= NULL
;
172 const static int kx_priority
[16] = {
173 GNUTLS_KX_RSA
, GNUTLS_KX_DHE_DSS
, GNUTLS_KX_DHE_RSA
, GNUTLS_KX_SRP
,
174 /* Do not use anonymous authentication, unless you know what that means */
175 GNUTLS_KX_ANON_DH
, GNUTLS_KX_RSA_EXPORT
, 0
177 const static int cipher_priority
[16] = {
178 GNUTLS_CIPHER_RIJNDAEL_128_CBC
, GNUTLS_CIPHER_ARCFOUR_128
,
179 GNUTLS_CIPHER_3DES_CBC
, GNUTLS_CIPHER_AES_256_CBC
, GNUTLS_CIPHER_ARCFOUR_40
, 0
181 const static int cert_type_priority
[16] = { GNUTLS_CRT_X509
, GNUTLS_CRT_OPENPGP
, 0 };
185 init_gnutls(struct module
*module
)
187 int ret
= gnutls_global_init();
188 unsigned char *ca_file
= get_opt_str("connection.ssl.trusted_ca_file",
192 INTERNAL("GNUTLS init failed: %s", gnutls_strerror(ret
));
194 ret
= gnutls_anon_allocate_client_credentials(&anon_cred
);
196 INTERNAL("GNUTLS anon credentials alloc failed: %s",
197 gnutls_strerror(ret
));
199 ret
= gnutls_certificate_allocate_credentials(&xcred
);
201 INTERNAL("GNUTLS X509 credentials alloc failed: %s",
202 gnutls_strerror(ret
));
203 /* Here, we should load certificate files etc. */
205 /* FIXME: check returned values. --witekfl */
206 gnutls_certificate_set_x509_trust_file(xcred
, ca_file
,
207 GNUTLS_X509_FMT_PEM
);
209 gnutls_certificate_set_verify_flags(xcred
,
210 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT
);
216 done_gnutls(struct module
*module
)
218 if (xcred
) gnutls_certificate_free_credentials(xcred
);
219 if (anon_cred
) gnutls_anon_free_client_credentials(anon_cred
);
220 gnutls_global_deinit();
223 static union option_info gnutls_options
[] = {
224 INIT_OPT_BOOL("connection.ssl", N_("Verify certificates"),
226 N_("Verify the peer's SSL certificate. If you enable "
227 "this, set also \"Trusted CA file\".")),
229 /* The default value of the following option points to a file
230 * generated by the ca-certificates Debian package. Don't use
231 * CONFDIR here: if someone installs ELinks in $HOME and wants
232 * to have a user-specific trust list, he or she can just
233 * change the file name via the option manager. Distributors
234 * of binary packages should of course change the default to
235 * suit their systems.
236 * TODO: If the file name is relative, look in elinks_home? */
237 INIT_OPT_STRING("connection.ssl", N_("Trusted CA file"),
238 "trusted_ca_file", 0, "/etc/ssl/certs/ca-certificates.crt",
239 N_("The location of a file containing certificates of "
240 "trusted certification authorities in PEM format. "
241 "ELinks then trusts certificates issued by these CAs.\n"
243 "If you change this option or the file, you must "
244 "restart ELinks for the changes to take effect. "
245 "This option affects GnuTLS but not OpenSSL.")),
250 static struct module gnutls_module
= struct_module(
251 /* name: */ "GnuTLS",
252 /* options: */ gnutls_options
,
254 /* submodules: */ NULL
,
256 /* init: */ init_gnutls
,
257 /* done: */ done_gnutls
260 #endif /* USE_OPENSSL or CONFIG_GNUTLS */
262 static union option_info ssl_options
[] = {
263 INIT_OPT_TREE("connection", N_("SSL"),
270 static struct module
*ssl_modules
[] = {
273 #elif defined(CONFIG_GNUTLS)
279 struct module ssl_module
= struct_module(
280 /* name: */ N_("SSL"),
281 /* options: */ ssl_options
,
283 /* submodules: */ ssl_modules
,
290 init_ssl_connection(struct socket
*socket
,
291 const unsigned char *server_name
)
294 socket
->ssl
= SSL_new(context
);
295 if (!socket
->ssl
) return S_SSL_ERROR
;
297 if (!SSL_set_ex_data(socket
->ssl
, socket_SSL_ex_data_idx
, socket
)) {
298 SSL_free(socket
->ssl
);
303 /* If the server name is known, pass it to OpenSSL.
305 * The return value of SSL_set_tlsext_host_name is not
306 * documented. The source shows that it returns 1 if
307 * successful; on error, it calls SSLerr and returns 0. */
309 && !SSL_set_tlsext_host_name(socket
->ssl
, server_name
)) {
310 SSL_free(socket
->ssl
);
315 #elif defined(CONFIG_GNUTLS)
316 ssl_t
*state
= mem_alloc(sizeof(ssl_t
));
318 if (!state
) return S_SSL_ERROR
;
320 if (gnutls_init(state
, GNUTLS_CLIENT
) < 0) {
321 /* DBG("sslinit %s", gnutls_strerror(ret)); */
326 if (gnutls_cred_set(*state
, GNUTLS_CRD_ANON
, anon_cred
) < 0) {
327 /* DBG("sslanoncred %s", gnutls_strerror(ret)); */
328 gnutls_deinit(*state
);
333 if (gnutls_cred_set(*state
, GNUTLS_CRD_CERTIFICATE
, xcred
) < 0) {
334 /* DBG("sslx509cred %s", gnutls_strerror(ret)); */
335 gnutls_deinit(*state
);
340 #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
341 /* Disable OpenPGP certificates because they are not widely
342 * used and ELinks does not yet support verifying them.
343 * Besides, in GnuTLS < 2.4.0, they require the gnutls-extra
344 * library, whose GPLv3+ is not compatible with GPLv2 of
347 * Disable TLS1.1 because https://bugzilla.novell.com/ does
348 * not reply to it and leaves the connection open so that
349 * ELinks does not detect an SSL error but rather times out.
350 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=528661#25
352 * There is another gnutls_priority_set_direct call elsewhere
353 * in ELinks. If you change the priorities here, please check
354 * whether that one needs to be changed as well. */
355 if (gnutls_priority_set_direct(*state
,
356 "NORMAL:-CTYPE-OPENPGP:-VERS-TLS1.1:-VERS-SSL3.0",
358 gnutls_deinit(*state
);
363 gnutls_set_default_priority(*state
);
366 /* Deprecated functions */
367 /* gnutls_handshake_set_private_extensions(*state, 1); */
368 gnutls_cipher_set_priority(*state
, cipher_priority
);
369 gnutls_kx_set_priority(*state
, kx_priority
);
370 /* gnutls_certificate_type_set_priority(*state, cert_type_priority); */
374 && gnutls_server_name_set(*state
, GNUTLS_NAME_DNS
, server_name
,
375 strlen(server_name
))) {
376 gnutls_deinit(*state
);
388 done_ssl_connection(struct socket
*socket
)
390 ssl_t
*ssl
= socket
->ssl
;
395 #elif defined(CONFIG_GNUTLS)
403 get_ssl_connection_cipher(struct socket
*socket
)
405 ssl_t
*ssl
= socket
->ssl
;
408 if (!init_string(&str
)) return NULL
;
411 add_format_to_string(&str
, "%ld-bit %s %s",
412 SSL_get_cipher_bits(ssl
, NULL
),
413 SSL_get_cipher_version(ssl
),
414 SSL_get_cipher_name(ssl
));
415 #elif defined(CONFIG_GNUTLS)
416 /* XXX: How to get other relevant parameters? */
417 add_format_to_string(&str
, "%s - %s - %s - %s - %s (compr: %s)",
418 gnutls_protocol_get_name(gnutls_protocol_get_version(*ssl
)),
419 gnutls_kx_get_name(gnutls_kx_get(*ssl
)),
420 gnutls_cipher_get_name(gnutls_cipher_get(*ssl
)),
421 gnutls_mac_get_name(gnutls_mac_get(*ssl
)),
422 gnutls_certificate_type_get_name(gnutls_certificate_type_get(*ssl
)),
423 gnutls_compression_get_name(gnutls_compression_get(*ssl
)));
429 /* When CONFIG_SSL is defined, this implementation replaces the one in
430 * src/util/random.c. */
432 random_nonce(unsigned char buf
[], size_t size
)
435 RAND_pseudo_bytes(buf
, size
);
436 #elif defined(CONFIG_GNUTLS)
437 gcry_create_nonce(buf
, size
);
439 # error unsupported SSL library