147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <vector>
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if HAVE_CONFIG_H
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "config.h"
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // HAVE_CONFIG_H
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if HAVE_NSS_SSL_H
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/nssstreamadapter.h"
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "keyhi.h"
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "nspr.h"
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "nss.h"
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "pk11pub.h"
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "secerr.h"
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef NSS_SSL_RELATIVE_PATH
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "ssl.h"
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "sslerr.h"
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "sslproto.h"
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "net/third_party/nss/ssl/ssl.h"
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "net/third_party/nss/ssl/sslerr.h"
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "net/third_party/nss/ssl/sslproto.h"
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/nssidentity.h"
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/safe_conversions.h"
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/thread.h"
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgPRDescIdentity NSSStreamAdapter::nspr_layer_identity = PR_INVALID_IO_LAYER;
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define UNIMPLEMENTED \
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); \
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_ERROR) \
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  << "Call to unimplemented function "<< __FUNCTION__; ASSERT(false)
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef SRTP_AES128_CM_HMAC_SHA1_80
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define HAVE_DTLS_SRTP
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef HAVE_DTLS_SRTP
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// SRTP cipher suite table
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstruct SrtpCipherMapEntry {
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  const char* external_name;
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PRUint16 cipher_id;
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// This isn't elegant, but it's better than an external reference
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const SrtpCipherMapEntry kSrtpCipherMap[] = {
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  {"AES_CM_128_HMAC_SHA1_80", SRTP_AES128_CM_HMAC_SHA1_80 },
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  {"AES_CM_128_HMAC_SHA1_32", SRTP_AES128_CM_HMAC_SHA1_32 },
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  {NULL, 0}
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Implementation of NSPR methods
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamClose(PRFileDesc *socket) {
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(!socket->lower);
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  socket->dtor(socket);
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_SUCCESS;
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamRead(PRFileDesc *socket, void *buf, PRInt32 length) {
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamInterface *stream = reinterpret_cast<StreamInterface *>(socket->secret);
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t read;
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int error;
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamResult result = stream->Read(buf, length, &read, &error);
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result == SR_SUCCESS) {
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return checked_cast<PRInt32>(read);
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result == SR_EOS) {
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return 0;
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result == SR_BLOCK) {
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PR_SetError(PR_UNKNOWN_ERROR, error);
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamWrite(PRFileDesc *socket, const void *buf,
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                           PRInt32 length) {
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamInterface *stream = reinterpret_cast<StreamInterface *>(socket->secret);
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t written;
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int error;
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamResult result = stream->Write(buf, length, &written, &error);
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result == SR_SUCCESS) {
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return checked_cast<PRInt32>(written);
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (result == SR_BLOCK) {
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) <<
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        "NSSStreamAdapter: write to underlying transport would block";
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_ERROR) << "Write error";
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PR_SetError(PR_UNKNOWN_ERROR, error);
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamAvailable(PRFileDesc *socket) {
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgPRInt64 StreamAvailable64(PRFileDesc *socket) {
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamSync(PRFileDesc *socket) {
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PROffset32 StreamSeek(PRFileDesc *socket, PROffset32 offset,
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                             PRSeekWhence how) {
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PROffset64 StreamSeek64(PRFileDesc *socket, PROffset64 offset,
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                               PRSeekWhence how) {
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamFileInfo(PRFileDesc *socket, PRFileInfo *info) {
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamFileInfo64(PRFileDesc *socket, PRFileInfo64 *info) {
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamWritev(PRFileDesc *socket, const PRIOVec *iov,
15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                     PRInt32 iov_size, PRIntervalTime timeout) {
16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamConnect(PRFileDesc *socket, const PRNetAddr *addr,
16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              PRIntervalTime timeout) {
16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRFileDesc *StreamAccept(PRFileDesc *sd, PRNetAddr *addr,
17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                PRIntervalTime timeout) {
17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return NULL;
17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamBind(PRFileDesc *socket, const PRNetAddr *addr) {
17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamListen(PRFileDesc *socket, PRIntn depth) {
18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamShutdown(PRFileDesc *socket, PRIntn how) {
18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Note: this is always nonblocking and ignores the timeout.
19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// TODO(ekr@rtfm.com): In future verify that the socket is
19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// actually in non-blocking mode.
19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// This function does not support peek.
19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamRecv(PRFileDesc *socket, void *buf, PRInt32 amount,
19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   PRIntn flags, PRIntervalTime to) {
19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(flags == 0);
19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (flags != 0) {
20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return StreamRead(socket, buf, amount);
20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Note: this is always nonblocking and assumes a zero timeout.
20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// This function does not support peek.
20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamSend(PRFileDesc *socket, const void *buf,
21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                          PRInt32 amount, PRIntn flags,
21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                          PRIntervalTime to) {
21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(flags == 0);
21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return StreamWrite(socket, buf, amount);
21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamRecvfrom(PRFileDesc *socket, void *buf,
21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              PRInt32 amount, PRIntn flags,
21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              PRNetAddr *addr, PRIntervalTime to) {
22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamSendto(PRFileDesc *socket, const void *buf,
22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                            PRInt32 amount, PRIntn flags,
22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                            const PRNetAddr *addr, PRIntervalTime to) {
22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt16 StreamPoll(PRFileDesc *socket, PRInt16 in_flags,
23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                          PRInt16 *out_flags) {
23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                PRNetAddr **raddr,
23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                void *buf, PRInt32 amount, PRIntervalTime t) {
24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamTransmitFile(PRFileDesc *sd, PRFileDesc *socket,
24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                  const void *headers, PRInt32 hlen,
24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                  PRTransmitFileFlags flags, PRIntervalTime t) {
24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamGetPeerName(PRFileDesc *socket, PRNetAddr *addr) {
25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // TODO(ekr@rtfm.com): Modify to return unique names for each channel
25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // somehow, as opposed to always the same static address. The current
25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // implementation messes up the session cache, which is why it's off
25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // elsewhere
25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  addr->inet.family = PR_AF_INET;
25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  addr->inet.port = 0;
25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  addr->inet.ip = 0;
25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_SUCCESS;
26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamGetSockName(PRFileDesc *socket, PRNetAddr *addr) {
26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamGetSockOption(PRFileDesc *socket, PRSocketOptionData *opt) {
26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (opt->option) {
27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case PR_SockOpt_Nonblocking:
27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      opt->value.non_blocking = PR_TRUE;
27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return PR_SUCCESS;
27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    default:
27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      UNIMPLEMENTED;
27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Imitate setting socket options. These are mostly noops.
28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamSetSockOption(PRFileDesc *socket,
28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                    const PRSocketOptionData *opt) {
28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (opt->option) {
28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case PR_SockOpt_Nonblocking:
28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return PR_SUCCESS;
28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case PR_SockOpt_NoDelay:
28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return PR_SUCCESS;
28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    default:
29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      UNIMPLEMENTED;
29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRInt32 StreamSendfile(PRFileDesc *out, PRSendFileData *in,
29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              PRTransmitFileFlags flags, PRIntervalTime to) {
29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRStatus StreamConnectContinue(PRFileDesc *socket, PRInt16 flags) {
30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return PR_FAILURE;
30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic PRIntn StreamReserved(PRFileDesc *socket) {
30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UNIMPLEMENTED;
31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const struct PRIOMethods nss_methods = {
31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PR_DESC_LAYERED,
31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamClose,
31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamRead,
31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamWrite,
31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamAvailable,
31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamAvailable64,
32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamSync,
32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamSeek,
32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamSeek64,
32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamFileInfo,
32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamFileInfo64,
32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamWritev,
32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamConnect,
32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamAccept,
32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamBind,
32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamListen,
33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamShutdown,
33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamRecv,
33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamSend,
33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamRecvfrom,
33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamSendto,
33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamPoll,
33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamAcceptRead,
33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamTransmitFile,
33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamGetSockName,
33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamGetPeerName,
34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamReserved,
34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamReserved,
34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamGetSockOption,
34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamSetSockOption,
34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamSendfile,
34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamConnectContinue,
34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamReserved,
34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamReserved,
34847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamReserved,
34947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  StreamReserved
35047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
35147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
35247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgNSSStreamAdapter::NSSStreamAdapter(StreamInterface *stream)
35347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : SSLStreamAdapterHelper(stream),
35447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ssl_fd_(NULL),
35547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      cert_ok_(false) {
35647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
35747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
35847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSStreamAdapter::Init() {
35947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (nspr_layer_identity == PR_INVALID_IO_LAYER) {
36047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    nspr_layer_identity = PR_GetUniqueIdentity("nssstreamadapter");
36147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
36247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PRFileDesc *pr_fd = PR_CreateIOLayerStub(nspr_layer_identity, &nss_methods);
36347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!pr_fd)
36447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
36547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  pr_fd->secret = reinterpret_cast<PRFilePrivate *>(stream());
36647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
36747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PRFileDesc *ssl_fd;
36847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (ssl_mode_ == SSL_MODE_DTLS) {
36947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ssl_fd = DTLS_ImportFD(NULL, pr_fd);
37047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
37147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ssl_fd = SSL_ImportFD(NULL, pr_fd);
37247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
37347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(ssl_fd != NULL);  // This should never happen
37447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!ssl_fd) {
37547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PR_Close(pr_fd);
37647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
37747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
37847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
37947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SECStatus rv;
38047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Turn on security.
38147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_OptionSet(ssl_fd, SSL_SECURITY, PR_TRUE);
38247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
38347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Error enabling security on SSL Socket";
38447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
38547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
38647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
38747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Disable SSLv2.
38847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SSL2, PR_FALSE);
38947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
39047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Error disabling SSL2";
39147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
39247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
39347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Disable caching.
39547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // TODO(ekr@rtfm.com): restore this when I have the caching
39647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // identity set.
39747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_OptionSet(ssl_fd, SSL_NO_CACHE, PR_TRUE);
39847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
39947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Error disabling cache";
40047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
40147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
40247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
40347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Disable session tickets.
40447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
40547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
40647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Error enabling tickets";
40747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
40847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
40947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
41047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Disable renegotiation.
41147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_RENEGOTIATION,
41247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                     SSL_RENEGOTIATE_NEVER);
41347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
41447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Error disabling renegotiation";
41547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
41647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
41747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
41847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Disable false start.
41947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_FALSE_START, PR_FALSE);
42047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
42147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Error disabling false start";
42247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
42347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
42447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
42547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ssl_fd_ = ssl_fd;
42647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
42747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
42847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
42947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
43047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgNSSStreamAdapter::~NSSStreamAdapter() {
43147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (ssl_fd_)
43247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PR_Close(ssl_fd_);
43347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
43447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
43547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
43647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint NSSStreamAdapter::BeginSSL() {
43747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SECStatus rv;
43847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
43947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!Init()) {
44047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("Init", -1, false);
44147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
44247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
44347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
44447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(state_ == SSL_CONNECTING);
44547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // The underlying stream has been opened. If we are in peer-to-peer mode
44647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // then a peer certificate must have been specified by now.
44747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(!ssl_server_name_.empty() ||
44847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org         peer_certificate_.get() != NULL ||
44947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org         !peer_certificate_digest_algorithm_.empty());
45047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_INFO) << "BeginSSL: "
45147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org               << (!ssl_server_name_.empty() ? ssl_server_name_ :
45247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                               "with peer");
45347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
45447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (role_ == SSL_CLIENT) {
45547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "BeginSSL: as client";
45647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
45747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook,
45847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   this);
45947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (rv != SECSuccess) {
46047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("BeginSSL", -1, false);
46147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
46247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
46347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
46447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "BeginSSL: as server";
46547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    NSSIdentity *identity;
46647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
46747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (identity_.get()) {
46847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      identity = static_cast<NSSIdentity *>(identity_.get());
46947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
47047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Can't be an SSL server without an identity";
47147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("BeginSSL", -1, false);
47247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
47347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
47447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    rv = SSL_ConfigSecureServer(ssl_fd_, identity->certificate().certificate(),
47547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                identity->keypair()->privkey(),
47647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                kt_rsa);
47747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (rv != SECSuccess) {
47847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("BeginSSL", -1, false);
47947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
48047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
48147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
48247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Insist on a certificate from the client
48347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    rv = SSL_OptionSet(ssl_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE);
48447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (rv != SECSuccess) {
48547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("BeginSSL", -1, false);
48647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
48747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
48847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4894f81cfbdcc099ef101e726a7b1fa8bfc30a23d49tkchin@webrtc.org    // TODO(juberti): Check for client_auth_enabled()
4904f81cfbdcc099ef101e726a7b1fa8bfc30a23d49tkchin@webrtc.org
49147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    rv = SSL_OptionSet(ssl_fd_, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
49247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (rv != SECSuccess) {
49347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("BeginSSL", -1, false);
49447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
49547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
49647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
49747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
49847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Set the version range.
49947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SSLVersionRange vrange;
50047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  vrange.min =  (ssl_mode_ == SSL_MODE_DTLS) ?
50147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      SSL_LIBRARY_VERSION_TLS_1_1 :
50247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      SSL_LIBRARY_VERSION_TLS_1_0;
50347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
50447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
50547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_VersionRangeSet(ssl_fd_, &vrange);
50647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
50747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("BeginSSL", -1, false);
50847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
50947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
51047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
51147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // SRTP
51247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef HAVE_DTLS_SRTP
51347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!srtp_ciphers_.empty()) {
51447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    rv = SSL_SetSRTPCiphers(
51547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        ssl_fd_, &srtp_ciphers_[0],
51647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        checked_cast<unsigned int>(srtp_ciphers_.size()));
51747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (rv != SECSuccess) {
51847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("BeginSSL", -1, false);
51947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
52047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
52147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
52247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
52347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
52447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Certificate validation
52547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this);
52647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
52747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("BeginSSL", -1, false);
52847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
52947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
53047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
53147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Now start the handshake
53247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  rv = SSL_ResetHandshake(ssl_fd_, role_ == SSL_SERVER ? PR_TRUE : PR_FALSE);
53347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv != SECSuccess) {
53447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("BeginSSL", -1, false);
53547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return -1;
53647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
53747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
53847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return ContinueSSL();
53947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
54047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
54147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint NSSStreamAdapter::ContinueSSL() {
54247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_INFO) << "ContinueSSL";
54347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(state_ == SSL_CONNECTING);
54447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
54547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Clear the DTLS timer
54647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Thread::Current()->Clear(this, MSG_DTLS_TIMEOUT);
54747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
54847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SECStatus rv = SSL_ForceHandshake(ssl_fd_);
54947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
55047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv == SECSuccess) {
55147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "Handshake complete";
55247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
55347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(cert_ok_);
55447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!cert_ok_) {
55547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("ContinueSSL", -1, true);
55647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return -1;
55747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
55847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
55947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = SSL_CONNECTED;
56047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    StreamAdapterInterface::OnEvent(stream(), SE_OPEN|SE_READ|SE_WRITE, 0);
56147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return 0;
56247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
56347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
56447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PRInt32 err = PR_GetError();
56547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (err) {
56647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
56747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (ssl_mode_ != SSL_MODE_DTLS) {
56847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        Error("ContinueSSL", -1, true);
56947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        return -1;
57047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      } else {
57147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_INFO) << "Malformed DTLS message. Ignoring.";
57247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        // Fall through
57347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
57447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case PR_WOULD_BLOCK_ERROR:
57547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_INFO) << "Would have blocked";
57647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (ssl_mode_ == SSL_MODE_DTLS) {
57747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        PRIntervalTime timeout;
57847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
57947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        SECStatus rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
58047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        if (rv == SECSuccess) {
58147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          LOG(LS_INFO) << "Timeout is " << timeout << " ms";
58247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          Thread::Current()->PostDelayed(PR_IntervalToMilliseconds(timeout),
58347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                         this, MSG_DTLS_TIMEOUT, 0);
58447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        }
58547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
58647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
58747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return 0;
58847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    default:
58947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_INFO) << "Error " << err;
59047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
59147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
59247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
59347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Error("ContinueSSL", -1, true);
59447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return -1;
59547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
59647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
59747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid NSSStreamAdapter::Cleanup() {
59847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ != SSL_ERROR) {
59947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = SSL_CLOSED;
60047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
60147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
60247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (ssl_fd_) {
60347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PR_Close(ssl_fd_);
60447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ssl_fd_ = NULL;
60547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
60647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
60747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  identity_.reset();
60847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  peer_certificate_.reset();
60947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
61047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Thread::Current()->Clear(this, MSG_DTLS_TIMEOUT);
61147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
61247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
61347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgStreamResult NSSStreamAdapter::Read(void* data, size_t data_len,
61447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                    size_t* read, int* error) {
61547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // SSL_CONNECTED sanity check.
61647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (state_) {
61747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_NONE:
61847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_WAIT:
61947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_CONNECTING:
62047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return SR_BLOCK;
62147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
62247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_CONNECTED:
62347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
62447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
62547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_CLOSED:
62647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return SR_EOS;
62747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
62847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_ERROR:
62947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    default:
63047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (error)
63147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        *error = ssl_error_code_;
63247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return SR_ERROR;
63347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
63447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
63547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PRInt32 rv = PR_Read(ssl_fd_, data, checked_cast<PRInt32>(data_len));
63647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
63747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv == 0) {
63847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SR_EOS;
63947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
64047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
64147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Error
64247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv < 0) {
64347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PRInt32 err = PR_GetError();
64447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
64547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    switch (err) {
64647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      case PR_WOULD_BLOCK_ERROR:
64747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        return SR_BLOCK;
64847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      default:
64947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        Error("Read", -1, false);
65047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        *error = err;  // libjingle semantics are that this is impl-specific
65147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        return SR_ERROR;
65247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
65347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
65447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
65547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Success
65647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  *read = rv;
65747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
65847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return SR_SUCCESS;
65947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
66047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
66147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgStreamResult NSSStreamAdapter::Write(const void* data, size_t data_len,
66247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                     size_t* written, int* error) {
66347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // SSL_CONNECTED sanity check.
66447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (state_) {
66547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_NONE:
66647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_WAIT:
66747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_CONNECTING:
66847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return SR_BLOCK;
66947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
67047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_CONNECTED:
67147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
67247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
67347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_ERROR:
67447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    case SSL_CLOSED:
67547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    default:
67647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (error)
67747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        *error = ssl_error_code_;
67847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return SR_ERROR;
67947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
68047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
68147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PRInt32 rv = PR_Write(ssl_fd_, data, checked_cast<PRInt32>(data_len));
68247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
68347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Error
68447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv < 0) {
68547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PRInt32 err = PR_GetError();
68647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
68747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    switch (err) {
68847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      case PR_WOULD_BLOCK_ERROR:
68947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        return SR_BLOCK;
69047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      default:
69147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        Error("Write", -1, false);
69247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        *error = err;  // libjingle semantics are that this is impl-specific
69347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        return SR_ERROR;
69447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
69547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
69647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
69747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Success
69847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  *written = rv;
69947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
70047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return SR_SUCCESS;
70147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
70247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
70347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid NSSStreamAdapter::OnEvent(StreamInterface* stream, int events,
70447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                               int err) {
70547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int events_to_signal = 0;
70647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int signal_error = 0;
70747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(stream == this->stream());
70847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if ((events & SE_OPEN)) {
70947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "NSSStreamAdapter::OnEvent SE_OPEN";
71047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (state_ != SSL_WAIT) {
71147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ASSERT(state_ == SSL_NONE);
71247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      events_to_signal |= SE_OPEN;
71347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
71447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      state_ = SSL_CONNECTING;
71547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (int err = BeginSSL()) {
71647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        Error("BeginSSL", err, true);
71747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        return;
71847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
71947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
72047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
72147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if ((events & (SE_READ|SE_WRITE))) {
72247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "NSSStreamAdapter::OnEvent"
72347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                 << ((events & SE_READ) ? " SE_READ" : "")
72447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                 << ((events & SE_WRITE) ? " SE_WRITE" : "");
72547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (state_ == SSL_NONE) {
72647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      events_to_signal |= events & (SE_READ|SE_WRITE);
72747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (state_ == SSL_CONNECTING) {
72847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (int err = ContinueSSL()) {
72947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        Error("ContinueSSL", err, true);
73047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        return;
73147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
73247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (state_ == SSL_CONNECTED) {
73347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (events & SE_WRITE) {
73447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_INFO) << " -- onStreamWriteable";
73547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        events_to_signal |= SE_WRITE;
73647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
73747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (events & SE_READ) {
73847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_INFO) << " -- onStreamReadable";
73947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        events_to_signal |= SE_READ;
74047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
74147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
74247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
74347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if ((events & SE_CLOSE)) {
74447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "NSSStreamAdapter::OnEvent(SE_CLOSE, " << err << ")";
74547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Cleanup();
74647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    events_to_signal |= SE_CLOSE;
74747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // SE_CLOSE is the only event that uses the final parameter to OnEvent().
74847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(signal_error == 0);
74947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    signal_error = err;
75047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
75147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (events_to_signal)
75247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    StreamAdapterInterface::OnEvent(stream, events_to_signal, signal_error);
75347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
75447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
75547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid NSSStreamAdapter::OnMessage(Message* msg) {
75647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Process our own messages and then pass others to the superclass
75747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (MSG_DTLS_TIMEOUT == msg->message_id) {
75847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "DTLS timeout expired";
75947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ContinueSSL();
76047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
76147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    StreamInterface::OnMessage(msg);
76247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
76347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
76447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
76547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Certificate verification callback. Called to check any certificate
76647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSECStatus NSSStreamAdapter::AuthCertificateHook(void *arg,
76747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                PRFileDesc *fd,
76847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                PRBool checksig,
76947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                PRBool isServer) {
77047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_INFO) << "NSSStreamAdapter::AuthCertificateHook";
77147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // SSL_PeerCertificate returns a pointer that is owned by the caller, and
77247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // the NSSCertificate constructor copies its argument, so |raw_peer_cert|
77347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // must be destroyed in this function.
77447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CERTCertificate* raw_peer_cert = SSL_PeerCertificate(fd);
77547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  NSSCertificate peer_cert(raw_peer_cert);
77647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CERT_DestroyCertificate(raw_peer_cert);
77747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
77847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
77947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  stream->cert_ok_ = false;
78047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
78147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Read the peer's certificate chain.
78247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CERTCertList* cert_list = SSL_PeerCertificateChain(fd);
78347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(cert_list != NULL);
78447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
78547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // If the peer provided multiple certificates, check that they form a valid
78647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // chain as defined by RFC 5246 Section 7.4.2: "Each following certificate
78747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // MUST directly certify the one preceding it.".  This check does NOT
78847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // verify other requirements, such as whether the chain reaches a trusted
78947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // root, self-signed certificates have valid signatures, certificates are not
79047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // expired, etc.
79147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Even if the chain is valid, the leaf certificate must still match a
79247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // provided certificate or digest.
79347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!NSSCertificate::IsValidChain(cert_list)) {
79447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CERT_DestroyCertList(cert_list);
79547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
79647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SECFailure;
79747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
79847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
79947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (stream->peer_certificate_.get()) {
80047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "Checking against specified certificate";
80147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
80247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // The peer certificate was specified
80347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (reinterpret_cast<NSSCertificate *>(stream->peer_certificate_.get())->
80447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        Equals(&peer_cert)) {
80547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_INFO) << "Accepted peer certificate";
80647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      stream->cert_ok_ = true;
80747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
80847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else if (!stream->peer_certificate_digest_algorithm_.empty()) {
80947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "Checking against specified digest";
81047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // The peer certificate digest was specified
81147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    unsigned char digest[64];  // Maximum size
81247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    size_t digest_length;
81347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
81447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!peer_cert.ComputeDigest(
81547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            stream->peer_certificate_digest_algorithm_,
81647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            digest, sizeof(digest), &digest_length)) {
81747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Digest computation failed";
81847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
81947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Buffer computed_digest(digest, digest_length);
82047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (computed_digest == stream->peer_certificate_digest_value_) {
82147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_INFO) << "Accepted peer certificate";
82247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        stream->cert_ok_ = true;
82347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
82447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
82547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
82647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Other modes, but we haven't implemented yet
82747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // TODO(ekr@rtfm.com): Implement real certificate validation
82847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    UNIMPLEMENTED;
82947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
83047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
83147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!stream->cert_ok_ && stream->ignore_bad_cert()) {
83247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
83347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    stream->cert_ok_ = true;
83447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
83547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
83647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (stream->cert_ok_)
83747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    stream->peer_certificate_.reset(new NSSCertificate(cert_list));
83847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
83947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CERT_DestroyCertList(cert_list);
84047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
84147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (stream->cert_ok_)
84247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SECSuccess;
84347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
84447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
84547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return SECFailure;
84647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
84747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
84847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
84947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSECStatus NSSStreamAdapter::GetClientAuthDataHook(void *arg, PRFileDesc *fd,
85047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                  CERTDistNames *caNames,
85147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                  CERTCertificate **pRetCert,
85247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                  SECKEYPrivateKey **pRetKey) {
85347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_INFO) << "Client cert requested";
85447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
85547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
85647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!stream->identity_.get()) {
85747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "No identity available";
85847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SECFailure;
85947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
86047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
86147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  NSSIdentity *identity = static_cast<NSSIdentity *>(stream->identity_.get());
86247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Destroyed internally by NSS
86347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  *pRetCert = CERT_DupCertificate(identity->certificate().certificate());
86447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  *pRetKey = SECKEY_CopyPrivateKey(identity->keypair()->privkey());
86547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
86647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return SECSuccess;
86747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
86847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
86947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// RFC 5705 Key Exporter
87047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSStreamAdapter::ExportKeyingMaterial(const std::string& label,
87147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            const uint8* context,
87247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            size_t context_len,
87347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            bool use_context,
87447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            uint8* result,
87547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                            size_t result_len) {
87647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SECStatus rv = SSL_ExportKeyingMaterial(
87747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ssl_fd_,
87847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      label.c_str(),
87947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      checked_cast<unsigned int>(label.size()),
88047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      use_context,
88147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      context,
88247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      checked_cast<unsigned int>(context_len),
88347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      result,
88447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      checked_cast<unsigned int>(result_len));
88547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
88647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return rv == SECSuccess;
88747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
88847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
88947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSStreamAdapter::SetDtlsSrtpCiphers(
89047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    const std::vector<std::string>& ciphers) {
89147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef HAVE_DTLS_SRTP
89247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::vector<PRUint16> internal_ciphers;
89347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ != SSL_NONE)
89447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
89547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
89647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (std::vector<std::string>::const_iterator cipher = ciphers.begin();
89747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org       cipher != ciphers.end(); ++cipher) {
89847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    bool found = false;
89947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    for (const SrtpCipherMapEntry *entry = kSrtpCipherMap; entry->cipher_id;
90047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org         ++entry) {
90147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (*cipher == entry->external_name) {
90247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        found = true;
90347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        internal_ciphers.push_back(entry->cipher_id);
90447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        break;
90547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
90647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
90747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
90847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!found) {
90947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Could not find cipher: " << *cipher;
91047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
91147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
91247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
91347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
91447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (internal_ciphers.empty())
91547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
91647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
91747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  srtp_ciphers_ = internal_ciphers;
91847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
91947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
92047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
92147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return false;
92247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
92347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
92447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
92547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) {
92647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef HAVE_DTLS_SRTP
92747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(state_ == SSL_CONNECTED);
92847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ != SSL_CONNECTED)
92947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
93047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
93147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PRUint16 selected_cipher;
93247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
93347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, &selected_cipher);
93447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (rv == SECFailure)
93547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
93647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
93747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (const SrtpCipherMapEntry *entry = kSrtpCipherMap;
93847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org       entry->cipher_id; ++entry) {
93947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (selected_cipher == entry->cipher_id) {
94047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      *cipher = entry->external_name;
94147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return true;
94247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
94347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
94447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
94547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(false);  // This should never happen
94647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
94747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return false;
94847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
94947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
95047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
95147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSContext::initialized;
95247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgNSSContext *NSSContext::global_nss_context;
95347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
95447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Static initialization and shutdown
95547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgNSSContext *NSSContext::Instance() {
95647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!global_nss_context) {
9579fbd3ec906560447cebb21681c7e79e37c2eed83tommi@webrtc.org    scoped_ptr<NSSContext> new_ctx(new NSSContext());
9589fbd3ec906560447cebb21681c7e79e37c2eed83tommi@webrtc.org    new_ctx->slot_ = PK11_GetInternalSlot();
9599fbd3ec906560447cebb21681c7e79e37c2eed83tommi@webrtc.org    if (new_ctx->slot_)
9609fbd3ec906560447cebb21681c7e79e37c2eed83tommi@webrtc.org      global_nss_context = new_ctx.release();
96147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
96247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return global_nss_context;
96347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
96447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
96547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
96647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
96747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSContext::InitializeSSL(VerificationCallback callback) {
96847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(!callback);
96947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
97047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!initialized) {
97147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SECStatus rv;
97247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
97347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    rv = NSS_NoDB_Init(NULL);
97447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (rv != SECSuccess) {
97547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Couldn't initialize NSS error=" <<
97647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          PORT_GetError();
97747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
97847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
97947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
98047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    NSS_SetDomesticPolicy();
98147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
98247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    initialized = true;
98347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
98447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
98547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
98647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
98747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
98847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSContext::InitializeSSLThread() {
98947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Not needed
99047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
99147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
99247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
99347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSContext::CleanupSSL() {
99447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Not needed
99547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
99647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
99747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
99847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSStreamAdapter::HaveDtls() {
99947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
100047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
100147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
100247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSStreamAdapter::HaveDtlsSrtp() {
100347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef HAVE_DTLS_SRTP
100447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
100547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
100647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return false;
100747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
100847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
100947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
101047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool NSSStreamAdapter::HaveExporter() {
101147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
101247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
101347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
101447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
101547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
101647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // HAVE_NSS_SSL_H
1017