1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Original author: ekr@rtfm.com 8 9 #ifndef transportlayerdtls_h__ 10 #define transportlayerdtls_h__ 11 12 #include <queue> 13 #include <set> 14 15 #ifdef XP_MACOSX 16 // ensure that Apple Security kit enum goes before "sslproto.h" 17 # include <CoreFoundation/CFAvailability.h> 18 # include <Security/CipherSuite.h> 19 #endif 20 21 #include "sigslot.h" 22 23 #include "mozilla/RefPtr.h" 24 #include "mozilla/UniquePtr.h" 25 #include "mozilla/TimeStamp.h" 26 #include "nsCOMPtr.h" 27 #include "nsITimer.h" 28 #include "ScopedNSSTypes.h" 29 #include "m_cpp_utils.h" 30 #include "dtlsidentity.h" 31 #include "transportlayer.h" 32 #include "ssl.h" 33 #include "sslproto.h" 34 35 namespace mozilla { 36 37 // RFC 5764 (we don't support the NULL cipher) 38 static const uint16_t kDtlsSrtpAes128CmHmacSha1_80 = 0x0001; 39 static const uint16_t kDtlsSrtpAes128CmHmacSha1_32 = 0x0002; 40 // RFC 7714 41 static const uint16_t kDtlsSrtpAeadAes128Gcm = 0x0007; 42 static const uint16_t kDtlsSrtpAeadAes256Gcm = 0x0008; 43 44 struct Packet; 45 46 class TransportLayerNSPRAdapter { 47 public: TransportLayerNSPRAdapter(TransportLayer * output)48 explicit TransportLayerNSPRAdapter(TransportLayer* output) 49 : output_(output), input_(), enabled_(true) {} 50 51 void PacketReceived(MediaPacket& packet); 52 int32_t Recv(void* buf, int32_t buflen); 53 int32_t Write(const void* buf, int32_t length); SetEnabled(bool enabled)54 void SetEnabled(bool enabled) { enabled_ = enabled; } 55 56 private: 57 DISALLOW_COPY_ASSIGN(TransportLayerNSPRAdapter); 58 59 TransportLayer* output_; 60 std::queue<MediaPacket*> input_; 61 bool enabled_; 62 }; 63 64 class TransportLayerDtls final : public TransportLayer { 65 public: 66 TransportLayerDtls() = default; 67 68 virtual ~TransportLayerDtls(); 69 70 enum Role { CLIENT, SERVER }; 71 enum Verification { VERIFY_UNSET, VERIFY_ALLOW_ALL, VERIFY_DIGEST }; 72 73 // DTLS-specific operations SetRole(Role role)74 void SetRole(Role role) { role_ = role; } role()75 Role role() { return role_; } 76 77 enum class Version : uint16_t { 78 DTLS_1_0 = SSL_LIBRARY_VERSION_DTLS_1_0, 79 DTLS_1_2 = SSL_LIBRARY_VERSION_DTLS_1_2, 80 DTLS_1_3 = SSL_LIBRARY_VERSION_DTLS_1_3 81 }; 82 void SetMinMaxVersion(Version min_version, Version max_version); 83 SetIdentity(const RefPtr<DtlsIdentity> & identity)84 void SetIdentity(const RefPtr<DtlsIdentity>& identity) { 85 identity_ = identity; 86 } 87 nsresult SetAlpn(const std::set<std::string>& allowedAlpn, 88 const std::string& alpnDefault); GetNegotiatedAlpn()89 const std::string& GetNegotiatedAlpn() const { return alpn_; } 90 91 nsresult SetVerificationAllowAll(); 92 93 nsresult SetVerificationDigest(const DtlsDigest& digest); 94 95 nsresult GetCipherSuite(uint16_t* cipherSuite) const; 96 97 nsresult SetSrtpCiphers(const std::vector<uint16_t>& ciphers); 98 nsresult GetSrtpCipher(uint16_t* cipher) const; 99 static std::vector<uint16_t> GetDefaultSrtpCiphers(); 100 101 nsresult ExportKeyingMaterial(const std::string& label, bool use_context, 102 const std::string& context, unsigned char* out, 103 unsigned int outlen); 104 105 // Transport layer overrides. 106 nsresult InitInternal() override; 107 void WasInserted() override; 108 TransportResult SendPacket(MediaPacket& packet) override; 109 110 // Signals 111 void StateChange(TransportLayer* layer, State state); 112 void PacketReceived(TransportLayer* layer, MediaPacket& packet); 113 114 // For testing use only. Returns the fd. internal_fd()115 PRFileDesc* internal_fd() { 116 CheckThread(); 117 return ssl_fd_.get(); 118 } 119 120 TRANSPORT_LAYER_ID("dtls") 121 122 protected: 123 void SetState(State state, const char* file, unsigned line) override; 124 125 private: 126 DISALLOW_COPY_ASSIGN(TransportLayerDtls); 127 128 bool Setup(); 129 bool SetupCipherSuites(UniquePRFileDesc& ssl_fd); 130 bool SetupAlpn(UniquePRFileDesc& ssl_fd) const; 131 void GetDecryptedPackets(); 132 void Handshake(); 133 134 bool CheckAlpn(); 135 136 static SECStatus GetClientAuthDataHook(void* arg, PRFileDesc* fd, 137 CERTDistNames* caNames, 138 CERTCertificate** pRetCert, 139 SECKEYPrivateKey** pRetKey); 140 static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, 141 PRBool checksig, PRBool isServer); 142 SECStatus AuthCertificateHook(PRFileDesc* fd, PRBool checksig, 143 PRBool isServer); 144 145 static void TimerCallback(nsITimer* timer, void* arg); 146 147 SECStatus CheckDigest(const DtlsDigest& digest, 148 UniqueCERTCertificate& cert) const; 149 150 void RecordHandshakeCompletionTelemetry(TransportLayer::State endState); 151 void RecordTlsTelemetry(); 152 153 static PRBool WriteSrtpXtn(PRFileDesc* fd, SSLHandshakeType message, 154 uint8_t* data, unsigned int* len, 155 unsigned int max_len, void* arg); 156 157 static SECStatus HandleSrtpXtn(PRFileDesc* fd, SSLHandshakeType message, 158 const uint8_t* data, unsigned int len, 159 SSLAlertDescription* alert, void* arg); 160 161 RefPtr<DtlsIdentity> identity_; 162 // What ALPN identifiers are permitted. 163 std::set<std::string> alpn_allowed_; 164 // What ALPN identifier is used if ALPN is not supported. 165 // The empty string indicates that ALPN is required. 166 std::string alpn_default_; 167 // What ALPN string was negotiated. 168 std::string alpn_; 169 std::vector<uint16_t> enabled_srtp_ciphers_; 170 uint16_t srtp_cipher_ = 0; 171 172 Role role_ = CLIENT; 173 Verification verification_mode_ = VERIFY_UNSET; 174 std::vector<DtlsDigest> digests_; 175 176 Version minVersion_ = Version::DTLS_1_0; 177 Version maxVersion_ = Version::DTLS_1_2; 178 179 // Must delete nspr_io_adapter after ssl_fd_ b/c ssl_fd_ causes an alert 180 // (ssl_fd_ contains an un-owning pointer to nspr_io_adapter_) 181 UniquePtr<TransportLayerNSPRAdapter> nspr_io_adapter_ = nullptr; 182 UniquePRFileDesc ssl_fd_ = nullptr; 183 184 nsCOMPtr<nsITimer> timer_ = nullptr; 185 bool auth_hook_called_ = false; 186 bool cert_ok_ = false; 187 }; 188 189 } // namespace mozilla 190 #endif 191