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