blob: 185c243f5e52dc03d4f5950add752cf99134aea4 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2008, Google Inc.
4 * Copyright 2004--2011, RTFM, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <vector>
30
31#if HAVE_CONFIG_H
32#include "config.h"
33#endif // HAVE_CONFIG_H
34
35#if HAVE_NSS_SSL_H
36
37#include "talk/base/nssstreamadapter.h"
38
39#include "keyhi.h"
40#include "nspr.h"
41#include "nss.h"
42#include "pk11pub.h"
43#include "secerr.h"
44
45#ifdef NSS_SSL_RELATIVE_PATH
46#include "ssl.h"
47#include "sslerr.h"
48#include "sslproto.h"
49#else
50#include "net/third_party/nss/ssl/ssl.h"
51#include "net/third_party/nss/ssl/sslerr.h"
52#include "net/third_party/nss/ssl/sslproto.h"
53#endif
54
55#include "talk/base/nssidentity.h"
56#include "talk/base/thread.h"
57
58namespace talk_base {
59
60PRDescIdentity NSSStreamAdapter::nspr_layer_identity = PR_INVALID_IO_LAYER;
61
62#define UNIMPLEMENTED \
63 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); \
64 LOG(LS_ERROR) \
65 << "Call to unimplemented function "<< __FUNCTION__; ASSERT(false)
66
67#ifdef SRTP_AES128_CM_HMAC_SHA1_80
68#define HAVE_DTLS_SRTP
69#endif
70
71#ifdef HAVE_DTLS_SRTP
72// SRTP cipher suite table
73struct SrtpCipherMapEntry {
74 const char* external_name;
75 PRUint16 cipher_id;
76};
77
78// This isn't elegant, but it's better than an external reference
79static const SrtpCipherMapEntry kSrtpCipherMap[] = {
80 {"AES_CM_128_HMAC_SHA1_80", SRTP_AES128_CM_HMAC_SHA1_80 },
81 {"AES_CM_128_HMAC_SHA1_32", SRTP_AES128_CM_HMAC_SHA1_32 },
82 {NULL, 0}
83};
84#endif
85
86
87// Implementation of NSPR methods
88static PRStatus StreamClose(PRFileDesc *socket) {
89 // Noop
90 return PR_SUCCESS;
91}
92
93static PRInt32 StreamRead(PRFileDesc *socket, void *buf, PRInt32 length) {
94 StreamInterface *stream = reinterpret_cast<StreamInterface *>(socket->secret);
95 size_t read;
96 int error;
97 StreamResult result = stream->Read(buf, length, &read, &error);
98 if (result == SR_SUCCESS) {
99 return read;
100 }
101
102 if (result == SR_EOS) {
103 return 0;
104 }
105
106 if (result == SR_BLOCK) {
107 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
108 return -1;
109 }
110
111 PR_SetError(PR_UNKNOWN_ERROR, error);
112 return -1;
113}
114
115static PRInt32 StreamWrite(PRFileDesc *socket, const void *buf,
116 PRInt32 length) {
117 StreamInterface *stream = reinterpret_cast<StreamInterface *>(socket->secret);
118 size_t written;
119 int error;
120 StreamResult result = stream->Write(buf, length, &written, &error);
121 if (result == SR_SUCCESS) {
122 return written;
123 }
124
125 if (result == SR_BLOCK) {
126 LOG(LS_INFO) <<
127 "NSSStreamAdapter: write to underlying transport would block";
128 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
129 return -1;
130 }
131
132 LOG(LS_ERROR) << "Write error";
133 PR_SetError(PR_UNKNOWN_ERROR, error);
134 return -1;
135}
136
137static PRInt32 StreamAvailable(PRFileDesc *socket) {
138 UNIMPLEMENTED;
139 return -1;
140}
141
142PRInt64 StreamAvailable64(PRFileDesc *socket) {
143 UNIMPLEMENTED;
144 return -1;
145}
146
147static PRStatus StreamSync(PRFileDesc *socket) {
148 UNIMPLEMENTED;
149 return PR_FAILURE;
150}
151
152static PROffset32 StreamSeek(PRFileDesc *socket, PROffset32 offset,
153 PRSeekWhence how) {
154 UNIMPLEMENTED;
155 return -1;
156}
157
158static PROffset64 StreamSeek64(PRFileDesc *socket, PROffset64 offset,
159 PRSeekWhence how) {
160 UNIMPLEMENTED;
161 return -1;
162}
163
164static PRStatus StreamFileInfo(PRFileDesc *socket, PRFileInfo *info) {
165 UNIMPLEMENTED;
166 return PR_FAILURE;
167}
168
169static PRStatus StreamFileInfo64(PRFileDesc *socket, PRFileInfo64 *info) {
170 UNIMPLEMENTED;
171 return PR_FAILURE;
172}
173
174static PRInt32 StreamWritev(PRFileDesc *socket, const PRIOVec *iov,
175 PRInt32 iov_size, PRIntervalTime timeout) {
176 UNIMPLEMENTED;
177 return -1;
178}
179
180static PRStatus StreamConnect(PRFileDesc *socket, const PRNetAddr *addr,
181 PRIntervalTime timeout) {
182 UNIMPLEMENTED;
183 return PR_FAILURE;
184}
185
186static PRFileDesc *StreamAccept(PRFileDesc *sd, PRNetAddr *addr,
187 PRIntervalTime timeout) {
188 UNIMPLEMENTED;
189 return NULL;
190}
191
192static PRStatus StreamBind(PRFileDesc *socket, const PRNetAddr *addr) {
193 UNIMPLEMENTED;
194 return PR_FAILURE;
195}
196
197static PRStatus StreamListen(PRFileDesc *socket, PRIntn depth) {
198 UNIMPLEMENTED;
199 return PR_FAILURE;
200}
201
202static PRStatus StreamShutdown(PRFileDesc *socket, PRIntn how) {
203 UNIMPLEMENTED;
204 return PR_FAILURE;
205}
206
207// Note: this is always nonblocking and ignores the timeout.
208// TODO(ekr@rtfm.com): In future verify that the socket is
209// actually in non-blocking mode.
210// This function does not support peek.
211static PRInt32 StreamRecv(PRFileDesc *socket, void *buf, PRInt32 amount,
212 PRIntn flags, PRIntervalTime to) {
213 ASSERT(flags == 0);
214
215 if (flags != 0) {
216 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
217 return -1;
218 }
219
220 return StreamRead(socket, buf, amount);
221}
222
223// Note: this is always nonblocking and assumes a zero timeout.
224// This function does not support peek.
225static PRInt32 StreamSend(PRFileDesc *socket, const void *buf,
226 PRInt32 amount, PRIntn flags,
227 PRIntervalTime to) {
228 ASSERT(flags == 0);
229
230 return StreamWrite(socket, buf, amount);
231}
232
233static PRInt32 StreamRecvfrom(PRFileDesc *socket, void *buf,
234 PRInt32 amount, PRIntn flags,
235 PRNetAddr *addr, PRIntervalTime to) {
236 UNIMPLEMENTED;
237 return -1;
238}
239
240static PRInt32 StreamSendto(PRFileDesc *socket, const void *buf,
241 PRInt32 amount, PRIntn flags,
242 const PRNetAddr *addr, PRIntervalTime to) {
243 UNIMPLEMENTED;
244 return -1;
245}
246
247static PRInt16 StreamPoll(PRFileDesc *socket, PRInt16 in_flags,
248 PRInt16 *out_flags) {
249 UNIMPLEMENTED;
250 return -1;
251}
252
253static PRInt32 StreamAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
254 PRNetAddr **raddr,
255 void *buf, PRInt32 amount, PRIntervalTime t) {
256 UNIMPLEMENTED;
257 return -1;
258}
259
260static PRInt32 StreamTransmitFile(PRFileDesc *sd, PRFileDesc *socket,
261 const void *headers, PRInt32 hlen,
262 PRTransmitFileFlags flags, PRIntervalTime t) {
263 UNIMPLEMENTED;
264 return -1;
265}
266
267static PRStatus StreamGetPeerName(PRFileDesc *socket, PRNetAddr *addr) {
268 // TODO(ekr@rtfm.com): Modify to return unique names for each channel
269 // somehow, as opposed to always the same static address. The current
270 // implementation messes up the session cache, which is why it's off
271 // elsewhere
272 addr->inet.family = PR_AF_INET;
273 addr->inet.port = 0;
274 addr->inet.ip = 0;
275
276 return PR_SUCCESS;
277}
278
279static PRStatus StreamGetSockName(PRFileDesc *socket, PRNetAddr *addr) {
280 UNIMPLEMENTED;
281 return PR_FAILURE;
282}
283
284static PRStatus StreamGetSockOption(PRFileDesc *socket, PRSocketOptionData *opt) {
285 switch (opt->option) {
286 case PR_SockOpt_Nonblocking:
287 opt->value.non_blocking = PR_TRUE;
288 return PR_SUCCESS;
289 default:
290 UNIMPLEMENTED;
291 break;
292 }
293
294 return PR_FAILURE;
295}
296
297// Imitate setting socket options. These are mostly noops.
298static PRStatus StreamSetSockOption(PRFileDesc *socket,
299 const PRSocketOptionData *opt) {
300 switch (opt->option) {
301 case PR_SockOpt_Nonblocking:
302 return PR_SUCCESS;
303 case PR_SockOpt_NoDelay:
304 return PR_SUCCESS;
305 default:
306 UNIMPLEMENTED;
307 break;
308 }
309
310 return PR_FAILURE;
311}
312
313static PRInt32 StreamSendfile(PRFileDesc *out, PRSendFileData *in,
314 PRTransmitFileFlags flags, PRIntervalTime to) {
315 UNIMPLEMENTED;
316 return -1;
317}
318
319static PRStatus StreamConnectContinue(PRFileDesc *socket, PRInt16 flags) {
320 UNIMPLEMENTED;
321 return PR_FAILURE;
322}
323
324static PRIntn StreamReserved(PRFileDesc *socket) {
325 UNIMPLEMENTED;
326 return -1;
327}
328
329static const struct PRIOMethods nss_methods = {
330 PR_DESC_LAYERED,
331 StreamClose,
332 StreamRead,
333 StreamWrite,
334 StreamAvailable,
335 StreamAvailable64,
336 StreamSync,
337 StreamSeek,
338 StreamSeek64,
339 StreamFileInfo,
340 StreamFileInfo64,
341 StreamWritev,
342 StreamConnect,
343 StreamAccept,
344 StreamBind,
345 StreamListen,
346 StreamShutdown,
347 StreamRecv,
348 StreamSend,
349 StreamRecvfrom,
350 StreamSendto,
351 StreamPoll,
352 StreamAcceptRead,
353 StreamTransmitFile,
354 StreamGetSockName,
355 StreamGetPeerName,
356 StreamReserved,
357 StreamReserved,
358 StreamGetSockOption,
359 StreamSetSockOption,
360 StreamSendfile,
361 StreamConnectContinue,
362 StreamReserved,
363 StreamReserved,
364 StreamReserved,
365 StreamReserved
366};
367
368NSSStreamAdapter::NSSStreamAdapter(StreamInterface *stream)
369 : SSLStreamAdapterHelper(stream),
370 ssl_fd_(NULL),
371 cert_ok_(false) {
372}
373
374bool NSSStreamAdapter::Init() {
375 if (nspr_layer_identity == PR_INVALID_IO_LAYER) {
376 nspr_layer_identity = PR_GetUniqueIdentity("nssstreamadapter");
377 }
378 PRFileDesc *pr_fd = PR_CreateIOLayerStub(nspr_layer_identity, &nss_methods);
379 if (!pr_fd)
380 return false;
381 pr_fd->secret = reinterpret_cast<PRFilePrivate *>(stream());
382
383 PRFileDesc *ssl_fd;
384 if (ssl_mode_ == SSL_MODE_DTLS) {
385 ssl_fd = DTLS_ImportFD(NULL, pr_fd);
386 } else {
387 ssl_fd = SSL_ImportFD(NULL, pr_fd);
388 }
389 ASSERT(ssl_fd != NULL); // This should never happen
390 if (!ssl_fd) {
391 PR_Close(pr_fd);
392 return false;
393 }
394
395 SECStatus rv;
396 // Turn on security.
397 rv = SSL_OptionSet(ssl_fd, SSL_SECURITY, PR_TRUE);
398 if (rv != SECSuccess) {
399 LOG(LS_ERROR) << "Error enabling security on SSL Socket";
400 return false;
401 }
402
403 // Disable SSLv2.
404 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SSL2, PR_FALSE);
405 if (rv != SECSuccess) {
406 LOG(LS_ERROR) << "Error disabling SSL2";
407 return false;
408 }
409
410 // Disable caching.
411 // TODO(ekr@rtfm.com): restore this when I have the caching
412 // identity set.
413 rv = SSL_OptionSet(ssl_fd, SSL_NO_CACHE, PR_TRUE);
414 if (rv != SECSuccess) {
415 LOG(LS_ERROR) << "Error disabling cache";
416 return false;
417 }
418
419 // Disable session tickets.
420 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
421 if (rv != SECSuccess) {
422 LOG(LS_ERROR) << "Error enabling tickets";
423 return false;
424 }
425
426 // Disable renegotiation.
427 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_RENEGOTIATION,
428 SSL_RENEGOTIATE_NEVER);
429 if (rv != SECSuccess) {
430 LOG(LS_ERROR) << "Error disabling renegotiation";
431 return false;
432 }
433
434 // Disable false start.
435 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_FALSE_START, PR_FALSE);
436 if (rv != SECSuccess) {
437 LOG(LS_ERROR) << "Error disabling false start";
438 return false;
439 }
440
441 ssl_fd_ = ssl_fd;
442
443 return true;
444}
445
446NSSStreamAdapter::~NSSStreamAdapter() {
447 if (ssl_fd_)
448 PR_Close(ssl_fd_);
449};
450
451
452int NSSStreamAdapter::BeginSSL() {
453 SECStatus rv;
454
455 if (!Init()) {
456 Error("Init", -1, false);
457 return -1;
458 }
459
460 ASSERT(state_ == SSL_CONNECTING);
461 // The underlying stream has been opened. If we are in peer-to-peer mode
462 // then a peer certificate must have been specified by now.
463 ASSERT(!ssl_server_name_.empty() ||
464 peer_certificate_.get() != NULL ||
465 !peer_certificate_digest_algorithm_.empty());
466 LOG(LS_INFO) << "BeginSSL: "
467 << (!ssl_server_name_.empty() ? ssl_server_name_ :
468 "with peer");
469
470 if (role_ == SSL_CLIENT) {
471 LOG(LS_INFO) << "BeginSSL: as client";
472
473 rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook,
474 this);
475 if (rv != SECSuccess) {
476 Error("BeginSSL", -1, false);
477 return -1;
478 }
479 } else {
480 LOG(LS_INFO) << "BeginSSL: as server";
481 NSSIdentity *identity;
482
483 if (identity_.get()) {
484 identity = static_cast<NSSIdentity *>(identity_.get());
485 } else {
486 LOG(LS_ERROR) << "Can't be an SSL server without an identity";
487 Error("BeginSSL", -1, false);
488 return -1;
489 }
490 rv = SSL_ConfigSecureServer(ssl_fd_, identity->certificate().certificate(),
491 identity->keypair()->privkey(),
492 kt_rsa);
493 if (rv != SECSuccess) {
494 Error("BeginSSL", -1, false);
495 return -1;
496 }
497
498 // Insist on a certificate from the client
499 rv = SSL_OptionSet(ssl_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE);
500 if (rv != SECSuccess) {
501 Error("BeginSSL", -1, false);
502 return -1;
503 }
504
505 rv = SSL_OptionSet(ssl_fd_, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
506 if (rv != SECSuccess) {
507 Error("BeginSSL", -1, false);
508 return -1;
509 }
510 }
511
512 // Set the version range.
513 SSLVersionRange vrange;
514 vrange.min = (ssl_mode_ == SSL_MODE_DTLS) ?
515 SSL_LIBRARY_VERSION_TLS_1_1 :
516 SSL_LIBRARY_VERSION_TLS_1_0;
517 vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
518
519 rv = SSL_VersionRangeSet(ssl_fd_, &vrange);
520 if (rv != SECSuccess) {
521 Error("BeginSSL", -1, false);
522 return -1;
523 }
524
525 // SRTP
526#ifdef HAVE_DTLS_SRTP
527 if (!srtp_ciphers_.empty()) {
528 rv = SSL_SetSRTPCiphers(ssl_fd_, &srtp_ciphers_[0], srtp_ciphers_.size());
529 if (rv != SECSuccess) {
530 Error("BeginSSL", -1, false);
531 return -1;
532 }
533 }
534#endif
535
536 // Certificate validation
537 rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this);
538 if (rv != SECSuccess) {
539 Error("BeginSSL", -1, false);
540 return -1;
541 }
542
543 // Now start the handshake
544 rv = SSL_ResetHandshake(ssl_fd_, role_ == SSL_SERVER ? PR_TRUE : PR_FALSE);
545 if (rv != SECSuccess) {
546 Error("BeginSSL", -1, false);
547 return -1;
548 }
549
550 return ContinueSSL();
551}
552
553int NSSStreamAdapter::ContinueSSL() {
554 LOG(LS_INFO) << "ContinueSSL";
555 ASSERT(state_ == SSL_CONNECTING);
556
557 // Clear the DTLS timer
558 Thread::Current()->Clear(this, MSG_DTLS_TIMEOUT);
559
560 SECStatus rv = SSL_ForceHandshake(ssl_fd_);
561
562 if (rv == SECSuccess) {
563 LOG(LS_INFO) << "Handshake complete";
564
565 ASSERT(cert_ok_);
566 if (!cert_ok_) {
567 Error("ContinueSSL", -1, true);
568 return -1;
569 }
570
571 state_ = SSL_CONNECTED;
572 StreamAdapterInterface::OnEvent(stream(), SE_OPEN|SE_READ|SE_WRITE, 0);
573 return 0;
574 }
575
576 PRInt32 err = PR_GetError();
577 switch (err) {
578 case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
579 if (ssl_mode_ != SSL_MODE_DTLS) {
580 Error("ContinueSSL", -1, true);
581 return -1;
582 } else {
583 LOG(LS_INFO) << "Malformed DTLS message. Ignoring.";
584 // Fall through
585 }
586 case PR_WOULD_BLOCK_ERROR:
587 LOG(LS_INFO) << "Would have blocked";
588 if (ssl_mode_ == SSL_MODE_DTLS) {
589 PRIntervalTime timeout;
590
591 SECStatus rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
592 if (rv == SECSuccess) {
593 LOG(LS_INFO) << "Timeout is " << timeout << " ms";
594 Thread::Current()->PostDelayed(PR_IntervalToMilliseconds(timeout),
595 this, MSG_DTLS_TIMEOUT, 0);
596 }
597 }
598
599 return 0;
600 default:
601 LOG(LS_INFO) << "Error " << err;
602 break;
603 }
604
605 Error("ContinueSSL", -1, true);
606 return -1;
607}
608
609void NSSStreamAdapter::Cleanup() {
610 if (state_ != SSL_ERROR) {
611 state_ = SSL_CLOSED;
612 }
613
614 if (ssl_fd_) {
615 PR_Close(ssl_fd_);
616 ssl_fd_ = NULL;
617 }
618
619 identity_.reset();
620 peer_certificate_.reset();
621
622 Thread::Current()->Clear(this, MSG_DTLS_TIMEOUT);
623}
624
625StreamResult NSSStreamAdapter::Read(void* data, size_t data_len,
626 size_t* read, int* error) {
627 // SSL_CONNECTED sanity check.
628 switch (state_) {
629 case SSL_NONE:
630 case SSL_WAIT:
631 case SSL_CONNECTING:
632 return SR_BLOCK;
633
634 case SSL_CONNECTED:
635 break;
636
637 case SSL_CLOSED:
638 return SR_EOS;
639
640 case SSL_ERROR:
641 default:
642 if (error)
643 *error = ssl_error_code_;
644 return SR_ERROR;
645 }
646
647 PRInt32 rv = PR_Read(ssl_fd_, data, data_len);
648
649 if (rv == 0) {
650 return SR_EOS;
651 }
652
653 // Error
654 if (rv < 0) {
655 PRInt32 err = PR_GetError();
656
657 switch (err) {
658 case PR_WOULD_BLOCK_ERROR:
659 return SR_BLOCK;
660 default:
661 Error("Read", -1, false);
662 *error = err; // libjingle semantics are that this is impl-specific
663 return SR_ERROR;
664 }
665 }
666
667 // Success
668 *read = rv;
669
670 return SR_SUCCESS;
671}
672
673StreamResult NSSStreamAdapter::Write(const void* data, size_t data_len,
674 size_t* written, int* error) {
675 // SSL_CONNECTED sanity check.
676 switch (state_) {
677 case SSL_NONE:
678 case SSL_WAIT:
679 case SSL_CONNECTING:
680 return SR_BLOCK;
681
682 case SSL_CONNECTED:
683 break;
684
685 case SSL_ERROR:
686 case SSL_CLOSED:
687 default:
688 if (error)
689 *error = ssl_error_code_;
690 return SR_ERROR;
691 }
692
693 PRInt32 rv = PR_Write(ssl_fd_, data, data_len);
694
695 // Error
696 if (rv < 0) {
697 PRInt32 err = PR_GetError();
698
699 switch (err) {
700 case PR_WOULD_BLOCK_ERROR:
701 return SR_BLOCK;
702 default:
703 Error("Write", -1, false);
704 *error = err; // libjingle semantics are that this is impl-specific
705 return SR_ERROR;
706 }
707 }
708
709 // Success
710 *written = rv;
711
712 return SR_SUCCESS;
713}
714
715void NSSStreamAdapter::OnEvent(StreamInterface* stream, int events,
716 int err) {
717 int events_to_signal = 0;
718 int signal_error = 0;
719 ASSERT(stream == this->stream());
720 if ((events & SE_OPEN)) {
721 LOG(LS_INFO) << "NSSStreamAdapter::OnEvent SE_OPEN";
722 if (state_ != SSL_WAIT) {
723 ASSERT(state_ == SSL_NONE);
724 events_to_signal |= SE_OPEN;
725 } else {
726 state_ = SSL_CONNECTING;
727 if (int err = BeginSSL()) {
728 Error("BeginSSL", err, true);
729 return;
730 }
731 }
732 }
733 if ((events & (SE_READ|SE_WRITE))) {
734 LOG(LS_INFO) << "NSSStreamAdapter::OnEvent"
735 << ((events & SE_READ) ? " SE_READ" : "")
736 << ((events & SE_WRITE) ? " SE_WRITE" : "");
737 if (state_ == SSL_NONE) {
738 events_to_signal |= events & (SE_READ|SE_WRITE);
739 } else if (state_ == SSL_CONNECTING) {
740 if (int err = ContinueSSL()) {
741 Error("ContinueSSL", err, true);
742 return;
743 }
744 } else if (state_ == SSL_CONNECTED) {
745 if (events & SE_WRITE) {
746 LOG(LS_INFO) << " -- onStreamWriteable";
747 events_to_signal |= SE_WRITE;
748 }
749 if (events & SE_READ) {
750 LOG(LS_INFO) << " -- onStreamReadable";
751 events_to_signal |= SE_READ;
752 }
753 }
754 }
755 if ((events & SE_CLOSE)) {
756 LOG(LS_INFO) << "NSSStreamAdapter::OnEvent(SE_CLOSE, " << err << ")";
757 Cleanup();
758 events_to_signal |= SE_CLOSE;
759 // SE_CLOSE is the only event that uses the final parameter to OnEvent().
760 ASSERT(signal_error == 0);
761 signal_error = err;
762 }
763 if (events_to_signal)
764 StreamAdapterInterface::OnEvent(stream, events_to_signal, signal_error);
765}
766
767void NSSStreamAdapter::OnMessage(Message* msg) {
768 // Process our own messages and then pass others to the superclass
769 if (MSG_DTLS_TIMEOUT == msg->message_id) {
770 LOG(LS_INFO) << "DTLS timeout expired";
771 ContinueSSL();
772 } else {
773 StreamInterface::OnMessage(msg);
774 }
775}
776
777// Certificate verification callback. Called to check any certificate
778SECStatus NSSStreamAdapter::AuthCertificateHook(void *arg,
779 PRFileDesc *fd,
780 PRBool checksig,
781 PRBool isServer) {
782 LOG(LS_INFO) << "NSSStreamAdapter::AuthCertificateHook";
783 NSSCertificate peer_cert(SSL_PeerCertificate(fd));
784 bool ok = false;
785
786 // TODO(ekr@rtfm.com): Should we be enforcing self-signed like
787 // the OpenSSL version?
788 NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
789
790 if (stream->peer_certificate_.get()) {
791 LOG(LS_INFO) << "Checking against specified certificate";
792
793 // The peer certificate was specified
794 if (reinterpret_cast<NSSCertificate *>(stream->peer_certificate_.get())->
795 Equals(&peer_cert)) {
796 LOG(LS_INFO) << "Accepted peer certificate";
797 ok = true;
798 }
799 } else if (!stream->peer_certificate_digest_algorithm_.empty()) {
800 LOG(LS_INFO) << "Checking against specified digest";
801 // The peer certificate digest was specified
802 unsigned char digest[64]; // Maximum size
803 std::size_t digest_length;
804
805 if (!peer_cert.ComputeDigest(
806 stream->peer_certificate_digest_algorithm_,
807 digest, sizeof(digest), &digest_length)) {
808 LOG(LS_ERROR) << "Digest computation failed";
809 } else {
810 Buffer computed_digest(digest, digest_length);
811 if (computed_digest == stream->peer_certificate_digest_value_) {
812 LOG(LS_INFO) << "Accepted peer certificate";
813 ok = true;
814 }
815 }
816 } else {
817 // Other modes, but we haven't implemented yet
818 // TODO(ekr@rtfm.com): Implement real certificate validation
819 UNIMPLEMENTED;
820 }
821
822 if (ok) {
823 stream->cert_ok_ = true;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000824
825 // Record the peer's certificate chain.
826 CERTCertList* cert_list = SSL_PeerCertificateChain(fd);
827 ASSERT(cert_list != NULL);
828
829 stream->peer_certificate_.reset(new NSSCertificate(cert_list));
830 CERT_DestroyCertList(cert_list);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 return SECSuccess;
832 }
833
834 if (!ok && stream->ignore_bad_cert()) {
835 LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
836 stream->cert_ok_ = true;
837 return SECSuccess;
838 }
839
840 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
841 return SECFailure;
842}
843
844
845SECStatus NSSStreamAdapter::GetClientAuthDataHook(void *arg, PRFileDesc *fd,
846 CERTDistNames *caNames,
847 CERTCertificate **pRetCert,
848 SECKEYPrivateKey **pRetKey) {
849 LOG(LS_INFO) << "Client cert requested";
850 NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
851
852 if (!stream->identity_.get()) {
853 LOG(LS_ERROR) << "No identity available";
854 return SECFailure;
855 }
856
857 NSSIdentity *identity = static_cast<NSSIdentity *>(stream->identity_.get());
858 // Destroyed internally by NSS
859 *pRetCert = CERT_DupCertificate(identity->certificate().certificate());
860 *pRetKey = SECKEY_CopyPrivateKey(identity->keypair()->privkey());
861
862 return SECSuccess;
863}
864
865// RFC 5705 Key Exporter
866bool NSSStreamAdapter::ExportKeyingMaterial(const std::string& label,
867 const uint8* context,
868 size_t context_len,
869 bool use_context,
870 uint8* result,
871 size_t result_len) {
872 SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_,
873 label.c_str(), label.size(),
874 use_context,
875 context, context_len,
876 result, result_len);
877
878 return rv == SECSuccess;
879}
880
881bool NSSStreamAdapter::SetDtlsSrtpCiphers(
882 const std::vector<std::string>& ciphers) {
883#ifdef HAVE_DTLS_SRTP
884 std::vector<PRUint16> internal_ciphers;
885 if (state_ != SSL_NONE)
886 return false;
887
888 for (std::vector<std::string>::const_iterator cipher = ciphers.begin();
889 cipher != ciphers.end(); ++cipher) {
890 bool found = false;
891 for (const SrtpCipherMapEntry *entry = kSrtpCipherMap; entry->cipher_id;
892 ++entry) {
893 if (*cipher == entry->external_name) {
894 found = true;
895 internal_ciphers.push_back(entry->cipher_id);
896 break;
897 }
898 }
899
900 if (!found) {
901 LOG(LS_ERROR) << "Could not find cipher: " << *cipher;
902 return false;
903 }
904 }
905
906 if (internal_ciphers.empty())
907 return false;
908
909 srtp_ciphers_ = internal_ciphers;
910
911 return true;
912#else
913 return false;
914#endif
915}
916
917bool NSSStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) {
918#ifdef HAVE_DTLS_SRTP
919 ASSERT(state_ == SSL_CONNECTED);
920 if (state_ != SSL_CONNECTED)
921 return false;
922
923 PRUint16 selected_cipher;
924
925 SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, &selected_cipher);
926 if (rv == SECFailure)
927 return false;
928
929 for (const SrtpCipherMapEntry *entry = kSrtpCipherMap;
930 entry->cipher_id; ++entry) {
931 if (selected_cipher == entry->cipher_id) {
932 *cipher = entry->external_name;
933 return true;
934 }
935 }
936
937 ASSERT(false); // This should never happen
938#endif
939 return false;
940}
941
942
943bool NSSContext::initialized;
944NSSContext *NSSContext::global_nss_context;
945
946// Static initialization and shutdown
947NSSContext *NSSContext::Instance() {
948 if (!global_nss_context) {
949 NSSContext *new_ctx = new NSSContext();
950
951 if (!(new_ctx->slot_ = PK11_GetInternalSlot())) {
952 delete new_ctx;
953 goto fail;
954 }
955
956 global_nss_context = new_ctx;
957 }
958
959 fail:
960 return global_nss_context;
961}
962
963
964
965bool NSSContext::InitializeSSL(VerificationCallback callback) {
966 ASSERT(!callback);
967
968 if (!initialized) {
969 SECStatus rv;
970
971 rv = NSS_NoDB_Init(NULL);
972 if (rv != SECSuccess) {
973 LOG(LS_ERROR) << "Couldn't initialize NSS error=" <<
974 PORT_GetError();
975 return false;
976 }
977
978 NSS_SetDomesticPolicy();
979
980 initialized = true;
981 }
982
983 return true;
984}
985
986bool NSSContext::InitializeSSLThread() {
987 // Not needed
988 return true;
989}
990
991bool NSSContext::CleanupSSL() {
992 // Not needed
993 return true;
994}
995
996bool NSSStreamAdapter::HaveDtls() {
997 return true;
998}
999
1000bool NSSStreamAdapter::HaveDtlsSrtp() {
1001#ifdef HAVE_DTLS_SRTP
1002 return true;
1003#else
1004 return false;
1005#endif
1006}
1007
1008bool NSSStreamAdapter::HaveExporter() {
1009 return true;
1010}
1011
1012} // namespace talk_base
1013
1014#endif // HAVE_NSS_SSL_H