Add preliminary version of NSS TLS/crypto wrapper for wpa_supplicant
authorJouni Malinen <j@w1.fi>
Mon, 28 Sep 2009 22:21:09 +0000 (01:21 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 28 Sep 2009 22:21:09 +0000 (01:21 +0300)
This brings in the first step in adding support for using NSS
(Mozilla Network Security Services) as the crypto and TLS library
with wpa_supplicant. This version is able to run through EAP-PEAP
and EAP-TTLS authentication, but does not yet implement any
certificate/private key configuration. In addition, this does not
implement proper key fetching functions either, so the end result
is not really of much use in real world yet.

src/crypto/crypto_nss.c [new file with mode: 0644]
src/crypto/fips_prf_nss.c [new file with mode: 0644]
src/crypto/tls_nss.c [new file with mode: 0644]
wpa_supplicant/Makefile

diff --git a/src/crypto/crypto_nss.c b/src/crypto/crypto_nss.c
new file mode 100644 (file)
index 0000000..fee4195
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Crypto wrapper functions for NSS
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <nspr/prtypes.h>
+#include <nspr/plarenas.h>
+#include <nspr/plhash.h>
+#include <nspr/prtime.h>
+#include <nspr/prinrval.h>
+#include <nspr/prclist.h>
+#include <nspr/prlock.h>
+#include <nss/sechash.h>
+#include <nss/pk11pub.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static int nss_hash(HASH_HashType type, unsigned int max_res_len,
+                   size_t num_elem, const u8 *addr[], const size_t *len,
+                   u8 *mac)
+{
+       HASHContext *ctx;
+       size_t i;
+       unsigned int reslen;
+
+       ctx = HASH_Create(type);
+       if (ctx == NULL)
+               return -1;
+
+       HASH_Begin(ctx);
+       for (i = 0; i < num_elem; i++)
+               HASH_Update(ctx, addr[i], len[i]);
+       HASH_End(ctx, mac, &reslen, max_res_len);
+       HASH_Destroy(ctx);
+
+       return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+       PK11Context *ctx = NULL;
+       PK11SlotInfo *slot;
+       SECItem *param = NULL;
+       PK11SymKey *symkey = NULL;
+       SECItem item;
+       int olen;
+       u8 pkey[8], next, tmp;
+       int i;
+
+       /* Add parity bits to the key */
+       next = 0;
+       for (i = 0; i < 7; i++) {
+               tmp = key[i];
+               pkey[i] = (tmp >> i) | next | 1;
+               next = tmp << (7 - i);
+       }
+       pkey[i] = next | 1;
+
+       slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
+       if (slot == NULL) {
+               wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
+               goto out;
+       }
+
+       item.type = siBuffer;
+       item.data = pkey;
+       item.len = 8;
+       symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
+                                  CKA_ENCRYPT, &item, NULL);
+       if (symkey == NULL) {
+               wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
+               goto out;
+       }
+
+       param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
+       if (param == NULL) {
+               wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
+               goto out;
+       }
+
+       ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
+                                        symkey, param);
+       if (ctx == NULL) {
+               wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
+                          "CKM_DES_ECB) failed");
+               goto out;
+       }
+
+       if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
+           SECSuccess) {
+               wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
+               goto out;
+       }
+
+out:
+       if (ctx)
+               PK11_DestroyContext(ctx, PR_TRUE);
+       if (symkey)
+               PK11_FreeSymKey(symkey);
+       if (param)
+               SECITEM_FreeItem(param, PR_TRUE);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+            u8 *data, size_t data_len)
+{
+       return -1;
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+       return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+       return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+                 u8 *mac)
+{
+       return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+       return NULL;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+       return NULL;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+                  const u8 *power, size_t power_len,
+                  const u8 *modulus, size_t modulus_len,
+                  u8 *result, size_t *result_len)
+{
+       return -1;
+}
+
+
+struct crypto_cipher {
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+                                         const u8 *iv, const u8 *key,
+                                         size_t key_len)
+{
+       return NULL;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+                         u8 *crypt, size_t len)
+{
+       return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+                         u8 *plain, size_t len)
+{
+       return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+}
diff --git a/src/crypto/fips_prf_nss.c b/src/crypto/fips_prf_nss.c
new file mode 100644 (file)
index 0000000..f941983
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * FIPS 186-2 PRF for NSS
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <openssl/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+       return -1;
+}
diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c
new file mode 100644 (file)
index 0000000..ba5ce08
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * SSL/TLS interface functions for NSS
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <nspr/prtypes.h>
+#include <nspr/plarenas.h>
+#include <nspr/plhash.h>
+#include <nspr/prio.h>
+#include <nspr/prclist.h>
+#include <nspr/prlock.h>
+#include <nspr/prinit.h>
+#include <nspr/prerror.h>
+#include <nspr/prmem.h>
+#include <nss/nss.h>
+#include <nss/nssilckt.h>
+#include <nss/ssl.h>
+#include <nss/pk11func.h>
+#include <nss/secerr.h>
+
+#include "common.h"
+#include "tls.h"
+
+static int tls_nss_ref_count = 0;
+
+static PRDescIdentity nss_layer_id;
+
+
+struct tls_connection {
+       PRFileDesc *fd;
+
+       int established;
+       int verify_peer;
+       u8 *push_buf, *pull_buf, *pull_buf_offset;
+       size_t push_buf_len, pull_buf_len;
+};
+
+
+static PRStatus nss_io_close(PRFileDesc *fd)
+{
+       wpa_printf(MSG_DEBUG, "NSS: I/O close");
+       return PR_SUCCESS;
+}
+
+
+static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+       wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
+       return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+       wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
+       return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
+                            PRInt32 iov_size, PRIntervalTime timeout)
+{
+       wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
+       return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+                          PRIntn flags, PRIntervalTime timeout)
+{
+       struct tls_connection *conn = (struct tls_connection *) fd->secret;
+       u8 *end;
+
+       wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
+
+       if (conn->pull_buf == NULL) {
+               wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
+               return PR_FAILURE;
+       }
+
+       end = conn->pull_buf + conn->pull_buf_len;
+       if (end - conn->pull_buf_offset < amount)
+               amount = end - conn->pull_buf_offset;
+       os_memcpy(buf, conn->pull_buf_offset, amount);
+       conn->pull_buf_offset += amount;
+       if (conn->pull_buf_offset == end) {
+               wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
+               os_free(conn->pull_buf);
+               conn->pull_buf = conn->pull_buf_offset = NULL;
+               conn->pull_buf_len = 0;
+       } else {
+               wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
+                          __func__,
+                          (unsigned long) (end - conn->pull_buf_offset));
+       }
+       return amount;
+}
+
+
+static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+                          PRIntn flags, PRIntervalTime timeout)
+{
+       struct tls_connection *conn = (struct tls_connection *) fd->secret;
+       u8 *nbuf;
+
+       wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+       wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
+
+       nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
+       if (nbuf == NULL) {
+               wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
+                          "data to be sent");
+               return PR_FAILURE;
+       }
+       os_memcpy(nbuf + conn->push_buf_len, buf, amount);
+       conn->push_buf = nbuf;
+       conn->push_buf_len += amount;
+
+       return amount;
+}
+
+
+static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+                              PRIntn flags, PRNetAddr *addr,
+                              PRIntervalTime timeout)
+{
+       wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+       return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
+                            PRIntn flags, const PRNetAddr *addr,
+                            PRIntervalTime timeout)
+{
+       wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+       return PR_FAILURE;
+}
+
+
+static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
+{
+       wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
+
+       /*
+        * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
+        * fake IPv4 address to work around this even though we are not really
+        * using TCP.
+        */
+       os_memset(addr, 0, sizeof(*addr));
+       addr->inet.family = PR_AF_INET;
+
+       return PR_SUCCESS;
+}
+
+
+static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
+                                      PRSocketOptionData *data)
+{
+       switch (data->option) {
+       case PR_SockOpt_Nonblocking:
+               wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
+               data->value.non_blocking = PR_TRUE;
+               return PR_SUCCESS;
+       default:
+               wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
+                          data->option);
+               return PR_FAILURE;
+       }
+}
+
+
+static const PRIOMethods nss_io = {
+       PR_DESC_LAYERED,
+       nss_io_close,
+       nss_io_read,
+       nss_io_write,
+       NULL /* available */,
+       NULL /* available64 */,
+       NULL /* fsync */,
+       NULL /* fseek */,
+       NULL /* fseek64 */,
+       NULL /* fileinfo */,
+       NULL /* fileinfo64 */,
+       nss_io_writev,
+       NULL /* connect */,
+       NULL /* accept */,
+       NULL /* bind */,
+       NULL /* listen */,
+       NULL /* shutdown */,
+       nss_io_recv,
+       nss_io_send,
+       nss_io_recvfrom,
+       nss_io_sendto,
+       NULL /* poll */,
+       NULL /* acceptread */,
+       NULL /* transmitfile */,
+       NULL /* getsockname */,
+       nss_io_getpeername,
+       NULL /* reserved_fn_6 */,
+       NULL /* reserved_fn_5 */,
+       nss_io_getsocketoption,
+       NULL /* setsocketoption */,
+       NULL /* sendfile */,
+       NULL /* connectcontinue */,
+       NULL /* reserved_fn_3 */,
+       NULL /* reserved_fn_2 */,
+       NULL /* reserved_fn_1 */,
+       NULL /* reserved_fn_0 */
+};
+
+
+static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+       wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
+       return NULL;
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+       char *dir;
+
+       tls_nss_ref_count++;
+       if (tls_nss_ref_count > 1)
+               return (void *) 1;
+
+       PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+
+       nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
+
+       PK11_SetPasswordFunc(nss_password_cb);
+
+       dir = getenv("SSL_DIR");
+       if (dir) {
+               if (NSS_Init(dir) != SECSuccess) {
+                       wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
+                                  "failed", dir);
+                       return NULL;
+               }
+       } else {
+               if (NSS_NoDB_Init(NULL) != SECSuccess) {
+                       wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
+                                  "failed");
+                       return NULL;
+               }
+       }
+
+       if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
+           SECSuccess ||
+           SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
+           SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
+           SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
+               wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
+               return NULL;
+       }
+
+       if (NSS_SetDomesticPolicy() != SECSuccess) {
+               wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
+               return NULL;
+       }
+
+       return (void *) 1;
+}
+
+void tls_deinit(void *ssl_ctx)
+{
+       tls_nss_ref_count--;
+       if (tls_nss_ref_count == 0) {
+               if (NSS_Shutdown() != SECSuccess)
+                       wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
+       }
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+       return 0;
+}
+
+
+static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
+{
+       struct tls_connection *conn = arg;
+       SECStatus res = SECSuccess;
+       PRErrorCode err;
+       CERTCertificate *cert;
+       char *subject, *issuer;
+
+       err = PR_GetError();
+       if (IS_SEC_ERROR(err))
+               wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
+                          "%d)", err - SEC_ERROR_BASE);
+       else
+               wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
+                          err);
+       cert = SSL_PeerCertificate(fd);
+       subject = CERT_NameToAscii(&cert->subject);
+       issuer = CERT_NameToAscii(&cert->issuer);
+       wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
+                  subject, issuer);
+       CERT_DestroyCertificate(cert);
+       PR_Free(subject);
+       PR_Free(issuer);
+       if (conn->verify_peer)
+               res = SECFailure;
+
+       return res;
+}
+
+
+static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
+{
+       struct tls_connection *conn = client_data;
+       wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
+       conn->established = 1;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+       struct tls_connection *conn;
+
+       conn = os_zalloc(sizeof(*conn));
+       if (conn == NULL)
+               return NULL;
+
+       conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
+       if (conn->fd == NULL) {
+               os_free(conn);
+               return NULL;
+       }
+       conn->fd->secret = (void *) conn;
+
+       conn->fd = SSL_ImportFD(NULL, conn->fd);
+       if (conn->fd == NULL) {
+               os_free(conn);
+               return NULL;
+       }
+
+       if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
+           SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
+           SECSuccess ||
+           SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
+           SECSuccess ||
+           SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
+           SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
+           SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
+           SECSuccess) {
+               wpa_printf(MSG_ERROR, "NSS: Failed to set options");
+               PR_Close(conn->fd);
+               os_free(conn);
+               return NULL;
+       }
+
+       SSL_ResetHandshake(conn->fd, PR_FALSE);
+
+       return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+       PR_Close(conn->fd);
+       os_free(conn->push_buf);
+       os_free(conn->pull_buf);
+       os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+       return conn->established;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+       return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+                             const struct tls_connection_params *params)
+{
+       wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
+       return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+                         const struct tls_connection_params *params)
+{
+       return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+       return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+                             int verify_peer)
+{
+       conn->verify_peer = verify_peer;
+       return 0;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+                         int tls_ia)
+{
+       return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+                           struct tls_keys *keys)
+{
+       static u8 hack[48]; /* FIX */
+       wpa_printf(MSG_DEBUG, "NSS: TODO - %s", __func__);
+       os_memset(keys, 0, sizeof(*keys));
+       keys->master_key = hack;
+       keys->master_key_len = 48;
+       keys->client_random = hack;
+       keys->server_random = hack;
+       keys->client_random_len = 32;
+       keys->server_random_len = 32;
+
+       return 0;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+                      const char *label, int server_random_first,
+                      u8 *out, size_t out_len)
+{
+       return -1;
+}
+
+
+u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
+                             const u8 *in_data, size_t in_len,
+                             size_t *out_len, u8 **appl_data,
+                             size_t *appl_data_len)
+{
+       u8 *out_data;
+
+       wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
+                  (unsigned int) in_len);
+
+       if (appl_data)
+               *appl_data = NULL;
+
+       if (in_data && in_len) {
+               if (conn->pull_buf) {
+                       wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+                                  "pull_buf", __func__,
+                                  (unsigned long) conn->pull_buf_len);
+                       os_free(conn->pull_buf);
+               }
+               conn->pull_buf = os_malloc(in_len);
+               if (conn->pull_buf == NULL)
+                       return NULL;
+               os_memcpy(conn->pull_buf, in_data, in_len);
+               conn->pull_buf_offset = conn->pull_buf;
+               conn->pull_buf_len = in_len;
+       }
+
+       SSL_ForceHandshake(conn->fd);
+
+       if (conn->established && conn->push_buf == NULL) {
+               /* Need to return something to get final TLS ACK. */
+               conn->push_buf = os_malloc(1);
+       }
+
+       out_data = conn->push_buf;
+       *out_len = conn->push_buf_len;
+       conn->push_buf = NULL;
+       conn->push_buf_len = 0;
+       return out_data;
+}
+
+
+u8 * tls_connection_server_handshake(void *tls_ctx,
+                                    struct tls_connection *conn,
+                                    const u8 *in_data, size_t in_len,
+                                    size_t *out_len)
+{
+       return NULL;
+}
+
+
+int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn,
+                          const u8 *in_data, size_t in_len,
+                          u8 *out_data, size_t out_len)
+{
+       PRInt32 res;
+
+       wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", (int) in_len);
+       res = PR_Send(conn->fd, in_data, in_len, 0, 0);
+       if (res < 0) {
+               wpa_printf(MSG_ERROR, "NSS: Encryption failed");
+               return -1;
+       }
+       if (conn->push_buf == NULL)
+               return -1;
+       if (conn->push_buf_len < out_len)
+               out_len = conn->push_buf_len;
+       else if (conn->push_buf_len > out_len) {
+               wpa_printf(MSG_INFO, "NSS: Not enough buffer space for "
+                          "encrypted message (in_len=%lu push_buf_len=%lu "
+                          "out_len=%lu",
+                          (unsigned long) in_len,
+                          (unsigned long) conn->push_buf_len,
+                          (unsigned long) out_len);
+       }
+       os_memcpy(out_data, conn->push_buf, out_len);
+       os_free(conn->push_buf);
+       conn->push_buf = NULL;
+       conn->push_buf_len = 0;
+       return out_len;
+}
+
+
+int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
+                          const u8 *in_data, size_t in_len,
+                          u8 *out_data, size_t out_len)
+{
+       PRInt32 res;
+
+       wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", (int) in_len);
+       if (conn->pull_buf) {
+               wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+                          "pull_buf", __func__,
+                          (unsigned long) conn->pull_buf_len);
+               os_free(conn->pull_buf);
+       }
+       conn->pull_buf = os_malloc(in_len);
+       if (conn->pull_buf == NULL)
+               return -1;
+       os_memcpy(conn->pull_buf, in_data, in_len);
+       conn->pull_buf_offset = conn->pull_buf;
+       conn->pull_buf_len = in_len;
+
+       res = PR_Recv(conn->fd, out_data, out_len, 0, 0);
+       wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
+
+       return res;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+       return 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+                                  u8 *ciphers)
+{
+       return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+                  char *buf, size_t buflen)
+{
+       return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+                                    struct tls_connection *conn)
+{
+       return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+                                   int ext_type, const u8 *data,
+                                   size_t data_len)
+{
+       return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+       return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+       return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+                                   struct tls_connection *conn)
+{
+       return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+                                    struct tls_connection *conn)
+{
+       return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+       return 0;
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+                                         struct tls_connection *conn,
+                                         int final,
+                                         u8 *out_data, size_t out_len)
+{
+       return -1;
+}
+
+
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+                                          struct tls_connection *conn)
+{
+       return -1;
+}
+
+
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+                                          struct tls_connection *conn,
+                                          const u8 *key, size_t key_len)
+{
+       return -1;
+}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+                                        struct tls_connection *conn,
+                                        tls_session_ticket_cb cb,
+                                        void *ctx)
+{
+       return -1;
+}
index 354f917..9e20c76 100644 (file)
@@ -655,6 +655,10 @@ endif
 ifeq ($(CONFIG_TLS), schannel)
 OBJS += ../src/crypto/tls_schannel.o
 endif
