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