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