1 /* SSL support - wrappers for SSL routines */
2 
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 
7 #ifdef CONFIG_OPENSSL
8 #include <openssl/ssl.h>
9 #include <openssl/rand.h>
10 #elif defined(CONFIG_GNUTLS)
11 #include <gnutls/gnutls.h>
12 #else
13 #error "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And then you want exactly *what* from me?"
14 #endif
15 
16 #ifdef HAVE_LIMITS_H
17 #include <limits.h>
18 #endif
19 
20 #include "elinks.h"
21 
22 #include "intl/gettext/libintl.h"
23 #include "main/module.h"
24 #include "network/connection.h"
25 #include "network/socket.h"
26 #include "network/ssl/ssl.h"
27 #include "util/conv.h"
28 #include "util/error.h"
29 #include "util/string.h"
30 
31 
32 /* FIXME: As you can see, SSL is currently implemented in very, erm,
33  * decentralized manner. */
34 
35 #ifdef CONFIG_OPENSSL
36 
37 #ifndef PATH_MAX
38 #define	PATH_MAX	256 /* according to my /usr/include/bits/posix1_lim.h */
39 #endif
40 
41 SSL_CTX *context = NULL;
42 
43 static void
init_openssl(struct module * module)44 init_openssl(struct module *module)
45 {
46 	unsigned char f_randfile[PATH_MAX];
47 
48 	/* In a nutshell, on OS's without a /dev/urandom, the OpenSSL library
49 	 * cannot initialize the PRNG and so every attempt to use SSL fails.
50 	 * It's actually an OpenSSL FAQ, and according to them, it's up to the
51 	 * application coders to seed the RNG. -- William Yodlowsky */
52 	RAND_file_name(f_randfile, sizeof(f_randfile));
53 #ifndef OPENSSL_NO_EGD
54 	if (RAND_egd(f_randfile) < 0)
55 	{
56 		/* Not an EGD, so read and write to it */
57 #endif
58 		if (RAND_load_file(f_randfile, -1))
59 			RAND_write_file(f_randfile);
60 #ifndef OPENSSL_NO_EGD
61 	}
62 #endif
63 
64 	SSLeay_add_ssl_algorithms();
65 	context = SSL_CTX_new(SSLv23_client_method());
66 	SSL_CTX_set_options(context, SSL_OP_ALL);
67 	SSL_CTX_set_default_verify_paths(context);
68 }
69 
70 static void
done_openssl(struct module * module)71 done_openssl(struct module *module)
72 {
73 	if (context) SSL_CTX_free(context);
74 }
75 
76 static struct option_info openssl_options[] = {
77 	INIT_OPT_BOOL("connection.ssl", N_("Verify certificates"),
78 		"cert_verify", 0, 0,
79 		N_("Verify the peer's SSL certificate. Note that this\n"
80 		"needs extensive configuration of OpenSSL by the user.")),
81 
82 	INIT_OPT_TREE("connection.ssl", N_("Client Certificates"),
83         	"client_cert", OPT_SORT,
84         	N_("X509 client certificate options.")),
85 
86 	INIT_OPT_BOOL("connection.ssl.client_cert", N_("Enable"),
87 		"enable", 0, 0,
88 		 N_("Enable or not the sending of X509 client certificates\n"
89 		    "to servers which request them.")),
90 
91 	INIT_OPT_STRING("connection.ssl.client_cert", N_("Certificate File"),
92 		"file", 0, "",
93 		 N_("The location of a file containing the client certificate\n"
94 		    "and unencrypted private key in PEM format. If unset, the\n"
95 		    "file pointed to by the X509_CLIENT_CERT variable is used\n"
96 		    "instead.")),
97 
98 	NULL_OPTION_INFO,
99 };
100 
101 static struct module openssl_module = struct_module(
102 	/* name: */		"OpenSSL",
103 	/* options: */		openssl_options,
104 	/* events: */		NULL,
105 	/* submodules: */	NULL,
106 	/* data: */		NULL,
107 	/* init: */		init_openssl,
108 	/* done: */		done_openssl
109 );
110 
111 #elif defined(CONFIG_GNUTLS)
112 
113 gnutls_anon_client_credentials_t anon_cred = NULL;
114 gnutls_certificate_credentials_t xcred = NULL;
115 
116 const static int kx_priority[16] = {
117 	GNUTLS_KX_RSA, GNUTLS_KX_DHE_DSS, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP,
118 	/* Do not use anonymous authentication, unless you know what that means */
119 	GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA_EXPORT, 0
120 };
121 const static int cipher_priority[16] = {
122 	GNUTLS_CIPHER_RIJNDAEL_128_CBC, GNUTLS_CIPHER_ARCFOUR_128,
123 	GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_ARCFOUR_40, 0
124 };
125 const static int cert_type_priority[16] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
126 
127 static void
init_gnutls(struct module * module)128 init_gnutls(struct module *module)
129 {
130 	int ret = gnutls_global_init();
131 
132 	if (ret < 0)
133 		INTERNAL("GNUTLS init failed: %s", gnutls_strerror(ret));
134 
135 	ret = gnutls_anon_allocate_client_credentials(&anon_cred);
136 	if (ret < 0)
137 		INTERNAL("GNUTLS anon credentials alloc failed: %s",
138 			 gnutls_strerror(ret));
139 
140 	ret = gnutls_certificate_allocate_credentials(&xcred);
141 	if (ret < 0)
142 		INTERNAL("GNUTLS X509 credentials alloc failed: %s",
143 			 gnutls_strerror(ret));
144 
145 	/* Here, we should load certificate files etc. */
146 }
147 
148 static void
done_gnutls(struct module * module)149 done_gnutls(struct module *module)
150 {
151 	if (xcred) gnutls_certificate_free_credentials(xcred);
152 	if (anon_cred) gnutls_anon_free_client_credentials(anon_cred);
153 	gnutls_global_deinit();
154 }
155 
156 static struct option_info gnutls_options[] = {
157 	INIT_OPT_BOOL("connection.ssl", N_("Verify certificates"),
158 		"cert_verify", 0, 0,
159 		N_("Verify the peer's SSL certificate. Note that this\n"
160 		"probably doesn't work properly at all with GnuTLS.")),
161 
162 	NULL_OPTION_INFO,
163 };
164 
165 static struct module gnutls_module = struct_module(
166 	/* name: */		"GnuTLS",
167 	/* options: */		gnutls_options,
168 	/* events: */		NULL,
169 	/* submodules: */	NULL,
170 	/* data: */		NULL,
171 	/* init: */		init_gnutls,
172 	/* done: */		done_gnutls
173 );
174 
175 #endif /* CONFIG_OPENSSL or CONFIG_GNUTLS */
176 
177 static struct option_info ssl_options[] = {
178 	INIT_OPT_TREE("connection", N_("SSL"),
179 		"ssl", OPT_SORT,
180 		N_("SSL options.")),
181 
182 	NULL_OPTION_INFO,
183 };
184 
185 static struct module *ssl_modules[] = {
186 #ifdef CONFIG_OPENSSL
187 	&openssl_module,
188 #elif defined(CONFIG_GNUTLS)
189 	&gnutls_module,
190 #endif
191 	NULL,
192 };
193 
194 struct module ssl_module = struct_module(
195 	/* name: */		N_("SSL"),
196 	/* options: */		ssl_options,
197 	/* events: */		NULL,
198 	/* submodules: */	ssl_modules,
199 	/* data: */		NULL,
200 	/* init: */		NULL,
201 	/* done: */		NULL
202 );
203 
204 int
init_ssl_connection(struct socket * socket)205 init_ssl_connection(struct socket *socket)
206 {
207 #ifdef CONFIG_OPENSSL
208 	socket->ssl = SSL_new(context);
209 	if (!socket->ssl) return S_SSL_ERROR;
210 #elif defined(CONFIG_GNUTLS)
211 	const unsigned char server_name[] = "localhost";
212 	ssl_t *state = mem_alloc(sizeof(ssl_t));
213 
214 	if (!state) return S_SSL_ERROR;
215 
216 	if (gnutls_init(state, GNUTLS_CLIENT) < 0) {
217 		/* DBG("sslinit %s", gnutls_strerror(ret)); */
218 		mem_free(state);
219 		return S_SSL_ERROR;
220 	}
221 
222 	if (gnutls_cred_set(*state, GNUTLS_CRD_ANON, anon_cred) < 0) {
223 		/* DBG("sslanoncred %s", gnutls_strerror(ret)); */
224 		gnutls_deinit(*state);
225 		mem_free(state);
226 		return S_SSL_ERROR;
227 	}
228 
229 	if (gnutls_cred_set(*state, GNUTLS_CRD_CERTIFICATE, xcred) < 0) {
230 		/* DBG("sslx509cred %s", gnutls_strerror(ret)); */
231 		gnutls_deinit(*state);
232 		mem_free(state);
233 		return S_SSL_ERROR;
234 	}
235 
236 	gnutls_set_default_priority(*state);
237 	gnutls_handshake_set_private_extensions(*state, 1);
238 	gnutls_cipher_set_priority(*state, cipher_priority);
239 	gnutls_kx_set_priority(*state, kx_priority);
240 	gnutls_certificate_type_set_priority(*state, cert_type_priority);
241 	gnutls_server_name_set(*state, GNUTLS_NAME_DNS, server_name,
242 			       sizeof(server_name) - 1);
243 
244 	socket->ssl = state;
245 #endif
246 
247 	return S_OK;
248 }
249 
250 void
done_ssl_connection(struct socket * socket)251 done_ssl_connection(struct socket *socket)
252 {
253 	ssl_t *ssl = socket->ssl;
254 
255 	if (!ssl) return;
256 #ifdef CONFIG_OPENSSL
257 	SSL_free(ssl);
258 #elif defined(CONFIG_GNUTLS)
259 	gnutls_deinit(*ssl);
260 	mem_free(ssl);
261 #endif
262 	socket->ssl = NULL;
263 }
264 
265 unsigned char *
get_ssl_connection_cipher(struct socket * socket)266 get_ssl_connection_cipher(struct socket *socket)
267 {
268 	ssl_t *ssl = socket->ssl;
269 	struct string str;
270 
271 	if (!init_string(&str)) return NULL;
272 
273 #ifdef CONFIG_OPENSSL
274 	add_format_to_string(&str, "%ld-bit %s %s",
275 		SSL_get_cipher_bits(ssl, NULL),
276 		SSL_get_cipher_version(ssl),
277 		SSL_get_cipher_name(ssl));
278 #elif defined(CONFIG_GNUTLS)
279 	/* XXX: How to get other relevant parameters? */
280 	add_format_to_string(&str, "%s - %s - %s - %s - %s (compr: %s)",
281 		gnutls_protocol_get_name(gnutls_protocol_get_version(*ssl)),
282 		gnutls_kx_get_name(gnutls_kx_get(*ssl)),
283 		gnutls_cipher_get_name(gnutls_cipher_get(*ssl)),
284 		gnutls_mac_get_name(gnutls_mac_get(*ssl)),
285 		gnutls_certificate_type_get_name(gnutls_certificate_type_get(*ssl)),
286 		gnutls_compression_get_name(gnutls_compression_get(*ssl)));
287 #endif
288 
289 	return str.source;
290 }
291