- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / base / nssstreamadapter.cc
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
58 namespace talk_base {
59
60 PRDescIdentity 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
73 struct 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
79 static 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
88 static PRStatus StreamClose(PRFileDesc *socket) {
89   // Noop
90   return PR_SUCCESS;
91 }
92
93 static 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
115 static 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
137 static PRInt32 StreamAvailable(PRFileDesc *socket) {
138   UNIMPLEMENTED;
139   return -1;
140 }
141
142 PRInt64 StreamAvailable64(PRFileDesc *socket) {
143   UNIMPLEMENTED;
144   return -1;
145 }
146
147 static PRStatus StreamSync(PRFileDesc *socket) {
148   UNIMPLEMENTED;
149   return PR_FAILURE;
150 }
151
152 static PROffset32 StreamSeek(PRFileDesc *socket, PROffset32 offset,
153                              PRSeekWhence how) {
154   UNIMPLEMENTED;
155   return -1;
156 }
157
158 static PROffset64 StreamSeek64(PRFileDesc *socket, PROffset64 offset,
159                                PRSeekWhence how) {
160   UNIMPLEMENTED;
161   return -1;
162 }
163
164 static PRStatus StreamFileInfo(PRFileDesc *socket, PRFileInfo *info) {
165   UNIMPLEMENTED;
166   return PR_FAILURE;
167 }
168
169 static PRStatus StreamFileInfo64(PRFileDesc *socket, PRFileInfo64 *info) {
170   UNIMPLEMENTED;
171   return PR_FAILURE;
172 }
173
174 static PRInt32 StreamWritev(PRFileDesc *socket, const PRIOVec *iov,
175                      PRInt32 iov_size, PRIntervalTime timeout) {
176   UNIMPLEMENTED;
177   return -1;
178 }
179
180 static PRStatus StreamConnect(PRFileDesc *socket, const PRNetAddr *addr,
181                               PRIntervalTime timeout) {
182   UNIMPLEMENTED;
183   return PR_FAILURE;
184 }
185
186 static PRFileDesc *StreamAccept(PRFileDesc *sd, PRNetAddr *addr,
187                                 PRIntervalTime timeout) {
188   UNIMPLEMENTED;
189   return NULL;
190 }
191
192 static PRStatus StreamBind(PRFileDesc *socket, const PRNetAddr *addr) {
193   UNIMPLEMENTED;
194   return PR_FAILURE;
195 }
196
197 static PRStatus StreamListen(PRFileDesc *socket, PRIntn depth) {
198   UNIMPLEMENTED;
199   return PR_FAILURE;
200 }
201
202 static 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.
211 static 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.
225 static 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
233 static PRInt32 StreamRecvfrom(PRFileDesc *socket, void *buf,
234                               PRInt32 amount, PRIntn flags,
235                               PRNetAddr *addr, PRIntervalTime to) {
236   UNIMPLEMENTED;
237   return -1;
238 }
239
240 static 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
247 static PRInt16 StreamPoll(PRFileDesc *socket, PRInt16 in_flags,
248                           PRInt16 *out_flags) {
249   UNIMPLEMENTED;
250   return -1;
251 }
252
253 static PRInt32 StreamAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
254                                 PRNetAddr **raddr,
255                                 void *buf, PRInt32 amount, PRIntervalTime t) {
256   UNIMPLEMENTED;
257   return -1;
258 }
259
260 static PRInt32 StreamTransmitFile(PRFileDesc *sd, PRFileDesc *socket,
261                                   const void *headers, PRInt32 hlen,
262                                   PRTransmitFileFlags flags, PRIntervalTime t) {
263   UNIMPLEMENTED;
264   return -1;
265 }
266
267 static 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
279 static PRStatus StreamGetSockName(PRFileDesc *socket, PRNetAddr *addr) {
280   UNIMPLEMENTED;
281   return PR_FAILURE;
282 }
283
284 static 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.
298 static 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
313 static PRInt32 StreamSendfile(PRFileDesc *out, PRSendFileData *in,
314                               PRTransmitFileFlags flags, PRIntervalTime to) {
315   UNIMPLEMENTED;
316   return -1;
317 }
318
319 static PRStatus StreamConnectContinue(PRFileDesc *socket, PRInt16 flags) {
320   UNIMPLEMENTED;
321   return PR_FAILURE;
322 }
323
324 static PRIntn StreamReserved(PRFileDesc *socket) {
325   UNIMPLEMENTED;
326   return -1;
327 }
328
329 static 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
368 NSSStreamAdapter::NSSStreamAdapter(StreamInterface *stream)
369     : SSLStreamAdapterHelper(stream),
370       ssl_fd_(NULL),
371       cert_ok_(false) {
372 }
373
374 bool 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
446 NSSStreamAdapter::~NSSStreamAdapter() {
447   if (ssl_fd_)
448     PR_Close(ssl_fd_);
449 };
450
451
452 int 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
553 int 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
609 void 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
625 StreamResult 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
673 StreamResult 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
715 void 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
767 void 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
778 SECStatus 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
845 SECStatus 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
866 bool 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
881 bool 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
917 bool 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
943 bool NSSContext::initialized;
944 NSSContext *NSSContext::global_nss_context;
945
946 // Static initialization and shutdown
947 NSSContext *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
965 bool 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
986 bool NSSContext::InitializeSSLThread() {
987   // Not needed
988   return true;
989 }
990
991 bool NSSContext::CleanupSSL() {
992   // Not needed
993   return true;
994 }
995
996 bool NSSStreamAdapter::HaveDtls() {
997   return true;
998 }
999
1000 bool NSSStreamAdapter::HaveDtlsSrtp() {
1001 #ifdef HAVE_DTLS_SRTP
1002   return true;
1003 #else
1004   return false;
1005 #endif
1006 }
1007
1008 bool NSSStreamAdapter::HaveExporter() {
1009   return true;
1010 }
1011
1012 }  // namespace talk_base
1013
1014 #endif  // HAVE_NSS_SSL_H