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