blob: acddb672b4b6654cdfc65088b37929606b46cbc4 [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));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784 NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
wu@webrtc.orgf6d6ed02014-01-03 22:08:47 +0000785 stream->cert_ok_ = false;
786
787 // Read the peer's certificate chain.
788 CERTCertList* cert_list = SSL_PeerCertificateChain(fd);
789 ASSERT(cert_list != NULL);
790
791 // If the peer provided multiple certificates, check that they form a valid
792 // chain as defined by RFC 5246 Section 7.4.2: "Each following certificate
793 // MUST directly certify the one preceding it.". This check does NOT
794 // verify other requirements, such as whether the chain reaches a trusted
795 // root, self-signed certificates have valid signatures, certificates are not
796 // expired, etc.
797 // Even if the chain is valid, the leaf certificate must still match a
798 // provided certificate or digest.
799 if (!NSSCertificate::IsValidChain(cert_list)) {
800 CERT_DestroyCertList(cert_list);
801 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
802 return SECFailure;
803 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804
805 if (stream->peer_certificate_.get()) {
806 LOG(LS_INFO) << "Checking against specified certificate";
807
808 // The peer certificate was specified
809 if (reinterpret_cast<NSSCertificate *>(stream->peer_certificate_.get())->
810 Equals(&peer_cert)) {
811 LOG(LS_INFO) << "Accepted peer certificate";
wu@webrtc.orgf6d6ed02014-01-03 22:08:47 +0000812 stream->cert_ok_ = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 }
814 } else if (!stream->peer_certificate_digest_algorithm_.empty()) {
815 LOG(LS_INFO) << "Checking against specified digest";
816 // The peer certificate digest was specified
817 unsigned char digest[64]; // Maximum size
818 std::size_t digest_length;
819
820 if (!peer_cert.ComputeDigest(
821 stream->peer_certificate_digest_algorithm_,
822 digest, sizeof(digest), &digest_length)) {
823 LOG(LS_ERROR) << "Digest computation failed";
824 } else {
825 Buffer computed_digest(digest, digest_length);
826 if (computed_digest == stream->peer_certificate_digest_value_) {
827 LOG(LS_INFO) << "Accepted peer certificate";
wu@webrtc.orgf6d6ed02014-01-03 22:08:47 +0000828 stream->cert_ok_ = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 }
830 }
831 } else {
832 // Other modes, but we haven't implemented yet
833 // TODO(ekr@rtfm.com): Implement real certificate validation
834 UNIMPLEMENTED;
835 }
836
wu@webrtc.orgf6d6ed02014-01-03 22:08:47 +0000837 if (!stream->cert_ok_ && stream->ignore_bad_cert()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
839 stream->cert_ok_ = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 }
841
wu@webrtc.orgf6d6ed02014-01-03 22:08:47 +0000842 if (stream->cert_ok_)
843 stream->peer_certificate_.reset(new NSSCertificate(cert_list));
844
845 CERT_DestroyCertList(cert_list);
846
847 if (stream->cert_ok_)
848 return SECSuccess;
849
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
851 return SECFailure;
852}
853
854
855SECStatus NSSStreamAdapter::GetClientAuthDataHook(void *arg, PRFileDesc *fd,
856 CERTDistNames *caNames,
857 CERTCertificate **pRetCert,
858 SECKEYPrivateKey **pRetKey) {
859 LOG(LS_INFO) << "Client cert requested";
860 NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
861
862 if (!stream->identity_.get()) {
863 LOG(LS_ERROR) << "No identity available";
864 return SECFailure;
865 }
866
867 NSSIdentity *identity = static_cast<NSSIdentity *>(stream->identity_.get());
868 // Destroyed internally by NSS
869 *pRetCert = CERT_DupCertificate(identity->certificate().certificate());
870 *pRetKey = SECKEY_CopyPrivateKey(identity->keypair()->privkey());
871
872 return SECSuccess;
873}
874
875// RFC 5705 Key Exporter
876bool NSSStreamAdapter::ExportKeyingMaterial(const std::string& label,
877 const uint8* context,
878 size_t context_len,
879 bool use_context,
880 uint8* result,
881 size_t result_len) {
882 SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_,
883 label.c_str(), label.size(),
884 use_context,
885 context, context_len,
886 result, result_len);
887
888 return rv == SECSuccess;
889}
890
891bool NSSStreamAdapter::SetDtlsSrtpCiphers(
892 const std::vector<std::string>& ciphers) {
893#ifdef HAVE_DTLS_SRTP
894 std::vector<PRUint16> internal_ciphers;
895 if (state_ != SSL_NONE)
896 return false;
897
898 for (std::vector<std::string>::const_iterator cipher = ciphers.begin();
899 cipher != ciphers.end(); ++cipher) {
900 bool found = false;
901 for (const SrtpCipherMapEntry *entry = kSrtpCipherMap; entry->cipher_id;
902 ++entry) {
903 if (*cipher == entry->external_name) {
904 found = true;
905 internal_ciphers.push_back(entry->cipher_id);
906 break;
907 }
908 }
909
910 if (!found) {
911 LOG(LS_ERROR) << "Could not find cipher: " << *cipher;
912 return false;
913 }
914 }
915
916 if (internal_ciphers.empty())
917 return false;
918
919 srtp_ciphers_ = internal_ciphers;
920
921 return true;
922#else
923 return false;
924#endif
925}
926
927bool NSSStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) {
928#ifdef HAVE_DTLS_SRTP
929 ASSERT(state_ == SSL_CONNECTED);
930 if (state_ != SSL_CONNECTED)
931 return false;
932
933 PRUint16 selected_cipher;
934
935 SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, &selected_cipher);
936 if (rv == SECFailure)
937 return false;
938
939 for (const SrtpCipherMapEntry *entry = kSrtpCipherMap;
940 entry->cipher_id; ++entry) {
941 if (selected_cipher == entry->cipher_id) {
942 *cipher = entry->external_name;
943 return true;
944 }
945 }
946
947 ASSERT(false); // This should never happen
948#endif
949 return false;
950}
951
952
953bool NSSContext::initialized;
954NSSContext *NSSContext::global_nss_context;
955
956// Static initialization and shutdown
957NSSContext *NSSContext::Instance() {
958 if (!global_nss_context) {
959 NSSContext *new_ctx = new NSSContext();
960
961 if (!(new_ctx->slot_ = PK11_GetInternalSlot())) {
962 delete new_ctx;
963 goto fail;
964 }
965
966 global_nss_context = new_ctx;
967 }
968
969 fail:
970 return global_nss_context;
971}
972
973
974
975bool NSSContext::InitializeSSL(VerificationCallback callback) {
976 ASSERT(!callback);
977
978 if (!initialized) {
979 SECStatus rv;
980
981 rv = NSS_NoDB_Init(NULL);
982 if (rv != SECSuccess) {
983 LOG(LS_ERROR) << "Couldn't initialize NSS error=" <<
984 PORT_GetError();
985 return false;
986 }
987
988 NSS_SetDomesticPolicy();
989
990 initialized = true;
991 }
992
993 return true;
994}
995
996bool NSSContext::InitializeSSLThread() {
997 // Not needed
998 return true;
999}
1000
1001bool NSSContext::CleanupSSL() {
1002 // Not needed
1003 return true;
1004}
1005
1006bool NSSStreamAdapter::HaveDtls() {
1007 return true;
1008}
1009
1010bool NSSStreamAdapter::HaveDtlsSrtp() {
1011#ifdef HAVE_DTLS_SRTP
1012 return true;
1013#else
1014 return false;
1015#endif
1016}
1017
1018bool NSSStreamAdapter::HaveExporter() {
1019 return true;
1020}
1021
1022} // namespace talk_base
1023
1024#endif // HAVE_NSS_SSL_H