author Boris Zbarsky <>
Wed, 20 Mar 2019 18:05:09 +0000
changeset 465263 3ab48ce01773af9a130477e46c50e17f9042ea4b
parent 455945 7ab42c7de77dc87e141c62138850f7583fbac874
child 485678 470fee6b609006fbab428baff5a901bf69d20e65
permissions -rw-r--r--
Bug 1535124 part 3. Add MOZ_CAN_RUN_SCRIPT annotations to geolocation code as needed. r=jdm Differential Revision:

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at */

// Original author:

#ifndef transportlayerdtls_h__
#define transportlayerdtls_h__

#include <queue>
#include <set>

#include "sigslot.h"

#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsIEventTarget.h"
#include "nsITimer.h"
#include "ScopedNSSTypes.h"
#include "m_cpp_utils.h"
#include "dtlsidentity.h"
#include "transportlayer.h"
#include "ssl.h"

namespace mozilla {

// RFC 5764 (we don't support the NULL cipher)
static const uint16_t kDtlsSrtpAes128CmHmacSha1_80 = 0x0001;
static const uint16_t kDtlsSrtpAes128CmHmacSha1_32 = 0x0002;
// RFC 7714
static const uint16_t kDtlsSrtpAeadAes128Gcm = 0x0007;
static const uint16_t kDtlsSrtpAeadAes256Gcm = 0x0008;

struct Packet;

class TransportLayerNSPRAdapter {
  explicit TransportLayerNSPRAdapter(TransportLayer* output)
      : output_(output), input_(), enabled_(true) {}

  void PacketReceived(MediaPacket& packet);
  int32_t Recv(void* buf, int32_t buflen);
  int32_t Write(const void* buf, int32_t length);
  void SetEnabled(bool enabled) { enabled_ = enabled; }


  TransportLayer* output_;
  std::queue<MediaPacket*> input_;
  bool enabled_;

class TransportLayerDtls final : public TransportLayer {
  TransportLayerDtls() = default;

  virtual ~TransportLayerDtls();

  enum Role { CLIENT, SERVER };

  // DTLS-specific operations
  void SetRole(Role role) { role_ = role; }
  Role role() { return role_; }

  void SetIdentity(const RefPtr<DtlsIdentity>& identity) {
    identity_ = identity;
  nsresult SetAlpn(const std::set<std::string>& allowedAlpn,
                   const std::string& alpnDefault);
  const std::string& GetNegotiatedAlpn() const { return alpn_; }

  nsresult SetVerificationAllowAll();

  nsresult SetVerificationDigest(const DtlsDigest& digest);

  nsresult GetCipherSuite(uint16_t* cipherSuite) const;

  nsresult SetSrtpCiphers(const std::vector<uint16_t>& ciphers);
  nsresult GetSrtpCipher(uint16_t* cipher) const;
  static std::vector<uint16_t> GetDefaultSrtpCiphers();

  nsresult ExportKeyingMaterial(const std::string& label, bool use_context,
                                const std::string& context, unsigned char* out,
                                unsigned int outlen);

  // Transport layer overrides.
  nsresult InitInternal() override;
  void WasInserted() override;
  TransportResult SendPacket(MediaPacket& packet) override;

  // Signals
  void StateChange(TransportLayer* layer, State state);
  void PacketReceived(TransportLayer* layer, MediaPacket& packet);

  // For testing use only.  Returns the fd.
  PRFileDesc* internal_fd() {
    return ssl_fd_.get();


  void SetState(State state, const char* file, unsigned line) override;


  bool Setup();
  bool SetupCipherSuites(UniquePRFileDesc& ssl_fd);
  bool SetupAlpn(UniquePRFileDesc& ssl_fd) const;
  void GetDecryptedPackets();
  void Handshake();

  bool CheckAlpn();

  static SECStatus GetClientAuthDataHook(void* arg, PRFileDesc* fd,
                                         CERTDistNames* caNames,
                                         CERTCertificate** pRetCert,
                                         SECKEYPrivateKey** pRetKey);
  static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd,
                                       PRBool checksig, PRBool isServer);
  SECStatus AuthCertificateHook(PRFileDesc* fd, PRBool checksig,
                                PRBool isServer);

  static void TimerCallback(nsITimer* timer, void* arg);

  SECStatus CheckDigest(const DtlsDigest& digest,
                        UniqueCERTCertificate& cert) const;

  void RecordHandshakeCompletionTelemetry(TransportLayer::State endState);
  void RecordTlsTelemetry();

  static PRBool WriteSrtpXtn(PRFileDesc* fd, SSLHandshakeType message,
                             uint8_t* data, unsigned int* len,
                             unsigned int max_len, void* arg);

  static SECStatus HandleSrtpXtn(PRFileDesc* fd, SSLHandshakeType message,
                                 const uint8_t* data, unsigned int len,
                                 SSLAlertDescription* alert, void* arg);

  RefPtr<DtlsIdentity> identity_;
  // What ALPN identifiers are permitted.
  std::set<std::string> alpn_allowed_;
  // What ALPN identifier is used if ALPN is not supported.
  // The empty string indicates that ALPN is required.
  std::string alpn_default_;
  // What ALPN string was negotiated.
  std::string alpn_;
  std::vector<uint16_t> enabled_srtp_ciphers_;
  uint16_t srtp_cipher_ = 0;

  Role role_ = CLIENT;
  Verification verification_mode_ = VERIFY_UNSET;
  std::vector<DtlsDigest> digests_;

  // Must delete nspr_io_adapter after ssl_fd_ b/c ssl_fd_ causes an alert
  // (ssl_fd_ contains an un-owning pointer to nspr_io_adapter_)
  UniquePtr<TransportLayerNSPRAdapter> nspr_io_adapter_ = nullptr;
  UniquePRFileDesc ssl_fd_ = nullptr;

  nsCOMPtr<nsITimer> timer_ = nullptr;
  bool auth_hook_called_ = false;
  bool cert_ok_ = false;
  TimeStamp handshake_started_;

}  // namespace mozilla