Home | History | Annotate | Download | only in base
      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 (at) 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 (at) 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 (at) 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 (at) 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 (at) rtfm.com): Implement real certificate validation
    819     UNIMPLEMENTED;
    820   }
    821 
    822   if (ok) {
    823     stream->cert_ok_ = true;
    824     return SECSuccess;
    825   }
    826 
    827   if (!ok && stream->ignore_bad_cert()) {
    828     LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
    829     stream->cert_ok_ = true;
    830     return SECSuccess;
    831   }
    832 
    833   PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
    834   return SECFailure;
    835 }
    836 
    837 
    838 SECStatus NSSStreamAdapter::GetClientAuthDataHook(void *arg, PRFileDesc *fd,
    839                                                   CERTDistNames *caNames,
    840                                                   CERTCertificate **pRetCert,
    841                                                   SECKEYPrivateKey **pRetKey) {
    842   LOG(LS_INFO) << "Client cert requested";
    843   NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
    844 
    845   if (!stream->identity_.get()) {
    846     LOG(LS_ERROR) << "No identity available";
    847     return SECFailure;
    848   }
    849 
    850   NSSIdentity *identity = static_cast<NSSIdentity *>(stream->identity_.get());
    851   // Destroyed internally by NSS
    852   *pRetCert = CERT_DupCertificate(identity->certificate().certificate());
    853   *pRetKey = SECKEY_CopyPrivateKey(identity->keypair()->privkey());
    854 
    855   return SECSuccess;
    856 }
    857 
    858 // RFC 5705 Key Exporter
    859 bool NSSStreamAdapter::ExportKeyingMaterial(const std::string& label,
    860                                             const uint8* context,
    861                                             size_t context_len,
    862                                             bool use_context,
    863                                             uint8* result,
    864                                             size_t result_len) {
    865   SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_,
    866                                           label.c_str(), label.size(),
    867                                           use_context,
    868                                           context, context_len,
    869                                           result, result_len);
    870 
    871   return rv == SECSuccess;
    872 }
    873 
    874 bool NSSStreamAdapter::SetDtlsSrtpCiphers(
    875     const std::vector<std::string>& ciphers) {
    876 #ifdef HAVE_DTLS_SRTP
    877   std::vector<PRUint16> internal_ciphers;
    878   if (state_ != SSL_NONE)
    879     return false;
    880 
    881   for (std::vector<std::string>::const_iterator cipher = ciphers.begin();
    882        cipher != ciphers.end(); ++cipher) {
    883     bool found = false;
    884     for (const SrtpCipherMapEntry *entry = kSrtpCipherMap; entry->cipher_id;
    885          ++entry) {
    886       if (*cipher == entry->external_name) {
    887         found = true;
    888         internal_ciphers.push_back(entry->cipher_id);
    889         break;
    890       }
    891     }
    892 
    893     if (!found) {
    894       LOG(LS_ERROR) << "Could not find cipher: " << *cipher;
    895       return false;
    896     }
    897   }
    898 
    899   if (internal_ciphers.empty())
    900     return false;
    901 
    902   srtp_ciphers_ = internal_ciphers;
    903 
    904   return true;
    905 #else
    906   return false;
    907 #endif
    908 }
    909 
    910 bool NSSStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) {
    911 #ifdef HAVE_DTLS_SRTP
    912   ASSERT(state_ == SSL_CONNECTED);
    913   if (state_ != SSL_CONNECTED)
    914     return false;
    915 
    916   PRUint16 selected_cipher;
    917 
    918   SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, &selected_cipher);
    919   if (rv == SECFailure)
    920     return false;
    921 
    922   for (const SrtpCipherMapEntry *entry = kSrtpCipherMap;
    923        entry->cipher_id; ++entry) {
    924     if (selected_cipher == entry->cipher_id) {
    925       *cipher = entry->external_name;
    926       return true;
    927     }
    928   }
    929 
    930   ASSERT(false);  // This should never happen
    931 #endif
    932   return false;
    933 }
    934 
    935 
    936 bool NSSContext::initialized;
    937 NSSContext *NSSContext::global_nss_context;
    938 
    939 // Static initialization and shutdown
    940 NSSContext *NSSContext::Instance() {
    941   if (!global_nss_context) {
    942     NSSContext *new_ctx = new NSSContext();
    943 
    944     if (!(new_ctx->slot_ = PK11_GetInternalSlot())) {
    945       delete new_ctx;
    946       goto fail;
    947     }
    948 
    949     global_nss_context = new_ctx;
    950   }
    951 
    952  fail:
    953   return global_nss_context;
    954 }
    955 
    956 
    957 
    958 bool NSSContext::InitializeSSL(VerificationCallback callback) {
    959   ASSERT(!callback);
    960 
    961   if (!initialized) {
    962     SECStatus rv;
    963 
    964     rv = NSS_NoDB_Init(NULL);
    965     if (rv != SECSuccess) {
    966       LOG(LS_ERROR) << "Couldn't initialize NSS error=" <<
    967           PORT_GetError();
    968       return false;
    969     }
    970 
    971     NSS_SetDomesticPolicy();
    972 
    973     initialized = true;
    974   }
    975 
    976   return true;
    977 }
    978 
    979 bool NSSContext::InitializeSSLThread() {
    980   // Not needed
    981   return true;
    982 }
    983 
    984 bool NSSContext::CleanupSSL() {
    985   // Not needed
    986   return true;
    987 }
    988 
    989 bool NSSStreamAdapter::HaveDtls() {
    990   return true;
    991 }
    992 
    993 bool NSSStreamAdapter::HaveDtlsSrtp() {
    994 #ifdef HAVE_DTLS_SRTP
    995   return true;
    996 #else
    997   return false;
    998 #endif
    999 }
   1000 
   1001 bool NSSStreamAdapter::HaveExporter() {
   1002   return true;
   1003 }
   1004 
   1005 }  // namespace talk_base
   1006 
   1007 #endif  // HAVE_NSS_SSL_H
   1008