1214501Srpaulo/* 2214501Srpaulo * SSL/TLS interface functions for NSS 3214501Srpaulo * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo */ 14214501Srpaulo 15214501Srpaulo#include "includes.h" 16214501Srpaulo#include <nspr/prtypes.h> 17214501Srpaulo#include <nspr/plarenas.h> 18214501Srpaulo#include <nspr/plhash.h> 19214501Srpaulo#include <nspr/prio.h> 20214501Srpaulo#include <nspr/prclist.h> 21214501Srpaulo#include <nspr/prlock.h> 22214501Srpaulo#include <nspr/prinit.h> 23214501Srpaulo#include <nspr/prerror.h> 24214501Srpaulo#include <nspr/prmem.h> 25214501Srpaulo#include <nss/nss.h> 26214501Srpaulo#include <nss/nssilckt.h> 27214501Srpaulo#include <nss/ssl.h> 28214501Srpaulo#include <nss/pk11func.h> 29214501Srpaulo#include <nss/secerr.h> 30214501Srpaulo 31214501Srpaulo#include "common.h" 32214501Srpaulo#include "tls.h" 33214501Srpaulo 34214501Srpaulostatic int tls_nss_ref_count = 0; 35214501Srpaulo 36214501Srpaulostatic PRDescIdentity nss_layer_id; 37214501Srpaulo 38214501Srpaulo 39214501Srpaulostruct tls_connection { 40214501Srpaulo PRFileDesc *fd; 41214501Srpaulo 42214501Srpaulo int established; 43214501Srpaulo int verify_peer; 44214501Srpaulo u8 *push_buf, *pull_buf, *pull_buf_offset; 45214501Srpaulo size_t push_buf_len, pull_buf_len; 46214501Srpaulo}; 47214501Srpaulo 48214501Srpaulo 49214501Srpaulostatic PRStatus nss_io_close(PRFileDesc *fd) 50214501Srpaulo{ 51214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O close"); 52214501Srpaulo return PR_SUCCESS; 53214501Srpaulo} 54214501Srpaulo 55214501Srpaulo 56214501Srpaulostatic PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount) 57214501Srpaulo{ 58214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount); 59214501Srpaulo return PR_FAILURE; 60214501Srpaulo} 61214501Srpaulo 62214501Srpaulo 63214501Srpaulostatic PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount) 64214501Srpaulo{ 65214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount); 66214501Srpaulo return PR_FAILURE; 67214501Srpaulo} 68214501Srpaulo 69214501Srpaulo 70214501Srpaulostatic PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov, 71214501Srpaulo PRInt32 iov_size, PRIntervalTime timeout) 72214501Srpaulo{ 73214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size); 74214501Srpaulo return PR_FAILURE; 75214501Srpaulo} 76214501Srpaulo 77214501Srpaulo 78214501Srpaulostatic PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, 79214501Srpaulo PRIntn flags, PRIntervalTime timeout) 80214501Srpaulo{ 81214501Srpaulo struct tls_connection *conn = (struct tls_connection *) fd->secret; 82214501Srpaulo u8 *end; 83214501Srpaulo 84214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount); 85214501Srpaulo 86214501Srpaulo if (conn->pull_buf == NULL) { 87214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet"); 88214501Srpaulo return PR_FAILURE; 89214501Srpaulo } 90214501Srpaulo 91214501Srpaulo end = conn->pull_buf + conn->pull_buf_len; 92214501Srpaulo if (end - conn->pull_buf_offset < amount) 93214501Srpaulo amount = end - conn->pull_buf_offset; 94214501Srpaulo os_memcpy(buf, conn->pull_buf_offset, amount); 95214501Srpaulo conn->pull_buf_offset += amount; 96214501Srpaulo if (conn->pull_buf_offset == end) { 97214501Srpaulo wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); 98214501Srpaulo os_free(conn->pull_buf); 99214501Srpaulo conn->pull_buf = conn->pull_buf_offset = NULL; 100214501Srpaulo conn->pull_buf_len = 0; 101214501Srpaulo } else { 102214501Srpaulo wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", 103214501Srpaulo __func__, 104214501Srpaulo (unsigned long) (end - conn->pull_buf_offset)); 105214501Srpaulo } 106214501Srpaulo return amount; 107214501Srpaulo} 108214501Srpaulo 109214501Srpaulo 110214501Srpaulostatic PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, 111214501Srpaulo PRIntn flags, PRIntervalTime timeout) 112214501Srpaulo{ 113214501Srpaulo struct tls_connection *conn = (struct tls_connection *) fd->secret; 114214501Srpaulo u8 *nbuf; 115214501Srpaulo 116214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); 117214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount); 118214501Srpaulo 119214501Srpaulo nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount); 120214501Srpaulo if (nbuf == NULL) { 121214501Srpaulo wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the " 122214501Srpaulo "data to be sent"); 123214501Srpaulo return PR_FAILURE; 124214501Srpaulo } 125214501Srpaulo os_memcpy(nbuf + conn->push_buf_len, buf, amount); 126214501Srpaulo conn->push_buf = nbuf; 127214501Srpaulo conn->push_buf_len += amount; 128214501Srpaulo 129214501Srpaulo return amount; 130214501Srpaulo} 131214501Srpaulo 132214501Srpaulo 133214501Srpaulostatic PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, 134214501Srpaulo PRIntn flags, PRNetAddr *addr, 135214501Srpaulo PRIntervalTime timeout) 136214501Srpaulo{ 137214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); 138214501Srpaulo return PR_FAILURE; 139214501Srpaulo} 140214501Srpaulo 141214501Srpaulo 142214501Srpaulostatic PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, 143214501Srpaulo PRIntn flags, const PRNetAddr *addr, 144214501Srpaulo PRIntervalTime timeout) 145214501Srpaulo{ 146214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); 147214501Srpaulo return PR_FAILURE; 148214501Srpaulo} 149214501Srpaulo 150214501Srpaulo 151214501Srpaulostatic PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr) 152214501Srpaulo{ 153214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O getpeername"); 154214501Srpaulo 155214501Srpaulo /* 156214501Srpaulo * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a 157214501Srpaulo * fake IPv4 address to work around this even though we are not really 158214501Srpaulo * using TCP. 159214501Srpaulo */ 160214501Srpaulo os_memset(addr, 0, sizeof(*addr)); 161214501Srpaulo addr->inet.family = PR_AF_INET; 162214501Srpaulo 163214501Srpaulo return PR_SUCCESS; 164214501Srpaulo} 165214501Srpaulo 166214501Srpaulo 167214501Srpaulostatic PRStatus nss_io_getsocketoption(PRFileDesc *fd, 168214501Srpaulo PRSocketOptionData *data) 169214501Srpaulo{ 170214501Srpaulo switch (data->option) { 171214501Srpaulo case PR_SockOpt_Nonblocking: 172214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)"); 173214501Srpaulo data->value.non_blocking = PR_TRUE; 174214501Srpaulo return PR_SUCCESS; 175214501Srpaulo default: 176214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)", 177214501Srpaulo data->option); 178214501Srpaulo return PR_FAILURE; 179214501Srpaulo } 180214501Srpaulo} 181214501Srpaulo 182214501Srpaulo 183214501Srpaulostatic const PRIOMethods nss_io = { 184214501Srpaulo PR_DESC_LAYERED, 185214501Srpaulo nss_io_close, 186214501Srpaulo nss_io_read, 187214501Srpaulo nss_io_write, 188214501Srpaulo NULL /* available */, 189214501Srpaulo NULL /* available64 */, 190214501Srpaulo NULL /* fsync */, 191214501Srpaulo NULL /* fseek */, 192214501Srpaulo NULL /* fseek64 */, 193214501Srpaulo NULL /* fileinfo */, 194214501Srpaulo NULL /* fileinfo64 */, 195214501Srpaulo nss_io_writev, 196214501Srpaulo NULL /* connect */, 197214501Srpaulo NULL /* accept */, 198214501Srpaulo NULL /* bind */, 199214501Srpaulo NULL /* listen */, 200214501Srpaulo NULL /* shutdown */, 201214501Srpaulo nss_io_recv, 202214501Srpaulo nss_io_send, 203214501Srpaulo nss_io_recvfrom, 204214501Srpaulo nss_io_sendto, 205214501Srpaulo NULL /* poll */, 206214501Srpaulo NULL /* acceptread */, 207214501Srpaulo NULL /* transmitfile */, 208214501Srpaulo NULL /* getsockname */, 209214501Srpaulo nss_io_getpeername, 210214501Srpaulo NULL /* reserved_fn_6 */, 211214501Srpaulo NULL /* reserved_fn_5 */, 212214501Srpaulo nss_io_getsocketoption, 213214501Srpaulo NULL /* setsocketoption */, 214214501Srpaulo NULL /* sendfile */, 215214501Srpaulo NULL /* connectcontinue */, 216214501Srpaulo NULL /* reserved_fn_3 */, 217214501Srpaulo NULL /* reserved_fn_2 */, 218214501Srpaulo NULL /* reserved_fn_1 */, 219214501Srpaulo NULL /* reserved_fn_0 */ 220214501Srpaulo}; 221214501Srpaulo 222214501Srpaulo 223214501Srpaulostatic char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg) 224214501Srpaulo{ 225214501Srpaulo wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); 226214501Srpaulo return NULL; 227214501Srpaulo} 228214501Srpaulo 229214501Srpaulo 230214501Srpaulovoid * tls_init(const struct tls_config *conf) 231214501Srpaulo{ 232214501Srpaulo char *dir; 233214501Srpaulo 234214501Srpaulo tls_nss_ref_count++; 235214501Srpaulo if (tls_nss_ref_count > 1) 236214501Srpaulo return (void *) 1; 237214501Srpaulo 238214501Srpaulo PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 239214501Srpaulo 240214501Srpaulo nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant"); 241214501Srpaulo 242214501Srpaulo PK11_SetPasswordFunc(nss_password_cb); 243214501Srpaulo 244214501Srpaulo dir = getenv("SSL_DIR"); 245214501Srpaulo if (dir) { 246214501Srpaulo if (NSS_Init(dir) != SECSuccess) { 247214501Srpaulo wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) " 248214501Srpaulo "failed", dir); 249214501Srpaulo return NULL; 250214501Srpaulo } 251214501Srpaulo } else { 252214501Srpaulo if (NSS_NoDB_Init(NULL) != SECSuccess) { 253214501Srpaulo wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) " 254214501Srpaulo "failed"); 255214501Srpaulo return NULL; 256214501Srpaulo } 257214501Srpaulo } 258214501Srpaulo 259214501Srpaulo if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != 260214501Srpaulo SECSuccess || 261214501Srpaulo SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess || 262214501Srpaulo SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess || 263214501Srpaulo SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) { 264214501Srpaulo wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed"); 265214501Srpaulo return NULL; 266214501Srpaulo } 267214501Srpaulo 268214501Srpaulo if (NSS_SetDomesticPolicy() != SECSuccess) { 269214501Srpaulo wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed"); 270214501Srpaulo return NULL; 271214501Srpaulo } 272214501Srpaulo 273214501Srpaulo return (void *) 1; 274214501Srpaulo} 275214501Srpaulo 276214501Srpaulovoid tls_deinit(void *ssl_ctx) 277214501Srpaulo{ 278214501Srpaulo tls_nss_ref_count--; 279214501Srpaulo if (tls_nss_ref_count == 0) { 280214501Srpaulo if (NSS_Shutdown() != SECSuccess) 281214501Srpaulo wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed"); 282214501Srpaulo } 283214501Srpaulo} 284214501Srpaulo 285214501Srpaulo 286214501Srpauloint tls_get_errors(void *tls_ctx) 287214501Srpaulo{ 288214501Srpaulo return 0; 289214501Srpaulo} 290214501Srpaulo 291214501Srpaulo 292214501Srpaulostatic SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd) 293214501Srpaulo{ 294214501Srpaulo struct tls_connection *conn = arg; 295214501Srpaulo SECStatus res = SECSuccess; 296214501Srpaulo PRErrorCode err; 297214501Srpaulo CERTCertificate *cert; 298214501Srpaulo char *subject, *issuer; 299214501Srpaulo 300214501Srpaulo err = PR_GetError(); 301214501Srpaulo if (IS_SEC_ERROR(err)) 302214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err " 303214501Srpaulo "%d)", err - SEC_ERROR_BASE); 304214501Srpaulo else 305214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)", 306214501Srpaulo err); 307214501Srpaulo cert = SSL_PeerCertificate(fd); 308214501Srpaulo subject = CERT_NameToAscii(&cert->subject); 309214501Srpaulo issuer = CERT_NameToAscii(&cert->issuer); 310214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'", 311214501Srpaulo subject, issuer); 312214501Srpaulo CERT_DestroyCertificate(cert); 313214501Srpaulo PR_Free(subject); 314214501Srpaulo PR_Free(issuer); 315214501Srpaulo if (conn->verify_peer) 316214501Srpaulo res = SECFailure; 317214501Srpaulo 318214501Srpaulo return res; 319214501Srpaulo} 320214501Srpaulo 321214501Srpaulo 322214501Srpaulostatic void nss_handshake_cb(PRFileDesc *fd, void *client_data) 323214501Srpaulo{ 324214501Srpaulo struct tls_connection *conn = client_data; 325214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: Handshake completed"); 326214501Srpaulo conn->established = 1; 327214501Srpaulo} 328214501Srpaulo 329214501Srpaulo 330214501Srpaulostruct tls_connection * tls_connection_init(void *tls_ctx) 331214501Srpaulo{ 332214501Srpaulo struct tls_connection *conn; 333214501Srpaulo 334214501Srpaulo conn = os_zalloc(sizeof(*conn)); 335214501Srpaulo if (conn == NULL) 336214501Srpaulo return NULL; 337214501Srpaulo 338214501Srpaulo conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io); 339214501Srpaulo if (conn->fd == NULL) { 340214501Srpaulo os_free(conn); 341214501Srpaulo return NULL; 342214501Srpaulo } 343214501Srpaulo conn->fd->secret = (void *) conn; 344214501Srpaulo 345214501Srpaulo conn->fd = SSL_ImportFD(NULL, conn->fd); 346214501Srpaulo if (conn->fd == NULL) { 347214501Srpaulo os_free(conn); 348214501Srpaulo return NULL; 349214501Srpaulo } 350214501Srpaulo 351214501Srpaulo if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess || 352214501Srpaulo SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != 353214501Srpaulo SECSuccess || 354214501Srpaulo SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != 355214501Srpaulo SECSuccess || 356214501Srpaulo SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess || 357214501Srpaulo SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess || 358214501Srpaulo SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) != 359214501Srpaulo SECSuccess) { 360214501Srpaulo wpa_printf(MSG_ERROR, "NSS: Failed to set options"); 361214501Srpaulo PR_Close(conn->fd); 362214501Srpaulo os_free(conn); 363214501Srpaulo return NULL; 364214501Srpaulo } 365214501Srpaulo 366214501Srpaulo SSL_ResetHandshake(conn->fd, PR_FALSE); 367214501Srpaulo 368214501Srpaulo return conn; 369214501Srpaulo} 370214501Srpaulo 371214501Srpaulo 372214501Srpaulovoid tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) 373214501Srpaulo{ 374214501Srpaulo PR_Close(conn->fd); 375214501Srpaulo os_free(conn->push_buf); 376214501Srpaulo os_free(conn->pull_buf); 377214501Srpaulo os_free(conn); 378214501Srpaulo} 379214501Srpaulo 380214501Srpaulo 381214501Srpauloint tls_connection_established(void *tls_ctx, struct tls_connection *conn) 382214501Srpaulo{ 383214501Srpaulo return conn->established; 384214501Srpaulo} 385214501Srpaulo 386214501Srpaulo 387214501Srpauloint tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) 388214501Srpaulo{ 389214501Srpaulo return -1; 390214501Srpaulo} 391214501Srpaulo 392214501Srpaulo 393214501Srpauloint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, 394214501Srpaulo const struct tls_connection_params *params) 395214501Srpaulo{ 396214501Srpaulo wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); 397214501Srpaulo return 0; 398214501Srpaulo} 399214501Srpaulo 400214501Srpaulo 401214501Srpauloint tls_global_set_params(void *tls_ctx, 402214501Srpaulo const struct tls_connection_params *params) 403214501Srpaulo{ 404214501Srpaulo return -1; 405214501Srpaulo} 406214501Srpaulo 407214501Srpaulo 408214501Srpauloint tls_global_set_verify(void *tls_ctx, int check_crl) 409214501Srpaulo{ 410214501Srpaulo return -1; 411214501Srpaulo} 412214501Srpaulo 413214501Srpaulo 414214501Srpauloint tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, 415214501Srpaulo int verify_peer) 416214501Srpaulo{ 417214501Srpaulo conn->verify_peer = verify_peer; 418214501Srpaulo return 0; 419214501Srpaulo} 420214501Srpaulo 421214501Srpaulo 422214501Srpauloint tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, 423214501Srpaulo int tls_ia) 424214501Srpaulo{ 425214501Srpaulo return -1; 426214501Srpaulo} 427214501Srpaulo 428214501Srpaulo 429214501Srpauloint tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, 430214501Srpaulo struct tls_keys *keys) 431214501Srpaulo{ 432214501Srpaulo /* NSS does not export master secret or client/server random. */ 433214501Srpaulo return -1; 434214501Srpaulo} 435214501Srpaulo 436214501Srpaulo 437214501Srpauloint tls_connection_prf(void *tls_ctx, struct tls_connection *conn, 438214501Srpaulo const char *label, int server_random_first, 439214501Srpaulo u8 *out, size_t out_len) 440214501Srpaulo{ 441214501Srpaulo if (conn == NULL || server_random_first) { 442214501Srpaulo wpa_printf(MSG_INFO, "NSS: Unsupported PRF request " 443214501Srpaulo "(server_random_first=%d)", 444214501Srpaulo server_random_first); 445214501Srpaulo return -1; 446214501Srpaulo } 447214501Srpaulo 448214501Srpaulo if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) != 449214501Srpaulo SECSuccess) { 450214501Srpaulo wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor " 451214501Srpaulo "(label='%s' out_len=%d", label, (int) out_len); 452214501Srpaulo return -1; 453214501Srpaulo } 454214501Srpaulo 455214501Srpaulo return 0; 456214501Srpaulo} 457214501Srpaulo 458214501Srpaulo 459214501Srpaulostruct wpabuf * tls_connection_handshake(void *tls_ctx, 460214501Srpaulo struct tls_connection *conn, 461214501Srpaulo const struct wpabuf *in_data, 462214501Srpaulo struct wpabuf **appl_data) 463214501Srpaulo{ 464214501Srpaulo struct wpabuf *out_data; 465214501Srpaulo 466214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u", 467214501Srpaulo in_data ? (unsigned int) wpabuf_len(in_data) : 0); 468214501Srpaulo 469214501Srpaulo if (appl_data) 470214501Srpaulo *appl_data = NULL; 471214501Srpaulo 472214501Srpaulo if (in_data && wpabuf_len(in_data) > 0) { 473214501Srpaulo if (conn->pull_buf) { 474214501Srpaulo wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " 475214501Srpaulo "pull_buf", __func__, 476214501Srpaulo (unsigned long) conn->pull_buf_len); 477214501Srpaulo os_free(conn->pull_buf); 478214501Srpaulo } 479214501Srpaulo conn->pull_buf = os_malloc(wpabuf_len(in_data)); 480214501Srpaulo if (conn->pull_buf == NULL) 481214501Srpaulo return NULL; 482214501Srpaulo os_memcpy(conn->pull_buf, wpabuf_head(in_data), 483214501Srpaulo wpabuf_len(in_data)); 484214501Srpaulo conn->pull_buf_offset = conn->pull_buf; 485214501Srpaulo conn->pull_buf_len = wpabuf_len(in_data); 486214501Srpaulo } 487214501Srpaulo 488214501Srpaulo SSL_ForceHandshake(conn->fd); 489214501Srpaulo 490214501Srpaulo if (conn->established && conn->push_buf == NULL) { 491214501Srpaulo /* Need to return something to get final TLS ACK. */ 492214501Srpaulo conn->push_buf = os_malloc(1); 493214501Srpaulo } 494214501Srpaulo 495214501Srpaulo if (conn->push_buf == NULL) 496214501Srpaulo return NULL; 497214501Srpaulo out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); 498214501Srpaulo if (out_data == NULL) 499214501Srpaulo os_free(conn->push_buf); 500214501Srpaulo conn->push_buf = NULL; 501214501Srpaulo conn->push_buf_len = 0; 502214501Srpaulo return out_data; 503214501Srpaulo} 504214501Srpaulo 505214501Srpaulo 506214501Srpaulostruct wpabuf * tls_connection_server_handshake(void *tls_ctx, 507214501Srpaulo struct tls_connection *conn, 508214501Srpaulo const struct wpabuf *in_data, 509214501Srpaulo struct wpabuf **appl_data) 510214501Srpaulo{ 511214501Srpaulo return NULL; 512214501Srpaulo} 513214501Srpaulo 514214501Srpaulo 515214501Srpaulostruct wpabuf * tls_connection_encrypt(void *tls_ctx, 516214501Srpaulo struct tls_connection *conn, 517214501Srpaulo const struct wpabuf *in_data) 518214501Srpaulo{ 519214501Srpaulo PRInt32 res; 520214501Srpaulo struct wpabuf *buf; 521214501Srpaulo 522214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", 523214501Srpaulo (int) wpabuf_len(in_data)); 524214501Srpaulo res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0, 525214501Srpaulo 0); 526214501Srpaulo if (res < 0) { 527214501Srpaulo wpa_printf(MSG_ERROR, "NSS: Encryption failed"); 528214501Srpaulo return NULL; 529214501Srpaulo } 530214501Srpaulo if (conn->push_buf == NULL) 531214501Srpaulo return NULL; 532214501Srpaulo buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); 533214501Srpaulo if (buf == NULL) 534214501Srpaulo os_free(conn->push_buf); 535214501Srpaulo conn->push_buf = NULL; 536214501Srpaulo conn->push_buf_len = 0; 537214501Srpaulo return buf; 538214501Srpaulo} 539214501Srpaulo 540214501Srpaulo 541214501Srpaulostruct wpabuf * tls_connection_decrypt(void *tls_ctx, 542214501Srpaulo struct tls_connection *conn, 543214501Srpaulo const struct wpabuf *in_data) 544214501Srpaulo{ 545214501Srpaulo PRInt32 res; 546214501Srpaulo struct wpabuf *out; 547214501Srpaulo 548214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", 549214501Srpaulo (int) wpabuf_len(in_data)); 550214501Srpaulo if (conn->pull_buf) { 551214501Srpaulo wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " 552214501Srpaulo "pull_buf", __func__, 553214501Srpaulo (unsigned long) conn->pull_buf_len); 554214501Srpaulo os_free(conn->pull_buf); 555214501Srpaulo } 556214501Srpaulo conn->pull_buf = os_malloc(wpabuf_len(in_data)); 557214501Srpaulo if (conn->pull_buf == NULL) 558214501Srpaulo return NULL; 559214501Srpaulo os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); 560214501Srpaulo conn->pull_buf_offset = conn->pull_buf; 561214501Srpaulo conn->pull_buf_len = wpabuf_len(in_data); 562214501Srpaulo 563214501Srpaulo /* 564214501Srpaulo * Even though we try to disable TLS compression, it is possible that 565214501Srpaulo * this cannot be done with all TLS libraries. Add extra buffer space 566214501Srpaulo * to handle the possibility of the decrypted data being longer than 567214501Srpaulo * input data. 568214501Srpaulo */ 569214501Srpaulo out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); 570214501Srpaulo if (out == NULL) 571214501Srpaulo return NULL; 572214501Srpaulo 573214501Srpaulo res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0); 574214501Srpaulo wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res); 575214501Srpaulo if (res < 0) { 576214501Srpaulo wpabuf_free(out); 577214501Srpaulo return NULL; 578214501Srpaulo } 579214501Srpaulo wpabuf_put(out, res); 580214501Srpaulo 581214501Srpaulo return out; 582214501Srpaulo} 583214501Srpaulo 584214501Srpaulo 585214501Srpauloint tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) 586214501Srpaulo{ 587214501Srpaulo return 0; 588214501Srpaulo} 589214501Srpaulo 590214501Srpaulo 591214501Srpauloint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, 592214501Srpaulo u8 *ciphers) 593214501Srpaulo{ 594214501Srpaulo return -1; 595214501Srpaulo} 596214501Srpaulo 597214501Srpaulo 598214501Srpauloint tls_get_cipher(void *tls_ctx, struct tls_connection *conn, 599214501Srpaulo char *buf, size_t buflen) 600214501Srpaulo{ 601214501Srpaulo return -1; 602214501Srpaulo} 603214501Srpaulo 604214501Srpaulo 605214501Srpauloint tls_connection_enable_workaround(void *tls_ctx, 606214501Srpaulo struct tls_connection *conn) 607214501Srpaulo{ 608214501Srpaulo return -1; 609214501Srpaulo} 610214501Srpaulo 611214501Srpaulo 612214501Srpauloint tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, 613214501Srpaulo int ext_type, const u8 *data, 614214501Srpaulo size_t data_len) 615214501Srpaulo{ 616214501Srpaulo return -1; 617214501Srpaulo} 618214501Srpaulo 619214501Srpaulo 620214501Srpauloint tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) 621214501Srpaulo{ 622214501Srpaulo return 0; 623214501Srpaulo} 624214501Srpaulo 625214501Srpaulo 626214501Srpauloint tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) 627214501Srpaulo{ 628214501Srpaulo return 0; 629214501Srpaulo} 630214501Srpaulo 631214501Srpaulo 632214501Srpauloint tls_connection_get_write_alerts(void *tls_ctx, 633214501Srpaulo struct tls_connection *conn) 634214501Srpaulo{ 635214501Srpaulo return 0; 636214501Srpaulo} 637214501Srpaulo 638214501Srpaulo 639214501Srpauloint tls_connection_get_keyblock_size(void *tls_ctx, 640214501Srpaulo struct tls_connection *conn) 641214501Srpaulo{ 642214501Srpaulo return -1; 643214501Srpaulo} 644214501Srpaulo 645214501Srpaulo 646214501Srpaulounsigned int tls_capabilities(void *tls_ctx) 647214501Srpaulo{ 648214501Srpaulo return 0; 649214501Srpaulo} 650214501Srpaulo 651214501Srpaulo 652214501Srpaulostruct wpabuf * tls_connection_ia_send_phase_finished( 653214501Srpaulo void *tls_ctx, struct tls_connection *conn, int final) 654214501Srpaulo{ 655214501Srpaulo return NULL; 656214501Srpaulo} 657214501Srpaulo 658214501Srpaulo 659214501Srpauloint tls_connection_ia_final_phase_finished(void *tls_ctx, 660214501Srpaulo struct tls_connection *conn) 661214501Srpaulo{ 662214501Srpaulo return -1; 663214501Srpaulo} 664214501Srpaulo 665214501Srpaulo 666214501Srpauloint tls_connection_ia_permute_inner_secret(void *tls_ctx, 667214501Srpaulo struct tls_connection *conn, 668214501Srpaulo const u8 *key, size_t key_len) 669214501Srpaulo{ 670214501Srpaulo return -1; 671214501Srpaulo} 672214501Srpaulo 673214501Srpaulo 674214501Srpauloint tls_connection_set_session_ticket_cb(void *tls_ctx, 675214501Srpaulo struct tls_connection *conn, 676214501Srpaulo tls_session_ticket_cb cb, 677214501Srpaulo void *ctx) 678214501Srpaulo{ 679214501Srpaulo return -1; 680214501Srpaulo} 681