Merge branch 'vendor/GCC50'
[dragonfly.git] / contrib / hostapd / src / crypto / tls_nss.c
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
28 static int tls_nss_ref_count = 0;
29
30 static PRDescIdentity nss_layer_id;
31
32
33 struct 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
43 static PRStatus nss_io_close(PRFileDesc *fd)
44 {
45         wpa_printf(MSG_DEBUG, "NSS: I/O close");
46         return PR_SUCCESS;
47 }
48
49
50 static 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
57 static 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
64 static 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
72 static 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
104 static 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
127 static 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
136 static 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
145 static 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
161 static 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
177 static 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
217 static 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
224 void * 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
270 void 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
280 int tls_get_errors(void *tls_ctx)
281 {
282         return 0;
283 }
284
285
286 static 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
316 static 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
324 struct 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
366 void 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
375 int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
376 {
377         return conn->established;
378 }
379
380
381 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
382 {
383         return -1;
384 }
385
386
387 int 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
395 int tls_global_set_params(void *tls_ctx,
396                           const struct tls_connection_params *params)
397 {
398         return -1;
399 }
400
401
402 int tls_global_set_verify(void *tls_ctx, int check_crl)
403 {
404         return -1;
405 }
406
407
408 int 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
416 int 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
424 int 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
446 struct 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
493 struct 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
502 struct 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
528 struct 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
572 int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
573 {
574         return 0;
575 }
576
577
578 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
579                                    u8 *ciphers)
580 {
581         return -1;
582 }
583
584
585 int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
586                    char *buf, size_t buflen)
587 {
588         return -1;
589 }
590
591
592 int tls_connection_enable_workaround(void *tls_ctx,
593                                      struct tls_connection *conn)
594 {
595         return -1;
596 }
597
598
599 int 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
607 int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
608 {
609         return 0;
610 }
611
612
613 int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
614 {
615         return 0;
616 }
617
618
619 int tls_connection_get_write_alerts(void *tls_ctx,
620                                     struct tls_connection *conn)
621 {
622         return 0;
623 }
624
625
626 int tls_connection_get_keyblock_size(void *tls_ctx,
627                                      struct tls_connection *conn)
628 {
629         return -1;
630 }
631
632
633 unsigned int tls_capabilities(void *tls_ctx)
634 {
635         return 0;
636 }
637
638
639 int 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 }