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_set_ia(void *tls_ctx
, struct tls_connection
*conn
,
429 int tls_connection_get_keys(void *tls_ctx
, struct tls_connection
*conn
,
430 struct tls_keys
*keys
)
432 /* NSS does not export master secret or client/server random. */
437 int 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
)
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
);
448 if (SSL_ExportKeyingMaterial(conn
->fd
, label
, NULL
, 0, out
, out_len
) !=
450 wpa_printf(MSG_INFO
, "NSS: Failed to use TLS extractor "
451 "(label='%s' out_len=%d", label
, (int) out_len
);
459 struct wpabuf
* tls_connection_handshake(void *tls_ctx
,
460 struct tls_connection
*conn
,
461 const struct wpabuf
*in_data
,
462 struct wpabuf
**appl_data
)
464 struct wpabuf
*out_data
;
466 wpa_printf(MSG_DEBUG
, "NSS: handshake: in_len=%u",
467 in_data
? (unsigned int) wpabuf_len(in_data
) : 0);
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
);
479 conn
->pull_buf
= os_malloc(wpabuf_len(in_data
));
480 if (conn
->pull_buf
== 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
);
488 SSL_ForceHandshake(conn
->fd
);
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);
495 if (conn
->push_buf
== 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;
506 struct wpabuf
* tls_connection_server_handshake(void *tls_ctx
,
507 struct tls_connection
*conn
,
508 const struct wpabuf
*in_data
,
509 struct wpabuf
**appl_data
)
515 struct wpabuf
* tls_connection_encrypt(void *tls_ctx
,
516 struct tls_connection
*conn
,
517 const struct wpabuf
*in_data
)
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,
527 wpa_printf(MSG_ERROR
, "NSS: Encryption failed");
530 if (conn
->push_buf
== NULL
)
532 buf
= wpabuf_alloc_ext_data(conn
->push_buf
, conn
->push_buf_len
);
534 os_free(conn
->push_buf
);
535 conn
->push_buf
= NULL
;
536 conn
->push_buf_len
= 0;
541 struct wpabuf
* tls_connection_decrypt(void *tls_ctx
,
542 struct tls_connection
*conn
,
543 const struct wpabuf
*in_data
)
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
);
556 conn
->pull_buf
= os_malloc(wpabuf_len(in_data
));
557 if (conn
->pull_buf
== 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
);
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
569 out
= wpabuf_alloc((wpabuf_len(in_data
) + 500) * 3);
573 res
= PR_Recv(conn
->fd
, wpabuf_mhead(out
), wpabuf_size(out
), 0, 0);
574 wpa_printf(MSG_DEBUG
, "NSS: PR_Recv: %d", res
);
579 wpabuf_put(out
, res
);
585 int tls_connection_resumed(void *tls_ctx
, struct tls_connection
*conn
)
591 int tls_connection_set_cipher_list(void *tls_ctx
, struct tls_connection
*conn
,
598 int tls_get_cipher(void *tls_ctx
, struct tls_connection
*conn
,
599 char *buf
, size_t buflen
)
605 int tls_connection_enable_workaround(void *tls_ctx
,
606 struct tls_connection
*conn
)
612 int tls_connection_client_hello_ext(void *tls_ctx
, struct tls_connection
*conn
,
613 int ext_type
, const u8
*data
,
620 int tls_connection_get_failed(void *tls_ctx
, struct tls_connection
*conn
)
626 int tls_connection_get_read_alerts(void *tls_ctx
, struct tls_connection
*conn
)
632 int tls_connection_get_write_alerts(void *tls_ctx
,
633 struct tls_connection
*conn
)
639 int tls_connection_get_keyblock_size(void *tls_ctx
,
640 struct tls_connection
*conn
)
646 unsigned int tls_capabilities(void *tls_ctx
)
652 struct wpabuf
* tls_connection_ia_send_phase_finished(
653 void *tls_ctx
, struct tls_connection
*conn
, int final
)
659 int tls_connection_ia_final_phase_finished(void *tls_ctx
,
660 struct tls_connection
*conn
)
666 int tls_connection_ia_permute_inner_secret(void *tls_ctx
,
667 struct tls_connection
*conn
,
668 const u8
*key
, size_t key_len
)
674 int tls_connection_set_session_ticket_cb(void *tls_ctx
,
675 struct tls_connection
*conn
,
676 tls_session_ticket_cb cb
,