2 * SSL/TLS interface functions for NSS
3 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
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>
26 #include <nss/nssilckt.h>
28 #include <nss/pk11func.h>
29 #include <nss/secerr.h>
34 static int tls_nss_ref_count = 0;
36 static PRDescIdentity nss_layer_id;
39 struct tls_connection {
44 u8 *push_buf, *pull_buf, *pull_buf_offset;
45 size_t push_buf_len, pull_buf_len;
49 static PRStatus nss_io_close(PRFileDesc *fd)
51 wpa_printf(MSG_DEBUG, "NSS: I/O close");
56 static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
58 wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
63 static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
65 wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
70 static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
71 PRInt32 iov_size, PRIntervalTime timeout)
73 wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
78 static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
79 PRIntn flags, PRIntervalTime timeout)
81 struct tls_connection *conn = (struct tls_connection *) fd->secret;
84 wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
86 if (conn->pull_buf == NULL) {
87 wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
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;
102 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
104 (unsigned long) (end - conn->pull_buf_offset));
110 static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
111 PRIntn flags, PRIntervalTime timeout)
113 struct tls_connection *conn = (struct tls_connection *) fd->secret;
116 wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
117 wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
119 nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
121 wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
125 os_memcpy(nbuf + conn->push_buf_len, buf, amount);
126 conn->push_buf = nbuf;
127 conn->push_buf_len += amount;
133 static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
134 PRIntn flags, PRNetAddr *addr,
135 PRIntervalTime timeout)
137 wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
142 static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
143 PRIntn flags, const PRNetAddr *addr,
144 PRIntervalTime timeout)
146 wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
151 static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
153 wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
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
160 os_memset(addr, 0, sizeof(*addr));
161 addr->inet.family = PR_AF_INET;
167 static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
168 PRSocketOptionData *data)
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;
176 wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
183 static const PRIOMethods nss_io = {
188 NULL /* available */,
189 NULL /* available64 */,
194 NULL /* fileinfo64 */,
206 NULL /* acceptread */,
207 NULL /* transmitfile */,
208 NULL /* getsockname */,
210 NULL /* reserved_fn_6 */,
211 NULL /* reserved_fn_5 */,
212 nss_io_getsocketoption,
213 NULL /* setsocketoption */,
215 NULL /* connectcontinue */,
216 NULL /* reserved_fn_3 */,
217 NULL /* reserved_fn_2 */,
218 NULL /* reserved_fn_1 */,
219 NULL /* reserved_fn_0 */
223 static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
225 wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
230 void * tls_init(const struct tls_config *conf)
235 if (tls_nss_ref_count > 1)
238 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
240 nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
242 PK11_SetPasswordFunc(nss_password_cb);
244 dir = getenv("SSL_DIR");
246 if (NSS_Init(dir) != SECSuccess) {
247 wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
252 if (NSS_NoDB_Init(NULL) != SECSuccess) {
253 wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
259 if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
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");
268 if (NSS_SetDomesticPolicy() != SECSuccess) {
269 wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
276 void tls_deinit(void *ssl_ctx)
279 if (tls_nss_ref_count == 0) {
280 if (NSS_Shutdown() != SECSuccess)
281 wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
286 int tls_get_errors(void *tls_ctx)
292 static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
294 struct tls_connection *conn = arg;
295 SECStatus res = SECSuccess;
297 CERTCertificate *cert;
298 char *subject, *issuer;
301 if (IS_SEC_ERROR(err))
302 wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
303 "%d)", err - SEC_ERROR_BASE);
305 wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
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'",
312 CERT_DestroyCertificate(cert);
315 if (conn->verify_peer)
322 static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
324 struct tls_connection *conn = client_data;
325 wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
326 conn->established = 1;
330 struct tls_connection * tls_connection_init(void *tls_ctx)
332 struct tls_connection *conn;
334 conn = os_zalloc(sizeof(*conn));
338 conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
339 if (conn->fd == NULL) {
343 conn->fd->secret = (void *) conn;
345 conn->fd = SSL_ImportFD(NULL, conn->fd);
346 if (conn->fd == NULL) {
351 if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
352 SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
354 SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
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) !=
360 wpa_printf(MSG_ERROR, "NSS: Failed to set options");
366 SSL_ResetHandshake(conn->fd, PR_FALSE);
372 void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
375 os_free(conn->push_buf);
376 os_free(conn->pull_buf);
381 int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
383 return conn->established;
387 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
393 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
394 const struct tls_connection_params *params)
396 wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
401 int tls_global_set_params(void *tls_ctx,
402 const struct tls_connection_params *params)
408 int tls_global_set_verify(void *tls_ctx, int check_crl)
414 int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
417 conn->verify_peer = verify_peer;
422 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
423 struct tls_keys *keys)
425 /* NSS does not export master secret or client/server random. */
430 int 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)
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);
441 if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
443 wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
444 "(label='%s' out_len=%d", label, (int) out_len);
452 struct wpabuf * tls_connection_handshake(void *tls_ctx,
453 struct tls_connection *conn,
454 const struct wpabuf *in_data,
455 struct wpabuf **appl_data)
457 struct wpabuf *out_data;
459 wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
460 in_data ? (unsigned int) wpabuf_len(in_data) : 0);
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);
472 conn->pull_buf = os_malloc(wpabuf_len(in_data));
473 if (conn->pull_buf == 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);
481 SSL_ForceHandshake(conn->fd);
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);
488 if (conn->push_buf == 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;
499 struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
500 struct tls_connection *conn,
501 const struct wpabuf *in_data,
502 struct wpabuf **appl_data)
508 struct wpabuf * tls_connection_encrypt(void *tls_ctx,
509 struct tls_connection *conn,
510 const struct wpabuf *in_data)
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,
520 wpa_printf(MSG_ERROR, "NSS: Encryption failed");
523 if (conn->push_buf == NULL)
525 buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
527 os_free(conn->push_buf);
528 conn->push_buf = NULL;
529 conn->push_buf_len = 0;
534 struct wpabuf * tls_connection_decrypt(void *tls_ctx,
535 struct tls_connection *conn,
536 const struct wpabuf *in_data)
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);
549 conn->pull_buf = os_malloc(wpabuf_len(in_data));
550 if (conn->pull_buf == 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);
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
562 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
566 res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
567 wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
572 wpabuf_put(out, res);
578 int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
584 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
591 int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
592 char *buf, size_t buflen)
598 int tls_connection_enable_workaround(void *tls_ctx,
599 struct tls_connection *conn)
605 int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
606 int ext_type, const u8 *data,
613 int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
619 int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
625 int tls_connection_get_write_alerts(void *tls_ctx,
626 struct tls_connection *conn)
632 int tls_connection_get_keyblock_size(void *tls_ctx,
633 struct tls_connection *conn)
639 unsigned int tls_capabilities(void *tls_ctx)
645 int tls_connection_set_session_ticket_cb(void *tls_ctx,
646 struct tls_connection *conn,
647 tls_session_ticket_cb cb,