blob: ad834b6493372a565c5060f2a384f472a74bcd3a [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
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_set_ia(void *tls_ctx, struct tls_connection *conn,
423 int tls_ia)
424{
425 return -1;
426}
427
428
429int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
430 struct tls_keys *keys)
431{
432 /* NSS does not export master secret or client/server random. */
433 return -1;
434}
435
436
437int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
438 const char *label, int server_random_first,
439 u8 *out, size_t out_len)
440{
441 if (conn == NULL || server_random_first) {
442 wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
443 "(server_random_first=%d)",
444 server_random_first);
445 return -1;
446 }
447
448 if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
449 SECSuccess) {
450 wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
451 "(label='%s' out_len=%d", label, (int) out_len);
452 return -1;
453 }
454
455 return 0;
456}
457
458
459struct wpabuf * tls_connection_handshake(void *tls_ctx,
460 struct tls_connection *conn,
461 const struct wpabuf *in_data,
462 struct wpabuf **appl_data)
463{
464 struct wpabuf *out_data;
465
466 wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
467 in_data ? (unsigned int) wpabuf_len(in_data) : 0);
468
469 if (appl_data)
470 *appl_data = NULL;
471
472 if (in_data && wpabuf_len(in_data) > 0) {
473 if (conn->pull_buf) {
474 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
475 "pull_buf", __func__,
476 (unsigned long) conn->pull_buf_len);
477 os_free(conn->pull_buf);
478 }
479 conn->pull_buf = os_malloc(wpabuf_len(in_data));
480 if (conn->pull_buf == NULL)
481 return NULL;
482 os_memcpy(conn->pull_buf, wpabuf_head(in_data),
483 wpabuf_len(in_data));
484 conn->pull_buf_offset = conn->pull_buf;
485 conn->pull_buf_len = wpabuf_len(in_data);
486 }
487
488 SSL_ForceHandshake(conn->fd);
489
490 if (conn->established && conn->push_buf == NULL) {
491 /* Need to return something to get final TLS ACK. */
492 conn->push_buf = os_malloc(1);
493 }
494
495 if (conn->push_buf == NULL)
496 return NULL;
497 out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
498 if (out_data == NULL)
499 os_free(conn->push_buf);
500 conn->push_buf = NULL;
501 conn->push_buf_len = 0;
502 return out_data;
503}
504
505
506struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
507 struct tls_connection *conn,
508 const struct wpabuf *in_data,
509 struct wpabuf **appl_data)
510{
511 return NULL;
512}
513
514
515struct wpabuf * tls_connection_encrypt(void *tls_ctx,
516 struct tls_connection *conn,
517 const struct wpabuf *in_data)
518{
519 PRInt32 res;
520 struct wpabuf *buf;
521
522 wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
523 (int) wpabuf_len(in_data));
524 res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
525 0);
526 if (res < 0) {
527 wpa_printf(MSG_ERROR, "NSS: Encryption failed");
528 return NULL;
529 }
530 if (conn->push_buf == NULL)
531 return NULL;
532 buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
533 if (buf == NULL)
534 os_free(conn->push_buf);
535 conn->push_buf = NULL;
536 conn->push_buf_len = 0;
537 return buf;
538}
539
540
541struct wpabuf * tls_connection_decrypt(void *tls_ctx,
542 struct tls_connection *conn,
543 const struct wpabuf *in_data)
544{
545 PRInt32 res;
546 struct wpabuf *out;
547
548 wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
549 (int) wpabuf_len(in_data));
550 if (conn->pull_buf) {
551 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
552 "pull_buf", __func__,
553 (unsigned long) conn->pull_buf_len);
554 os_free(conn->pull_buf);
555 }
556 conn->pull_buf = os_malloc(wpabuf_len(in_data));
557 if (conn->pull_buf == NULL)
558 return NULL;
559 os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
560 conn->pull_buf_offset = conn->pull_buf;
561 conn->pull_buf_len = wpabuf_len(in_data);
562
563 /*
564 * Even though we try to disable TLS compression, it is possible that
565 * this cannot be done with all TLS libraries. Add extra buffer space
566 * to handle the possibility of the decrypted data being longer than
567 * input data.
568 */
569 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
570 if (out == NULL)
571 return NULL;
572
573 res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
574 wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
575 if (res < 0) {
576 wpabuf_free(out);
577 return NULL;
578 }
579 wpabuf_put(out, res);
580
581 return out;
582}
583
584
585int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
586{
587 return 0;
588}
589
590
591int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
592 u8 *ciphers)
593{
594 return -1;
595}
596
597
598int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
599 char *buf, size_t buflen)
600{
601 return -1;
602}
603
604
605int tls_connection_enable_workaround(void *tls_ctx,
606 struct tls_connection *conn)
607{
608 return -1;
609}
610
611
612int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
613 int ext_type, const u8 *data,
614 size_t data_len)
615{
616 return -1;
617}
618
619
620int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
621{
622 return 0;
623}
624
625
626int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
627{
628 return 0;
629}
630
631
632int tls_connection_get_write_alerts(void *tls_ctx,
633 struct tls_connection *conn)
634{
635 return 0;
636}
637
638
639int tls_connection_get_keyblock_size(void *tls_ctx,
640 struct tls_connection *conn)
641{
642 return -1;
643}
644
645
646unsigned int tls_capabilities(void *tls_ctx)
647{
648 return 0;
649}
650
651
652struct wpabuf * tls_connection_ia_send_phase_finished(
653 void *tls_ctx, struct tls_connection *conn, int final)
654{
655 return NULL;
656}
657
658
659int tls_connection_ia_final_phase_finished(void *tls_ctx,
660 struct tls_connection *conn)
661{
662 return -1;
663}
664
665
666int tls_connection_ia_permute_inner_secret(void *tls_ctx,
667 struct tls_connection *conn,
668 const u8 *key, size_t key_len)
669{
670 return -1;
671}
672
673
674int tls_connection_set_session_ticket_cb(void *tls_ctx,
675 struct tls_connection *conn,
676 tls_session_ticket_cb cb,
677 void *ctx)
678{
679 return -1;
680}