+ifeq ($(CONFIG_TLS), nss)
+OBJS += ../src/crypto/tls_nss.o
+LIBS += -lnss3 -lssl3
+endif
 ifeq ($(CONFIG_TLS), internal)
 OBJS += ../src/crypto/tls_internal.o
 OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
@@ -724,6 +728,9 @@ LIBS_p += -lgcrypt
 endif
 ifeq ($(CONFIG_TLS), schannel)
 endif
+ifeq ($(CONFIG_TLS), nss)
+LIBS += -lnss3
+endif
 ifeq ($(CONFIG_TLS), internal)
 ifeq ($(CONFIG_CRYPTO), libtomcrypt)
 LIBS += -ltomcrypt -ltfm
@@ -753,6 +760,14 @@ OBJS_p += ../src/crypto/crypto_cryptoapi.o
 CONFIG_INTERNAL_SHA256=y
 CONFIG_INTERNAL_RC4=y
 endif
+ifeq ($(CONFIG_TLS), nss)
+OBJS += ../src/crypto/crypto_nss.o
+OBJS_p += ../src/crypto/crypto_nss.o
+CONFIG_INTERNAL_MD4=y
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_nss.o
+endif
+endif
 ifeq ($(CONFIG_TLS), internal)
 ifeq ($(CONFIG_CRYPTO), libtomcrypt)
 OBJS += ../src/crypto/crypto_libtomcrypt.o
@@ -1081,6 +1096,9 @@ endif
 ifeq ($(CONFIG_TLS), gnutls)
 OBJS_priv += ../src/crypto/crypto_gnutls.o
 endif
+ifeq ($(CONFIG_TLS), nss)
+OBJS_priv += ../src/crypto/crypto_nss.o
+endif
 ifeq ($(CONFIG_TLS), internal)
 ifeq ($(CONFIG_CRYPTO), libtomcrypt)
 OBJS_priv += ../src/crypto/crypto_libtomcrypt.o