tls_nss.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
1/*
2 * SSL/TLS interface functions for NSS
3 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16#include <nspr/prtypes.h>
17#include <nspr/plarenas.h>
18#include <nspr/plhash.h>
19#include <nspr/prio.h>
20#include <nspr/prclist.h>
21#include <nspr/prlock.h>
22#include <nspr/prinit.h>
23#include <nspr/prerror.h>
24#include <nspr/prmem.h>
25#include <nss/nss.h>
26#include <nss/nssilckt.h>
27#include <nss/ssl.h>
28#include <nss/pk11func.h>
29#include <nss/secerr.h>
30
31#include "common.h"
32#include "tls.h"
33
34static int tls_nss_ref_count = 0;
35
36static PRDescIdentity nss_layer_id;
37
38
39struct tls_connection {
40	PRFileDesc *fd;
41
42	int established;
43	int verify_peer;
44	u8 *push_buf, *pull_buf, *pull_buf_offset;
45	size_t push_buf_len, pull_buf_len;
46};
47
48
49static PRStatus nss_io_close(PRFileDesc *fd)
50{
51	wpa_printf(MSG_DEBUG, "NSS: I/O close");
52	return PR_SUCCESS;
53}
54
55
56static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
57{
58	wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
59	return PR_FAILURE;
60}
61
62
63static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
64{
65	wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
66	return PR_FAILURE;
67}
68
69
70static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
71			     PRInt32 iov_size, PRIntervalTime timeout)
72{
73	wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
74	return PR_FAILURE;
75}
76
77
78static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
79			   PRIntn flags, PRIntervalTime timeout)
80{
81	struct tls_connection *conn = (struct tls_connection *) fd->secret;
82	u8 *end;
83
84	wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
85
86	if (conn->pull_buf == NULL) {
87		wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
88		return PR_FAILURE;
89	}
90
91	end = conn->pull_buf + conn->pull_buf_len;
92	if (end - conn->pull_buf_offset < amount)
93		amount = end - conn->pull_buf_offset;
94	os_memcpy(buf, conn->pull_buf_offset, amount);
95	conn->pull_buf_offset += amount;
96	if (conn->pull_buf_offset == end) {
97		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
98		os_free(conn->pull_buf);
99		conn->pull_buf = conn->pull_buf_offset = NULL;
100		conn->pull_buf_len = 0;
101	} else {
102		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
103			   __func__,
104			   (unsigned long) (end - conn->pull_buf_offset));
105	}
106	return amount;
107}
108
109
110static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
111			   PRIntn flags, PRIntervalTime timeout)
112{
113	struct tls_connection *conn = (struct tls_connection *) fd->secret;
114	u8 *nbuf;
115
116	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
117	wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
118
119	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
120	if (nbuf == NULL) {
121		wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
122			   "data to be sent");
123		return PR_FAILURE;
124	}
125	os_memcpy(nbuf + conn->push_buf_len, buf, amount);
126	conn->push_buf = nbuf;
127	conn->push_buf_len += amount;
128
129	return amount;
130}
131
132
133static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
134			       PRIntn flags, PRNetAddr *addr,
135			       PRIntervalTime timeout)
136{
137	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
138	return PR_FAILURE;
139}
140
141
142static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
143			     PRIntn flags, const PRNetAddr *addr,
144			     PRIntervalTime timeout)
145{
146	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
147	return PR_FAILURE;
148}
149
150
151static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
152{
153	wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
154
155	/*
156	 * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
157	 * fake IPv4 address to work around this even though we are not really
158	 * using TCP.
159	 */
160	os_memset(addr, 0, sizeof(*addr));
161	addr->inet.family = PR_AF_INET;
162
163	return PR_SUCCESS;
164}
165
166
167static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
168				       PRSocketOptionData *data)
169{
170	switch (data->option) {
171	case PR_SockOpt_Nonblocking:
172		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
173		data->value.non_blocking = PR_TRUE;
174		return PR_SUCCESS;
175	default:
176		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
177			   data->option);
178		return PR_FAILURE;
179	}
180}
181
182
183static const PRIOMethods nss_io = {
184	PR_DESC_LAYERED,
185	nss_io_close,
186	nss_io_read,
187	nss_io_write,
188	NULL /* available */,
189	NULL /* available64 */,
190	NULL /* fsync */,
191	NULL /* fseek */,
192	NULL /* fseek64 */,
193	NULL /* fileinfo */,
194	NULL /* fileinfo64 */,
195	nss_io_writev,
196	NULL /* connect */,
197	NULL /* accept */,
198	NULL /* bind */,
199	NULL /* listen */,
200	NULL /* shutdown */,
201	nss_io_recv,
202	nss_io_send,
203	nss_io_recvfrom,
204	nss_io_sendto,
205	NULL /* poll */,
206	NULL /* acceptread */,
207	NULL /* transmitfile */,
208	NULL /* getsockname */,
209	nss_io_getpeername,
210	NULL /* reserved_fn_6 */,
211	NULL /* reserved_fn_5 */,
212	nss_io_getsocketoption,
213	NULL /* setsocketoption */,
214	NULL /* sendfile */,
215	NULL /* connectcontinue */,
216	NULL /* reserved_fn_3 */,
217	NULL /* reserved_fn_2 */,
218	NULL /* reserved_fn_1 */,
219	NULL /* reserved_fn_0 */
220};
221
222
223static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
224{
225	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
226	return NULL;
227}
228
229
230void * tls_init(const struct tls_config *conf)
231{
232	char *dir;
233
234	tls_nss_ref_count++;
235	if (tls_nss_ref_count > 1)
236		return (void *) 1;
237
238	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
239
240	nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
241
242	PK11_SetPasswordFunc(nss_password_cb);
243
244	dir = getenv("SSL_DIR");
245	if (dir) {
246		if (NSS_Init(dir) != SECSuccess) {
247			wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
248				   "failed", dir);
249			return NULL;
250		}
251	} else {
252		if (NSS_NoDB_Init(NULL) != SECSuccess) {
253			wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
254				   "failed");
255			return NULL;
256		}
257	}
258
259	if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
260	    SECSuccess ||
261	    SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
262	    SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
263	    SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
264		wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
265		return NULL;
266	}
267
268	if (NSS_SetDomesticPolicy() != SECSuccess) {
269		wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
270		return NULL;
271	}
272
273	return (void *) 1;
274}
275
276void tls_deinit(void *ssl_ctx)
277{
278	tls_nss_ref_count--;
279	if (tls_nss_ref_count == 0) {
280		if (NSS_Shutdown() != SECSuccess)
281			wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
282	}
283}
284
285
286int tls_get_errors(void *tls_ctx)
287{
288	return 0;
289}
290
291
292static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
293{
294	struct tls_connection *conn = arg;
295	SECStatus res = SECSuccess;
296	PRErrorCode err;
297	CERTCertificate *cert;
298	char *subject, *issuer;
299
300	err = PR_GetError();
301	if (IS_SEC_ERROR(err))
302		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
303			   "%d)", err - SEC_ERROR_BASE);
304	else
305		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
306			   err);
307	cert = SSL_PeerCertificate(fd);
308	subject = CERT_NameToAscii(&cert->subject);
309	issuer = CERT_NameToAscii(&cert->issuer);
310	wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
311		   subject, issuer);
312	CERT_DestroyCertificate(cert);
313	PR_Free(subject);
314	PR_Free(issuer);
315	if (conn->verify_peer)
316		res = SECFailure;
317
318	return res;
319}
320
321
322static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
323{
324	struct tls_connection *conn = client_data;
325	wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
326	conn->established = 1;
327}
328
329
330struct tls_connection * tls_connection_init(void *tls_ctx)
331{
332	struct tls_connection *conn;
333
334	conn = os_zalloc(sizeof(*conn));
335	if (conn == NULL)
336		return NULL;
337
338	conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
339	if (conn->fd == NULL) {
340		os_free(conn);
341		return NULL;
342	}
343	conn->fd->secret = (void *) conn;
344
345	conn->fd = SSL_ImportFD(NULL, conn->fd);
346	if (conn->fd == NULL) {
347		os_free(conn);
348		return NULL;
349	}
350
351	if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
352	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
353	    SECSuccess ||
354	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
355	    SECSuccess ||
356	    SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
357	    SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
358	    SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
359	    SECSuccess) {
360		wpa_printf(MSG_ERROR, "NSS: Failed to set options");
361		PR_Close(conn->fd);
362		os_free(conn);
363		return NULL;
364	}
365
366	SSL_ResetHandshake(conn->fd, PR_FALSE);
367
368	return conn;
369}
370
371
372void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
373{
374	PR_Close(conn->fd);
375	os_free(conn->push_buf);
376	os_free(conn->pull_buf);
377	os_free(conn);
378}
379
380
381int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
382{
383	return conn->established;
384}
385
386
387int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
388{
389	return -1;
390}
391
392
393int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
394			      const struct tls_connection_params *params)
395{
396	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
397	return 0;
398}
399
400
401int tls_global_set_params(void *tls_ctx,
402			  const struct tls_connection_params *params)
403{
404	return -1;
405}
406
407
408int tls_global_set_verify(void *tls_ctx, int check_crl)
409{
410	return -1;
411}
412
413
414int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
415			      int verify_peer)
416{
417	conn->verify_peer = verify_peer;
418	return 0;
419}
420
421
422int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
423			    struct tls_keys *keys)
424{
425	/* NSS does not export master secret or client/server random. */
426	return -1;
427}
428
429
430int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
431		       const char *label, int server_random_first,
432		       u8 *out, size_t out_len)
433{
434	if (conn == NULL || server_random_first) {
435		wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
436			   "(server_random_first=%d)",
437			   server_random_first);
438		return -1;
439	}
440
441	if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
442	    SECSuccess) {
443		wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
444			   "(label='%s' out_len=%d", label, (int) out_len);
445		return -1;
446	}
447
448	return 0;
449}
450
451
452struct wpabuf * tls_connection_handshake(void *tls_ctx,
453					 struct tls_connection *conn,
454					 const struct wpabuf *in_data,
455					 struct wpabuf **appl_data)
456{
457	struct wpabuf *out_data;
458
459	wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
460		   in_data ? (unsigned int) wpabuf_len(in_data) : 0);
461
462	if (appl_data)
463		*appl_data = NULL;
464
465	if (in_data && wpabuf_len(in_data) > 0) {
466		if (conn->pull_buf) {
467			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
468				   "pull_buf", __func__,
469				   (unsigned long) conn->pull_buf_len);
470			os_free(conn->pull_buf);
471		}
472		conn->pull_buf = os_malloc(wpabuf_len(in_data));
473		if (conn->pull_buf == NULL)
474			return NULL;
475		os_memcpy(conn->pull_buf, wpabuf_head(in_data),
476			  wpabuf_len(in_data));
477		conn->pull_buf_offset = conn->pull_buf;
478		conn->pull_buf_len = wpabuf_len(in_data);
479	}
480
481	SSL_ForceHandshake(conn->fd);
482
483	if (conn->established && conn->push_buf == NULL) {
484		/* Need to return something to get final TLS ACK. */
485		conn->push_buf = os_malloc(1);
486	}
487
488	if (conn->push_buf == NULL)
489		return NULL;
490	out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
491	if (out_data == NULL)
492		os_free(conn->push_buf);
493	conn->push_buf = NULL;
494	conn->push_buf_len = 0;
495	return out_data;
496}
497
498
499struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
500						struct tls_connection *conn,
501						const struct wpabuf *in_data,
502						struct wpabuf **appl_data)
503{
504	return NULL;
505}
506
507
508struct wpabuf * tls_connection_encrypt(void *tls_ctx,
509				       struct tls_connection *conn,
510				       const struct wpabuf *in_data)
511{
512	PRInt32 res;
513	struct wpabuf *buf;
514
515	wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
516		   (int) wpabuf_len(in_data));
517	res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
518		      0);
519	if (res < 0) {
520		wpa_printf(MSG_ERROR, "NSS: Encryption failed");
521		return NULL;
522	}
523	if (conn->push_buf == NULL)
524		return NULL;
525	buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
526	if (buf == NULL)
527		os_free(conn->push_buf);
528	conn->push_buf = NULL;
529	conn->push_buf_len = 0;
530	return buf;
531}
532
533
534struct wpabuf * tls_connection_decrypt(void *tls_ctx,
535				       struct tls_connection *conn,
536				       const struct wpabuf *in_data)
537{
538	PRInt32 res;
539	struct wpabuf *out;
540
541	wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
542		   (int) wpabuf_len(in_data));
543	if (conn->pull_buf) {
544		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
545			   "pull_buf", __func__,
546			   (unsigned long) conn->pull_buf_len);
547		os_free(conn->pull_buf);
548	}
549	conn->pull_buf = os_malloc(wpabuf_len(in_data));
550	if (conn->pull_buf == NULL)
551		return NULL;
552	os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
553	conn->pull_buf_offset = conn->pull_buf;
554	conn->pull_buf_len = wpabuf_len(in_data);
555
556	/*
557	 * Even though we try to disable TLS compression, it is possible that
558	 * this cannot be done with all TLS libraries. Add extra buffer space
559	 * to handle the possibility of the decrypted data being longer than
560	 * input data.
561	 */
562	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
563	if (out == NULL)
564		return NULL;
565
566	res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
567	wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
568	if (res < 0) {
569		wpabuf_free(out);
570		return NULL;
571	}
572	wpabuf_put(out, res);
573
574	return out;
575}
576
577
578int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
579{
580	return 0;
581}
582
583
584int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
585				   u8 *ciphers)
586{
587	return -1;
588}
589
590
591int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
592		   char *buf, size_t buflen)
593{
594	return -1;
595}
596
597
598int tls_connection_enable_workaround(void *tls_ctx,
599				     struct tls_connection *conn)
600{
601	return -1;
602}
603
604
605int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
606				    int ext_type, const u8 *data,
607				    size_t data_len)
608{
609	return -1;
610}
611
612
613int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
614{
615	return 0;
616}
617
618
619int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
620{
621	return 0;
622}
623
624
625int tls_connection_get_write_alerts(void *tls_ctx,
626				    struct tls_connection *conn)
627{
628	return 0;
629}
630
631
632int tls_connection_get_keyblock_size(void *tls_ctx,
633				     struct tls_connection *conn)
634{
635	return -1;
636}
637
638
639unsigned int tls_capabilities(void *tls_ctx)
640{
641	return 0;
642}
643
644
645int tls_connection_set_session_ticket_cb(void *tls_ctx,
646					 struct tls_connection *conn,
647					 tls_session_ticket_cb cb,
648					 void *ctx)
649{
650	return -1;
651}
652