Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1694)

Side by Side Diff: webrtc/base/nssstreamadapter.cc

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

Powered by Google App Engine
This is Rietveld 408576698