1/*
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;
824
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);
831    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
1015