TLSServerSocket.cpp (13513B)
1 /* vim:set ts=2 sw=2 et cindent: */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "TLSServerSocket.h" 7 8 #include "mozilla/net/DNS.h" 9 #include "mozilla/Components.h" 10 #include "nsComponentManagerUtils.h" 11 #include "nsDependentSubstring.h" 12 #include "nsIServerSocket.h" 13 #include "nsIX509Cert.h" 14 #include "nsIX509CertDB.h" 15 #include "nsNetCID.h" 16 #include "nsProxyRelease.h" 17 #include "nsServiceManagerUtils.h" 18 #include "nsSocketTransport2.h" 19 #include "nsThreadUtils.h" 20 #include "ScopedNSSTypes.h" 21 #include "ssl.h" 22 23 namespace mozilla { 24 namespace net { 25 26 //----------------------------------------------------------------------------- 27 // TLSServerSocket 28 //----------------------------------------------------------------------------- 29 30 NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket, nsServerSocket, nsITLSServerSocket) 31 32 nsresult TLSServerSocket::SetSocketDefaults() { 33 // Set TLS options on the listening socket 34 mFD = SSL_ImportFD(nullptr, mFD); 35 if (NS_WARN_IF(!mFD)) { 36 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); 37 } 38 39 SSL_OptionSet(mFD, SSL_SECURITY, true); 40 SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_CLIENT, false); 41 SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_SERVER, true); 42 SSL_OptionSet(mFD, SSL_NO_CACHE, true); 43 44 // We don't currently notify the server API consumer of renegotiation events 45 // (to revalidate peer certs, etc.), so disable it for now. 46 SSL_OptionSet(mFD, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER); 47 48 SetSessionTickets(true); 49 SetRequestClientCertificate(REQUEST_NEVER); 50 51 return NS_OK; 52 } 53 54 void TLSServerSocket::CreateClientTransport(PRFileDesc* aClientFD, 55 const NetAddr& aClientAddr) { 56 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 57 nsresult rv; 58 59 RefPtr<nsSocketTransport> trans = new nsSocketTransport; 60 if (NS_WARN_IF(!trans)) { 61 mCondition = NS_ERROR_OUT_OF_MEMORY; 62 return; 63 } 64 65 RefPtr<TLSServerConnectionInfo> info = new TLSServerConnectionInfo(); 66 info->mServerSocket = this; 67 info->mTransport = trans; 68 nsCOMPtr<nsIInterfaceRequestor> infoInterfaceRequestor(info); 69 rv = trans->InitWithConnectedSocket(aClientFD, &aClientAddr, 70 infoInterfaceRequestor); 71 if (NS_WARN_IF(NS_FAILED(rv))) { 72 mCondition = rv; 73 return; 74 } 75 76 // Override the default peer certificate validation, so that server consumers 77 // can make their own choice after the handshake completes. 78 SSL_AuthCertificateHook(aClientFD, AuthCertificateHook, nullptr); 79 // Once the TLS handshake has completed, the server consumer is notified and 80 // has access to various TLS state details. 81 // It's safe to pass info here because the socket transport holds it as 82 // |mSecInfo| which keeps it alive for the lifetime of the socket. 83 SSL_HandshakeCallback(aClientFD, TLSServerConnectionInfo::HandshakeCallback, 84 info); 85 86 // Notify the consumer of the new client so it can manage the streams. 87 // Security details aren't known yet. The security observer will be notified 88 // later when they are ready. 89 nsCOMPtr<nsIServerSocket> serverSocket = 90 do_QueryInterface(NS_ISUPPORTS_CAST(nsITLSServerSocket*, this)); 91 mListener->OnSocketAccepted(serverSocket, trans); 92 } 93 94 nsresult TLSServerSocket::OnSocketListen() { 95 if (NS_WARN_IF(!mServerCert)) { 96 return NS_ERROR_NOT_INITIALIZED; 97 } 98 99 UniqueCERTCertificate cert(mServerCert->GetCert()); 100 if (NS_WARN_IF(!cert)) { 101 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); 102 } 103 104 UniqueSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert.get(), nullptr)); 105 if (NS_WARN_IF(!key)) { 106 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); 107 } 108 109 SSLKEAType certKEA = NSS_FindCertKEAType(cert.get()); 110 111 nsresult rv = 112 MapSECStatus(SSL_ConfigSecureServer(mFD, cert.get(), key.get(), certKEA)); 113 if (NS_WARN_IF(NS_FAILED(rv))) { 114 return rv; 115 } 116 117 return NS_OK; 118 } 119 120 // static 121 SECStatus TLSServerSocket::AuthCertificateHook(void* arg, PRFileDesc* fd, 122 PRBool checksig, 123 PRBool isServer) { 124 // Allow any client cert here, server consumer code can decide whether it's 125 // okay after being notified of the new client socket. 126 return SECSuccess; 127 } 128 129 //----------------------------------------------------------------------------- 130 // TLSServerSocket::nsITLSServerSocket 131 //----------------------------------------------------------------------------- 132 133 NS_IMETHODIMP 134 TLSServerSocket::GetServerCert(nsIX509Cert** aCert) { 135 if (NS_WARN_IF(!aCert)) { 136 return NS_ERROR_INVALID_POINTER; 137 } 138 *aCert = do_AddRef(mServerCert).take(); 139 return NS_OK; 140 } 141 142 NS_IMETHODIMP 143 TLSServerSocket::SetServerCert(nsIX509Cert* aCert) { 144 // If AsyncListen was already called (and set mListener), it's too late to set 145 // this. 146 if (NS_WARN_IF(mListener)) { 147 return NS_ERROR_IN_PROGRESS; 148 } 149 mServerCert = aCert; 150 return NS_OK; 151 } 152 153 NS_IMETHODIMP 154 TLSServerSocket::SetSessionTickets(bool aEnabled) { 155 // If AsyncListen was already called (and set mListener), it's too late to set 156 // this. 157 if (NS_WARN_IF(mListener)) { 158 return NS_ERROR_IN_PROGRESS; 159 } 160 SSL_OptionSet(mFD, SSL_ENABLE_SESSION_TICKETS, aEnabled); 161 return NS_OK; 162 } 163 164 NS_IMETHODIMP 165 TLSServerSocket::SetRequestClientCertificate(uint32_t aMode) { 166 // If AsyncListen was already called (and set mListener), it's too late to set 167 // this. 168 if (NS_WARN_IF(mListener)) { 169 return NS_ERROR_IN_PROGRESS; 170 } 171 SSL_OptionSet(mFD, SSL_REQUEST_CERTIFICATE, aMode != REQUEST_NEVER); 172 173 switch (aMode) { 174 case REQUEST_ALWAYS: 175 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NO_ERROR); 176 break; 177 case REQUIRE_FIRST_HANDSHAKE: 178 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_FIRST_HANDSHAKE); 179 break; 180 case REQUIRE_ALWAYS: 181 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS); 182 break; 183 default: 184 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER); 185 } 186 return NS_OK; 187 } 188 189 NS_IMETHODIMP 190 TLSServerSocket::SetVersionRange(uint16_t aMinVersion, uint16_t aMaxVersion) { 191 // If AsyncListen was already called (and set mListener), it's too late to set 192 // this. 193 if (NS_WARN_IF(mListener)) { 194 return NS_ERROR_IN_PROGRESS; 195 } 196 197 SSLVersionRange range = {aMinVersion, aMaxVersion}; 198 if (SSL_VersionRangeSet(mFD, &range) != SECSuccess) { 199 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); 200 } 201 202 return NS_OK; 203 } 204 205 //----------------------------------------------------------------------------- 206 // TLSServerConnectionInfo 207 //----------------------------------------------------------------------------- 208 209 namespace { 210 211 class TLSServerSecurityObserverProxy final 212 : public nsITLSServerSecurityObserver { 213 ~TLSServerSecurityObserverProxy() = default; 214 215 public: 216 explicit TLSServerSecurityObserverProxy( 217 nsITLSServerSecurityObserver* aListener) 218 : mListener(new nsMainThreadPtrHolder<nsITLSServerSecurityObserver>( 219 "TLSServerSecurityObserverProxy::mListener", aListener)) {} 220 221 NS_DECL_THREADSAFE_ISUPPORTS 222 NS_DECL_NSITLSSERVERSECURITYOBSERVER 223 224 class OnHandshakeDoneRunnable : public Runnable { 225 public: 226 OnHandshakeDoneRunnable( 227 const nsMainThreadPtrHandle<nsITLSServerSecurityObserver>& aListener, 228 nsITLSServerSocket* aServer, nsITLSClientStatus* aStatus) 229 : Runnable( 230 "net::TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable"), 231 mListener(aListener), 232 mServer(aServer), 233 mStatus(aStatus) {} 234 235 NS_DECL_NSIRUNNABLE 236 237 private: 238 nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener; 239 nsCOMPtr<nsITLSServerSocket> mServer; 240 nsCOMPtr<nsITLSClientStatus> mStatus; 241 }; 242 243 private: 244 nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener; 245 }; 246 247 NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy, nsITLSServerSecurityObserver) 248 249 NS_IMETHODIMP 250 TLSServerSecurityObserverProxy::OnHandshakeDone(nsITLSServerSocket* aServer, 251 nsITLSClientStatus* aStatus) { 252 RefPtr<OnHandshakeDoneRunnable> r = 253 new OnHandshakeDoneRunnable(mListener, aServer, aStatus); 254 return NS_DispatchToMainThread(r); 255 } 256 257 NS_IMETHODIMP 258 TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable::Run() { 259 mListener->OnHandshakeDone(mServer, mStatus); 260 return NS_OK; 261 } 262 263 } // namespace 264 265 NS_IMPL_ISUPPORTS(TLSServerConnectionInfo, nsITLSServerConnectionInfo, 266 nsITLSClientStatus, nsIInterfaceRequestor) 267 268 TLSServerConnectionInfo::~TLSServerConnectionInfo() { 269 RefPtr<nsITLSServerSecurityObserver> observer; 270 { 271 MutexAutoLock lock(mLock); 272 observer = ToRefPtr(std::move(mSecurityObserver)); 273 } 274 275 if (observer) { 276 NS_ReleaseOnMainThread("TLSServerConnectionInfo::mSecurityObserver", 277 observer.forget()); 278 } 279 } 280 281 NS_IMETHODIMP 282 TLSServerConnectionInfo::SetSecurityObserver( 283 nsITLSServerSecurityObserver* aObserver) { 284 { 285 MutexAutoLock lock(mLock); 286 if (!aObserver) { 287 mSecurityObserver = nullptr; 288 return NS_OK; 289 } 290 291 mSecurityObserver = new TLSServerSecurityObserverProxy(aObserver); 292 // Call `OnHandshakeDone` if TLS handshake is already completed. 293 if (mTlsVersionUsed != TLS_VERSION_UNKNOWN) { 294 nsCOMPtr<nsITLSServerSocket> serverSocket; 295 GetServerSocket(getter_AddRefs(serverSocket)); 296 mSecurityObserver->OnHandshakeDone(serverSocket, this); 297 mSecurityObserver = nullptr; 298 } 299 } 300 return NS_OK; 301 } 302 303 NS_IMETHODIMP 304 TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket** aSocket) { 305 if (NS_WARN_IF(!aSocket)) { 306 return NS_ERROR_INVALID_POINTER; 307 } 308 *aSocket = do_AddRef(mServerSocket).take(); 309 return NS_OK; 310 } 311 312 NS_IMETHODIMP 313 TLSServerConnectionInfo::GetStatus(nsITLSClientStatus** aStatus) { 314 if (NS_WARN_IF(!aStatus)) { 315 return NS_ERROR_INVALID_POINTER; 316 } 317 *aStatus = do_AddRef(this).take(); 318 return NS_OK; 319 } 320 321 NS_IMETHODIMP 322 TLSServerConnectionInfo::GetPeerCert(nsIX509Cert** aCert) { 323 if (NS_WARN_IF(!aCert)) { 324 return NS_ERROR_INVALID_POINTER; 325 } 326 *aCert = do_AddRef(mPeerCert).take(); 327 return NS_OK; 328 } 329 330 NS_IMETHODIMP 331 TLSServerConnectionInfo::GetTlsVersionUsed(int16_t* aTlsVersionUsed) { 332 if (NS_WARN_IF(!aTlsVersionUsed)) { 333 return NS_ERROR_INVALID_POINTER; 334 } 335 *aTlsVersionUsed = mTlsVersionUsed; 336 return NS_OK; 337 } 338 339 NS_IMETHODIMP 340 TLSServerConnectionInfo::GetCipherName(nsACString& aCipherName) { 341 aCipherName.Assign(mCipherName); 342 return NS_OK; 343 } 344 345 NS_IMETHODIMP 346 TLSServerConnectionInfo::GetKeyLength(uint32_t* aKeyLength) { 347 if (NS_WARN_IF(!aKeyLength)) { 348 return NS_ERROR_INVALID_POINTER; 349 } 350 *aKeyLength = mKeyLength; 351 return NS_OK; 352 } 353 354 NS_IMETHODIMP 355 TLSServerConnectionInfo::GetMacLength(uint32_t* aMacLength) { 356 if (NS_WARN_IF(!aMacLength)) { 357 return NS_ERROR_INVALID_POINTER; 358 } 359 *aMacLength = mMacLength; 360 return NS_OK; 361 } 362 363 NS_IMETHODIMP 364 TLSServerConnectionInfo::GetInterface(const nsIID& aIID, void** aResult) { 365 NS_ENSURE_ARG_POINTER(aResult); 366 *aResult = nullptr; 367 368 if (aIID.Equals(NS_GET_IID(nsITLSServerConnectionInfo))) { 369 *aResult = static_cast<nsITLSServerConnectionInfo*>(this); 370 NS_ADDREF_THIS(); 371 return NS_OK; 372 } 373 374 return NS_NOINTERFACE; 375 } 376 377 // static 378 void TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD, void* aArg) { 379 RefPtr<TLSServerConnectionInfo> info = 380 static_cast<TLSServerConnectionInfo*>(aArg); 381 nsISocketTransport* transport = info->mTransport; 382 // No longer needed outside this function, so clear the weak ref 383 info->mTransport = nullptr; 384 nsresult rv = info->HandshakeCallback(aFD); 385 if (NS_WARN_IF(NS_FAILED(rv))) { 386 transport->Close(rv); 387 } 388 } 389 390 nsresult TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD) { 391 nsresult rv; 392 393 UniqueCERTCertificate clientCert(SSL_PeerCertificate(aFD)); 394 if (clientCert) { 395 nsCOMPtr<nsIX509CertDB> certDB; 396 certDB = mozilla::components::NSSCertificateDB::Service(&rv); 397 if (NS_FAILED(rv)) { 398 return rv; 399 } 400 401 nsCOMPtr<nsIX509Cert> clientCertPSM; 402 nsTArray<uint8_t> clientCertBytes; 403 clientCertBytes.AppendElements(clientCert->derCert.data, 404 clientCert->derCert.len); 405 rv = certDB->ConstructX509(clientCertBytes, getter_AddRefs(clientCertPSM)); 406 if (NS_FAILED(rv)) { 407 return rv; 408 } 409 410 mPeerCert = clientCertPSM; 411 } 412 413 SSLChannelInfo channelInfo; 414 rv = MapSECStatus(SSL_GetChannelInfo(aFD, &channelInfo, sizeof(channelInfo))); 415 if (NS_FAILED(rv)) { 416 return rv; 417 } 418 419 SSLCipherSuiteInfo cipherInfo; 420 rv = MapSECStatus(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo, 421 sizeof(cipherInfo))); 422 if (NS_FAILED(rv)) { 423 return rv; 424 } 425 mCipherName.Assign(cipherInfo.cipherSuiteName); 426 mKeyLength = cipherInfo.effectiveKeyBits; 427 mMacLength = cipherInfo.macBits; 428 429 // Notify consumer code that handshake is complete 430 nsCOMPtr<nsITLSServerSecurityObserver> observer; 431 { 432 MutexAutoLock lock(mLock); 433 mTlsVersionUsed = channelInfo.protocolVersion; 434 if (!mSecurityObserver) { 435 return NS_OK; 436 } 437 mSecurityObserver.swap(observer); 438 } 439 nsCOMPtr<nsITLSServerSocket> serverSocket; 440 GetServerSocket(getter_AddRefs(serverSocket)); 441 observer->OnHandshakeDone(serverSocket, this); 442 443 return NS_OK; 444 } 445 446 } // namespace net 447 } // namespace mozilla