1 /* SSL support - wrappers for SSL routines */
8 #include <openssl/ssl.h>
9 #include <openssl/rand.h>
10 #elif defined(CONFIG_GNUTLS)
11 #include <gnutls/gnutls.h>
12 #include <gnutls/x509.h>
14 #error "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And then you want exactly *what* from me?"
23 #include "intl/gettext/libintl.h"
24 #include "main/module.h"
25 #include "network/connection.h"
26 #include "network/socket.h"
27 #include "network/ssl/ssl.h"
28 #include "util/conv.h"
29 #include "util/error.h"
30 #include "util/string.h"
33 /* FIXME: As you can see, SSL is currently implemented in very, erm,
34 * decentralized manner. */
39 #define PATH_MAX 256 /* according to my /usr/include/bits/posix1_lim.h */
42 SSL_CTX
*context
= NULL
;
45 init_openssl(struct module
*module
)
47 unsigned char f_randfile
[PATH_MAX
];
49 /* In a nutshell, on OS's without a /dev/urandom, the OpenSSL library
50 * cannot initialize the PRNG and so every attempt to use SSL fails.
51 * It's actually an OpenSSL FAQ, and according to them, it's up to the
52 * application coders to seed the RNG. -- William Yodlowsky */
53 if (RAND_egd(RAND_file_name(f_randfile
, sizeof(f_randfile
))) < 0) {
54 /* Not an EGD, so read and write to it */
55 if (RAND_load_file(f_randfile
, -1))
56 RAND_write_file(f_randfile
);
59 SSLeay_add_ssl_algorithms();
60 context
= SSL_CTX_new(SSLv23_client_method());
61 SSL_CTX_set_options(context
, SSL_OP_ALL
);
62 SSL_CTX_set_default_verify_paths(context
);
66 done_openssl(struct module
*module
)
68 if (context
) SSL_CTX_free(context
);
71 static struct option_info openssl_options
[] = {
72 INIT_OPT_BOOL("connection.ssl", N_("Verify certificates"),
74 N_("Verify the peer's SSL certificate. Note that this "
75 "needs extensive configuration of OpenSSL by the user.")),
77 INIT_OPT_TREE("connection.ssl", N_("Client Certificates"),
78 "client_cert", OPT_SORT
,
79 N_("X509 client certificate options.")),
81 INIT_OPT_BOOL("connection.ssl.client_cert", N_("Enable"),
83 N_("Enable or not the sending of X509 client certificates "
84 "to servers which request them.")),
86 INIT_OPT_STRING("connection.ssl.client_cert", N_("Certificate File"),
88 N_("The location of a file containing the client certificate "
89 "and unencrypted private key in PEM format. If unset, the "
90 "file pointed to by the X509_CLIENT_CERT variable is used "
96 static struct module openssl_module
= struct_module(
97 /* name: */ "OpenSSL",
98 /* options: */ openssl_options
,
100 /* submodules: */ NULL
,
102 /* init: */ init_openssl
,
103 /* done: */ done_openssl
106 #elif defined(CONFIG_GNUTLS)
108 gnutls_anon_client_credentials_t anon_cred
= NULL
;
109 gnutls_certificate_credentials_t xcred
= NULL
;
111 const static int kx_priority
[16] = {
112 GNUTLS_KX_RSA
, GNUTLS_KX_DHE_DSS
, GNUTLS_KX_DHE_RSA
, GNUTLS_KX_SRP
,
113 /* Do not use anonymous authentication, unless you know what that means */
114 GNUTLS_KX_ANON_DH
, GNUTLS_KX_RSA_EXPORT
, 0
116 const static int cipher_priority
[16] = {
117 GNUTLS_CIPHER_RIJNDAEL_128_CBC
, GNUTLS_CIPHER_ARCFOUR_128
,
118 GNUTLS_CIPHER_3DES_CBC
, GNUTLS_CIPHER_AES_256_CBC
, GNUTLS_CIPHER_ARCFOUR_40
, 0
120 const static int cert_type_priority
[16] = { GNUTLS_CRT_X509
, GNUTLS_CRT_OPENPGP
, 0 };
123 init_gnutls(struct module
*module
)
125 int ret
= gnutls_global_init();
126 unsigned char *ca_file
= get_opt_str("connection.ssl.trusted_ca_file");
129 INTERNAL("GNUTLS init failed: %s", gnutls_strerror(ret
));
131 ret
= gnutls_anon_allocate_client_credentials(&anon_cred
);
133 INTERNAL("GNUTLS anon credentials alloc failed: %s",
134 gnutls_strerror(ret
));
136 ret
= gnutls_certificate_allocate_credentials(&xcred
);
138 INTERNAL("GNUTLS X509 credentials alloc failed: %s",
139 gnutls_strerror(ret
));
140 /* Here, we should load certificate files etc. */
142 /* FIXME: check returned values. --witekfl */
143 gnutls_certificate_set_x509_trust_file(xcred
, ca_file
,
144 GNUTLS_X509_FMT_PEM
);
146 gnutls_certificate_set_verify_flags(xcred
,
147 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT
);
153 done_gnutls(struct module
*module
)
155 if (xcred
) gnutls_certificate_free_credentials(xcred
);
156 if (anon_cred
) gnutls_anon_free_client_credentials(anon_cred
);
157 gnutls_global_deinit();
160 static struct option_info gnutls_options
[] = {
161 INIT_OPT_BOOL("connection.ssl", N_("Verify certificates"),
163 N_("Verify the peer's SSL certificate. If you enable "
164 "this, set also \"Trusted CA file\".")),
166 /* The default value of the following option points to a file
167 * generated by the ca-certificates Debian package. Don't use
168 * CONFDIR here: if someone installs ELinks in $HOME and wants
169 * to have a user-specific trust list, he or she can just
170 * change the file name via the option manager. Distributors
171 * of binary packages should of course change the default to
172 * suit their systems.
173 * TODO: If the file name is relative, look in elinks_home? */
174 INIT_OPT_STRING("connection.ssl", N_("Trusted CA file"),
175 "trusted_ca_file", 0, "/etc/ssl/certs/ca-certificates.crt",
176 N_("The location of a file containing certificates of "
177 "trusted certification authorities in PEM format. "
178 "ELinks then trusts certificates issued by these CAs.\n"
180 "If you change this option or the file, you must "
181 "restart ELinks for the changes to take effect. "
182 "This option affects GnuTLS but not OpenSSL.")),
187 static struct module gnutls_module
= struct_module(
188 /* name: */ "GnuTLS",
189 /* options: */ gnutls_options
,
191 /* submodules: */ NULL
,
193 /* init: */ init_gnutls
,
194 /* done: */ done_gnutls
197 #endif /* CONFIG_OPENSSL or CONFIG_GNUTLS */
199 static struct option_info ssl_options
[] = {
200 INIT_OPT_TREE("connection", N_("SSL"),
207 static struct module
*ssl_modules
[] = {
208 #ifdef CONFIG_OPENSSL
210 #elif defined(CONFIG_GNUTLS)
216 struct module ssl_module
= struct_module(
217 /* name: */ N_("SSL"),
218 /* options: */ ssl_options
,
220 /* submodules: */ ssl_modules
,
227 init_ssl_connection(struct socket
*socket
)
229 #ifdef CONFIG_OPENSSL
230 socket
->ssl
= SSL_new(context
);
231 if (!socket
->ssl
) return S_SSL_ERROR
;
232 #elif defined(CONFIG_GNUTLS)
233 /* const unsigned char server_name[] = "localhost"; */
234 ssl_t
*state
= mem_alloc(sizeof(ssl_t
));
236 if (!state
) return S_SSL_ERROR
;
238 if (gnutls_init(state
, GNUTLS_CLIENT
) < 0) {
239 /* DBG("sslinit %s", gnutls_strerror(ret)); */
244 if (gnutls_cred_set(*state
, GNUTLS_CRD_ANON
, anon_cred
) < 0) {
245 /* DBG("sslanoncred %s", gnutls_strerror(ret)); */
246 gnutls_deinit(*state
);
251 if (gnutls_cred_set(*state
, GNUTLS_CRD_CERTIFICATE
, xcred
) < 0) {
252 /* DBG("sslx509cred %s", gnutls_strerror(ret)); */
253 gnutls_deinit(*state
);
258 if (gnutls_priority_set_direct(*state
, "NORMAL:-CTYPE-OPENPGP", NULL
)) {
259 gnutls_deinit(*state
);
263 /* gnutls_set_default_priority(*state); */
264 /* gnutls_handshake_set_private_extensions(*state, 1); */
265 gnutls_cipher_set_priority(*state
, cipher_priority
);
266 gnutls_kx_set_priority(*state
, kx_priority
);
267 /* gnutls_certificate_type_set_priority(*state, cert_type_priority);
268 gnutls_server_name_set(*state, GNUTLS_NAME_DNS, server_name,
269 sizeof(server_name) - 1); */
278 done_ssl_connection(struct socket
*socket
)
280 ssl_t
*ssl
= socket
->ssl
;
283 #ifdef CONFIG_OPENSSL
285 #elif defined(CONFIG_GNUTLS)
293 get_ssl_connection_cipher(struct socket
*socket
)
295 ssl_t
*ssl
= socket
->ssl
;
298 if (!init_string(&str
)) return NULL
;
300 #ifdef CONFIG_OPENSSL
301 add_format_to_string(&str
, "%ld-bit %s %s",
302 SSL_get_cipher_bits(ssl
, NULL
),
303 SSL_get_cipher_version(ssl
),
304 SSL_get_cipher_name(ssl
));
305 #elif defined(CONFIG_GNUTLS)
306 /* XXX: How to get other relevant parameters? */
307 add_format_to_string(&str
, "%s - %s - %s - %s - %s (compr: %s)",
308 gnutls_protocol_get_name(gnutls_protocol_get_version(*ssl
)),
309 gnutls_kx_get_name(gnutls_kx_get(*ssl
)),
310 gnutls_cipher_get_name(gnutls_cipher_get(*ssl
)),
311 gnutls_mac_get_name(gnutls_mac_get(*ssl
)),
312 gnutls_certificate_type_get_name(gnutls_certificate_type_get(*ssl
)),
313 gnutls_compression_get_name(gnutls_compression_get(*ssl
)));