Bug 1311383 - Use unique pointers for DTLS transport and related, r=cykesiopka draft
authorMartin Thomson <martin.thomson@gmail.com>
Thu, 20 Oct 2016 11:29:58 +1100
changeset 428624 c46530bfc42b407caa5e7890266dfae8dcc9a3b9
parent 428476 215f9686117673a2c914ed207bc7da9bb8d741ad
child 534791 1474f31ea3d57b71d173f241f2fb4118ad63d431
push id33372
push userbmo:martin.thomson@gmail.com
push dateMon, 24 Oct 2016 11:53:24 +0000
reviewerscykesiopka
bugs1311383
milestone52.0a1
Bug 1311383 - Use unique pointers for DTLS transport and related, r=cykesiopka MozReview-Commit-ID: 79wKQtJjBNP
dom/media/webrtc/RTCCertificate.cpp
dom/media/webrtc/RTCCertificate.h
media/mtransport/dtlsidentity.cpp
media/mtransport/dtlsidentity.h
media/mtransport/transportlayerdtls.cpp
media/mtransport/transportlayerdtls.h
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
security/manager/ssl/ScopedNSSTypes.h
--- a/dom/media/webrtc/RTCCertificate.cpp
+++ b/dom/media/webrtc/RTCCertificate.cpp
@@ -77,17 +77,17 @@ public:
     if (ok && expval > 0) {
       mExpires = std::min(expval, EXPIRATION_MAX);
     }
   }
 
 private:
   PRTime mExpires;
   SSLKEAType mAuthType;
-  ScopedCERTCertificate mCertificate;
+  UniqueCERTCertificate mCertificate;
   SECOidTag mSignatureAlg;
 
   static CERTName* GenerateRandomName(PK11SlotInfo* aSlot)
   {
     uint8_t randomName[RTCCertificateCommonNameLength];
     SECStatus rv = PK11_GenerateRandomOnSlot(aSlot, randomName,
                                              sizeof(randomName));
     if (rv != SECSuccess) {
@@ -167,17 +167,17 @@ private:
       return NS_ERROR_DOM_UNKNOWN_ERR;
     }
 
     // Set version to X509v3.
     *(mCertificate->version.data) = SEC_CERTIFICATE_VERSION_3;
     mCertificate->version.len = 1;
 
     SECItem innerDER = { siBuffer, nullptr, 0 };
-    if (!SEC_ASN1EncodeItem(arena, &innerDER, mCertificate,
+    if (!SEC_ASN1EncodeItem(arena, &innerDER, mCertificate.get(),
                             SEC_ASN1_GET(CERT_CertificateTemplate))) {
       return NS_ERROR_DOM_UNKNOWN_ERR;
     }
 
     SECItem *signedCert = PORT_ArenaZNew(arena, SECItem);
     if (!signedCert) {
       return NS_ERROR_DOM_UNKNOWN_ERR;
     }
@@ -236,17 +236,17 @@ private:
     return NS_OK;
   }
 
   virtual void Resolve() override
   {
     // Make copies of the private key and certificate, otherwise, when this
     // object is deleted, the structures they reference will be deleted too.
     SECKEYPrivateKey* key = mKeyPair->mPrivateKey.get()->GetPrivateKey();
-    CERTCertificate* cert = CERT_DupCertificate(mCertificate);
+    CERTCertificate* cert = CERT_DupCertificate(mCertificate.get());
     RefPtr<RTCCertificate> result =
         new RTCCertificate(mResultPromise->GetParentObject(),
                            key, cert, mAuthType, mExpires);
     mResultPromise->MaybeResolve(result);
   }
 };
 
 already_AddRefed<Promise>
@@ -315,18 +315,18 @@ RTCCertificate::~RTCCertificate()
 // creates before the RTCCertificate reference is released.
 RefPtr<DtlsIdentity>
 RTCCertificate::CreateDtlsIdentity() const
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown() || !mPrivateKey || !mCertificate) {
     return nullptr;
   }
-  SECKEYPrivateKey* key = SECKEY_CopyPrivateKey(mPrivateKey);
-  CERTCertificate* cert = CERT_DupCertificate(mCertificate);
+  SECKEYPrivateKey* key = SECKEY_CopyPrivateKey(mPrivateKey.get());
+  CERTCertificate* cert = CERT_DupCertificate(mCertificate.get());
   RefPtr<DtlsIdentity> id = new DtlsIdentity(key, cert, mAuthType);
   return id;
 }
 
 JSObject*
 RTCCertificate::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return RTCCertificateBinding::Wrap(aCx, this, aGivenProto);
@@ -336,26 +336,26 @@ void
 RTCCertificate::virtualDestroyNSSReference()
 {
   destructorSafeDestroyNSSReference();
 }
 
 void
 RTCCertificate::destructorSafeDestroyNSSReference()
 {
-  mPrivateKey.dispose();
-  mCertificate.dispose();
+  mPrivateKey.reset();
+  mCertificate.reset();
 }
 
 bool
 RTCCertificate::WritePrivateKey(JSStructuredCloneWriter* aWriter,
                                 const nsNSSShutDownPreventionLock& aLockProof) const
 {
   JsonWebKey jwk;
-  nsresult rv = CryptoKey::PrivateKeyToJwk(mPrivateKey, jwk, aLockProof);
+  nsresult rv = CryptoKey::PrivateKeyToJwk(mPrivateKey.get(), jwk, aLockProof);
   if (NS_FAILED(rv)) {
     return false;
   }
   nsString json;
   if (!jwk.ToJSON(json)) {
     return false;
   }
   return WriteString(aWriter, json);
@@ -397,33 +397,33 @@ RTCCertificate::ReadPrivateKey(JSStructu
   nsString json;
   if (!ReadString(aReader, json)) {
     return false;
   }
   JsonWebKey jwk;
   if (!jwk.Init(json)) {
     return false;
   }
-  mPrivateKey = CryptoKey::PrivateKeyFromJwk(jwk, aLockProof);
+  mPrivateKey.reset(CryptoKey::PrivateKeyFromJwk(jwk, aLockProof));
   return !!mPrivateKey;
 }
 
 bool
 RTCCertificate::ReadCertificate(JSStructuredCloneReader* aReader,
                                 const nsNSSShutDownPreventionLock& /*proof*/)
 {
   CryptoBuffer cert;
   if (!ReadBuffer(aReader, cert) || cert.Length() == 0) {
     return false;
   }
 
   SECItem der = { siBuffer, cert.Elements(),
                   static_cast<unsigned int>(cert.Length()) };
-  mCertificate = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
-                                         &der, nullptr, true, true);
+  mCertificate.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+                                             &der, nullptr, true, true));
   return !!mCertificate;
 }
 
 bool
 RTCCertificate::ReadStructuredClone(JSStructuredCloneReader* aReader)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
--- a/dom/media/webrtc/RTCCertificate.h
+++ b/dom/media/webrtc/RTCCertificate.h
@@ -55,17 +55,17 @@ public:
   // NSPR PRTime is in microseconds since the same epoch.
   uint64_t Expires() const
   {
     return mExpires / PR_USEC_PER_MSEC;
   }
 
   // Accessors for use by PeerConnectionImpl.
   RefPtr<DtlsIdentity> CreateDtlsIdentity() const;
-  CERTCertificate* Certificate() const { return mCertificate; }
+  const UniqueCERTCertificate& Certificate() const { return mCertificate; }
 
   // For nsNSSShutDownObject
   virtual void virtualDestroyNSSReference() override;
   void destructorSafeDestroyNSSReference();
 
   // Structured clone methods
   bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
   bool ReadStructuredClone(JSStructuredCloneReader* aReader);
@@ -80,18 +80,18 @@ private:
   bool ReadPrivateKey(JSStructuredCloneReader* aReader,
                       const nsNSSShutDownPreventionLock& aLockProof);
   bool WriteCertificate(JSStructuredCloneWriter* aWriter,
                         const nsNSSShutDownPreventionLock& /*lockproof*/) const;
   bool WritePrivateKey(JSStructuredCloneWriter* aWriter,
                        const nsNSSShutDownPreventionLock& aLockProof) const;
 
   RefPtr<nsIGlobalObject> mGlobal;
-  ScopedSECKEYPrivateKey mPrivateKey;
-  ScopedCERTCertificate mCertificate;
+  UniqueSECKEYPrivateKey mPrivateKey;
+  UniqueCERTCertificate mCertificate;
   SSLKEAType mAuthType;
   PRTime mExpires;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_RTCCertificate_h
--- a/media/mtransport/dtlsidentity.cpp
+++ b/media/mtransport/dtlsidentity.cpp
@@ -13,22 +13,16 @@
 #include "pk11pub.h"
 #include "sechash.h"
 #include "ssl.h"
 
 #include "mozilla/Sprintf.h"
 
 namespace mozilla {
 
-DtlsIdentity::~DtlsIdentity() {
-  if (cert_) {
-    CERT_DestroyCertificate(cert_);
-  }
-}
-
 RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
   if (!slot) {
     return nullptr;
   }
 
   uint8_t random_name[16];
 
@@ -159,23 +153,23 @@ RefPtr<DtlsIdentity> DtlsIdentity::Gener
 }
 
 const std::string DtlsIdentity::DEFAULT_HASH_ALGORITHM = "sha-256";
 
 nsresult DtlsIdentity::ComputeFingerprint(const std::string algorithm,
                                           uint8_t *digest,
                                           size_t size,
                                           size_t *digest_length) const {
-  const CERTCertificate* c = cert();
+  const UniqueCERTCertificate& c = cert();
   MOZ_ASSERT(c);
 
   return ComputeFingerprint(c, algorithm, digest, size, digest_length);
 }
 
-nsresult DtlsIdentity::ComputeFingerprint(const CERTCertificate *cert,
+nsresult DtlsIdentity::ComputeFingerprint(const UniqueCERTCertificate& cert,
                                           const std::string algorithm,
                                           uint8_t *digest,
                                           size_t size,
                                           size_t *digest_length) {
   MOZ_ASSERT(cert);
 
   HASH_HashType ht;
 
--- a/media/mtransport/dtlsidentity.h
+++ b/media/mtransport/dtlsidentity.h
@@ -28,44 +28,43 @@ class DtlsIdentity final {
       : private_key_(privkey), cert_(cert), auth_type_(authType) {}
 
   // This is only for use in tests, or for external linkage.  It makes a (bad)
   // instance of this class.
   static RefPtr<DtlsIdentity> Generate();
 
   // These don't create copies or transfer ownership. If you want these to live
   // on, make a copy.
-  CERTCertificate *cert() const { return cert_; }
+  const UniqueCERTCertificate& cert() const { return cert_; }
   SECKEYPrivateKey *privkey() const { return private_key_; }
   // Note: this uses SSLKEAType because that is what the libssl API requires.
   // This is a giant confusing mess, but libssl indexes certificates based on a
   // key exchange type, not authentication type (as you might have reasonably
   // expected).
   SSLKEAType auth_type() const { return auth_type_; }
 
   nsresult ComputeFingerprint(const std::string algorithm,
                               uint8_t *digest,
                               size_t size,
                               size_t *digest_length) const;
-  static nsresult ComputeFingerprint(const CERTCertificate *cert,
+  static nsresult ComputeFingerprint(const UniqueCERTCertificate& cert,
                                      const std::string algorithm,
                                      uint8_t *digest,
                                      size_t size,
                                      size_t *digest_length);
 
   static const std::string DEFAULT_HASH_ALGORITHM;
   enum {
     HASH_ALGORITHM_MAX_LENGTH = 64
   };
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DtlsIdentity)
 
  private:
-  ~DtlsIdentity();
+  ~DtlsIdentity() {}
   DISALLOW_COPY_ASSIGN(DtlsIdentity);
 
   ScopedSECKEYPrivateKey private_key_;
-  CERTCertificate *cert_;  // TODO: Using a smart pointer here causes link
-                           // errors.
+  UniqueCERTCertificate cert_;
   SSLKEAType auth_type_;
 };
 }  // close namespace
 #endif
--- a/media/mtransport/transportlayerdtls.cpp
+++ b/media/mtransport/transportlayerdtls.cpp
@@ -10,17 +10,19 @@
 
 #include <algorithm>
 #include <queue>
 #include <sstream>
 
 #include "dtlsidentity.h"
 #include "keyhi.h"
 #include "logging.h"
+#include "mozilla/Move.h"
 #include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
 #include "nsCOMPtr.h"
 #include "nsComponentManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIEventTarget.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
 #include "ssl.h"
 #include "sslerr.h"
@@ -484,174 +486,175 @@ bool TransportLayerDtls::Setup() {
               "Can't start DTLS without specifying a verification mode");
     return false;
   }
 
   if (transport_layer_identity == PR_INVALID_IO_LAYER) {
     transport_layer_identity = PR_GetUniqueIdentity("nssstreamadapter");
   }
 
-  ScopedPRFileDesc pr_fd(PR_CreateIOLayerStub(transport_layer_identity,
+  UniquePRFileDesc pr_fd(PR_CreateIOLayerStub(transport_layer_identity,
                                               &TransportLayerMethods));
   MOZ_ASSERT(pr_fd != nullptr);
   if (!pr_fd)
     return false;
   pr_fd->secret = reinterpret_cast<PRFilePrivate *>(nspr_io_adapter_.get());
 
-  ScopedPRFileDesc ssl_fd(DTLS_ImportFD(nullptr, pr_fd));
+  UniquePRFileDesc ssl_fd(DTLS_ImportFD(nullptr, pr_fd.get()));
   MOZ_ASSERT(ssl_fd != nullptr);  // This should never happen
   if (!ssl_fd) {
     return false;
   }
 
-  pr_fd.forget(); // ownership transfered to ssl_fd;
+  Unused << pr_fd.release(); // ownership transfered to ssl_fd;
 
   if (role_ == CLIENT) {
     MOZ_MTLOG(ML_INFO, "Setting up DTLS as client");
-    rv = SSL_GetClientAuthDataHook(ssl_fd, GetClientAuthDataHook,
+    rv = SSL_GetClientAuthDataHook(ssl_fd.get(), GetClientAuthDataHook,
                                    this);
     if (rv != SECSuccess) {
       MOZ_MTLOG(ML_ERROR, "Couldn't set identity");
       return false;
     }
   } else {
     MOZ_MTLOG(ML_INFO, "Setting up DTLS as server");
     // Server side
-    rv = SSL_ConfigSecureServer(ssl_fd, identity_->cert(),
+    rv = SSL_ConfigSecureServer(ssl_fd.get(), identity_->cert().get(),
                                 identity_->privkey(),
                                 identity_->auth_type());
     if (rv != SECSuccess) {
       MOZ_MTLOG(ML_ERROR, "Couldn't set identity");
       return false;
     }
 
     // Insist on a certificate from the client
-    rv = SSL_OptionSet(ssl_fd, SSL_REQUEST_CERTIFICATE, PR_TRUE);
+    rv = SSL_OptionSet(ssl_fd.get(), SSL_REQUEST_CERTIFICATE, PR_TRUE);
     if (rv != SECSuccess) {
       MOZ_MTLOG(ML_ERROR, "Couldn't request certificate");
       return false;
     }
 
-    rv = SSL_OptionSet(ssl_fd, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
+    rv = SSL_OptionSet(ssl_fd.get(), SSL_REQUIRE_CERTIFICATE, PR_TRUE);
     if (rv != SECSuccess) {
       MOZ_MTLOG(ML_ERROR, "Couldn't require certificate");
       return false;
     }
   }
 
   // Require TLS 1.1 or 1.2. Perhaps some day in the future we will allow TLS
   // 1.0 for stream modes.
   SSLVersionRange version_range = {
     SSL_LIBRARY_VERSION_TLS_1_1,
     SSL_LIBRARY_VERSION_TLS_1_2
   };
 
-  rv = SSL_VersionRangeSet(ssl_fd, &version_range);
+  rv = SSL_VersionRangeSet(ssl_fd.get(), &version_range);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Can't disable SSLv3");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable session tickets");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_NO_CACHE, PR_TRUE);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_NO_CACHE, PR_TRUE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable session caching");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_DEFLATE, PR_FALSE);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_DEFLATE, PR_FALSE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable deflate");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_RENEGOTIATION,
+                     SSL_RENEGOTIATE_NEVER);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable renegotiation");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_FALSE_START, PR_FALSE);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_FALSE_START, PR_FALSE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable false start");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_NO_LOCKS, PR_TRUE);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_NO_LOCKS, PR_TRUE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable locks");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable ECDHE key reuse");
     return false;
   }
 
   if (!SetupCipherSuites(ssl_fd)) {
     return false;
   }
 
-  rv = SSL_NamedGroupConfig(ssl_fd, NamedGroupPreferences,
+  rv = SSL_NamedGroupConfig(ssl_fd.get(), NamedGroupPreferences,
                             mozilla::ArrayLength(NamedGroupPreferences));
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't set named groups");
     return false;
   }
 
   // Certificate validation
-  rv = SSL_AuthCertificateHook(ssl_fd, AuthCertificateHook,
+  rv = SSL_AuthCertificateHook(ssl_fd.get(), AuthCertificateHook,
                                reinterpret_cast<void *>(this));
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't set certificate validation hook");
     return false;
   }
 
   if (!SetupAlpn(ssl_fd)) {
     return false;
   }
 
   // Now start the handshake
-  rv = SSL_ResetHandshake(ssl_fd, role_ == SERVER ? PR_TRUE : PR_FALSE);
+  rv = SSL_ResetHandshake(ssl_fd.get(), role_ == SERVER ? PR_TRUE : PR_FALSE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't reset handshake");
     return false;
   }
-  ssl_fd_ = ssl_fd.forget();
+  ssl_fd_ = Move(ssl_fd);
 
   // Finally, get ready to receive data
   downward_->SignalStateChange.connect(this, &TransportLayerDtls::StateChange);
   downward_->SignalPacketReceived.connect(this, &TransportLayerDtls::PacketReceived);
 
   if (downward_->state() == TS_OPEN) {
     TL_SET_STATE(TS_CONNECTING);
     Handshake();
   }
 
   return true;
 }
 
-bool TransportLayerDtls::SetupAlpn(PRFileDesc* ssl_fd) const {
+bool TransportLayerDtls::SetupAlpn(UniquePRFileDesc& ssl_fd) const {
   if (alpn_allowed_.empty()) {
     return true;
   }
 
-  SECStatus rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_NPN, PR_FALSE);
+  SECStatus rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_NPN, PR_FALSE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable NPN");
     return false;
   }
 
-  rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_ALPN, PR_TRUE);
+  rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_ALPN, PR_TRUE);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't enable ALPN");
     return false;
   }
 
   unsigned char buf[MAX_ALPN_LENGTH];
   size_t offset = 0;
   for (auto tag = alpn_allowed_.begin();
@@ -659,17 +662,17 @@ bool TransportLayerDtls::SetupAlpn(PRFil
     if ((offset + 1 + tag->length()) >= sizeof(buf)) {
       MOZ_MTLOG(ML_ERROR, "ALPN too long");
       return false;
     }
     buf[offset++] = tag->length();
     memcpy(buf + offset, tag->c_str(), tag->length());
     offset += tag->length();
   }
-  rv = SSL_SetNextProtoNego(ssl_fd, buf, offset);
+  rv = SSL_SetNextProtoNego(ssl_fd.get(), buf, offset);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, "Couldn't set ALPN string");
     return false;
   }
   return true;
 }
 
 // Ciphers we need to enable.  These are on by default in standard firefox
@@ -736,52 +739,52 @@ static const uint32_t DisabledCiphers[] 
   TLS_ECDHE_RSA_WITH_NULL_SHA,
   TLS_ECDH_ECDSA_WITH_NULL_SHA,
   TLS_ECDH_RSA_WITH_NULL_SHA,
   TLS_RSA_WITH_NULL_SHA,
   TLS_RSA_WITH_NULL_SHA256,
   TLS_RSA_WITH_NULL_MD5,
 };
 
-bool TransportLayerDtls::SetupCipherSuites(PRFileDesc* ssl_fd) const {
+bool TransportLayerDtls::SetupCipherSuites(UniquePRFileDesc& ssl_fd) const {
   SECStatus rv;
 
   // Set the SRTP ciphers
   if (!srtp_ciphers_.empty()) {
     // Note: std::vector is guaranteed to contiguous
-    rv = SSL_SetSRTPCiphers(ssl_fd, &srtp_ciphers_[0], srtp_ciphers_.size());
-
+    rv = SSL_SetSRTPCiphers(ssl_fd.get(), &srtp_ciphers_[0],
+                            srtp_ciphers_.size());
     if (rv != SECSuccess) {
       MOZ_MTLOG(ML_ERROR, "Couldn't set SRTP cipher suite");
       return false;
     }
   }
 
   for (const auto& cipher : EnabledCiphers) {
     MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Enabling: " << cipher);
-    rv = SSL_CipherPrefSet(ssl_fd, cipher, PR_TRUE);
+    rv = SSL_CipherPrefSet(ssl_fd.get(), cipher, PR_TRUE);
     if (rv != SECSuccess) {
       MOZ_MTLOG(ML_ERROR, LAYER_INFO <<
                 "Unable to enable suite: " << cipher);
       return false;
     }
   }
 
   for (const auto& cipher : DisabledCiphers) {
     MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Disabling: " << cipher);
 
     PRBool enabled = false;
-    rv = SSL_CipherPrefGet(ssl_fd, cipher, &enabled);
+    rv = SSL_CipherPrefGet(ssl_fd.get(), cipher, &enabled);
     if (rv != SECSuccess) {
       MOZ_MTLOG(ML_NOTICE, LAYER_INFO <<
                 "Unable to check if suite is enabled: " << cipher);
       return false;
     }
     if (enabled) {
-      rv = SSL_CipherPrefSet(ssl_fd, cipher, PR_FALSE);
+      rv = SSL_CipherPrefSet(ssl_fd.get(), cipher, PR_FALSE);
       if (rv != SECSuccess) {
         MOZ_MTLOG(ML_NOTICE, LAYER_INFO <<
                   "Unable to disable suite: " << cipher);
         return false;
       }
     }
   }
 
@@ -793,17 +796,17 @@ nsresult TransportLayerDtls::GetCipherSu
   if (!cipherSuite) {
     MOZ_MTLOG(ML_ERROR, LAYER_INFO << "GetCipherSuite passed a nullptr");
     return NS_ERROR_NULL_POINTER;
   }
   if (state_ != TS_OPEN) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   SSLChannelInfo info;
-  SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &info, sizeof(info));
+  SECStatus rv = SSL_GetChannelInfo(ssl_fd_.get(), &info, sizeof(info));
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "GetCipherSuite can't get channel info");
     return NS_ERROR_FAILURE;
   }
   *cipherSuite = info.cipherSuite;
   return NS_OK;
 }
 
@@ -854,17 +857,17 @@ void TransportLayerDtls::StateChange(Tra
       break;
   }
 }
 
 void TransportLayerDtls::Handshake() {
   // Clear the retransmit timer
   timer_->Cancel();
 
-  SECStatus rv = SSL_ForceHandshake(ssl_fd_);
+  SECStatus rv = SSL_ForceHandshake(ssl_fd_.get());
 
   if (rv == SECSuccess) {
     MOZ_MTLOG(ML_NOTICE,
               LAYER_INFO << "****** SSL handshake completed ******");
     if (!cert_ok_) {
       MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Certificate check never occurred");
       TL_SET_STATE(TS_ERROR);
       return;
@@ -885,17 +888,17 @@ void TransportLayerDtls::Handshake() {
       case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
         MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Malformed DTLS message; ignoring");
         // If this were TLS (and not DTLS), this would be fatal, but
         // here we're required to ignore bad messages, so fall through
         MOZ_FALLTHROUGH;
       case PR_WOULD_BLOCK_ERROR:
         MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "Handshake would have blocked");
         PRIntervalTime timeout;
-        rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
+        rv = DTLS_GetHandshakeTimeout(ssl_fd_.get(), &timeout);
         if (rv == SECSuccess) {
           uint32_t timeout_ms = PR_IntervalToMilliseconds(timeout);
 
           MOZ_MTLOG(ML_DEBUG,
                     LAYER_INFO << "Setting DTLS timeout to " << timeout_ms);
           timer_->SetTarget(target_);
           timer_->InitWithFuncCallback(TimerCallback,
                                        this, timeout_ms,
@@ -918,17 +921,17 @@ void TransportLayerDtls::Handshake() {
 bool TransportLayerDtls::CheckAlpn() {
   if (alpn_allowed_.empty()) {
     return true;
   }
 
   SSLNextProtoState alpnState;
   char chosenAlpn[MAX_ALPN_LENGTH];
   unsigned int chosenAlpnLen;
-  SECStatus rv = SSL_GetNextProto(ssl_fd_, &alpnState,
+  SECStatus rv = SSL_GetNextProto(ssl_fd_.get(), &alpnState,
                                   reinterpret_cast<unsigned char*>(chosenAlpn),
                                   &chosenAlpnLen, sizeof(chosenAlpn));
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_ERROR, LAYER_INFO << "ALPN error");
     return false;
   }
   switch (alpnState) {
     case SSL_NEXT_PROTO_SELECTED:
@@ -993,17 +996,17 @@ void TransportLayerDtls::PacketReceived(
   // Now try a recv if we're open, since there might be data left
   if (state_ == TS_OPEN) {
     // nICEr uses a 9216 bytes buffer to allow support for jumbo frames
     unsigned char buf[9216];
 
     int32_t rv;
     // One packet might contain several DTLS packets
     do {
-      rv = PR_Recv(ssl_fd_, buf, sizeof(buf), 0, PR_INTERVAL_NO_WAIT);
+      rv = PR_Recv(ssl_fd_.get(), buf, sizeof(buf), 0, PR_INTERVAL_NO_WAIT);
       if (rv > 0) {
         // We have data
         MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Read " << rv << " bytes from NSS");
         SignalPacketReceived(this, buf, rv);
       } else if (rv == 0) {
         TL_SET_STATE(TS_CLOSED);
       } else {
         int32_t err = PR_GetError();
@@ -1024,17 +1027,17 @@ TransportResult TransportLayerDtls::Send
                                                size_t len) {
   CheckThread();
   if (state_ != TS_OPEN) {
     MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Can't call SendPacket() in state "
               << state_);
     return TE_ERROR;
   }
 
-  int32_t rv = PR_Send(ssl_fd_, data, len, 0, PR_INTERVAL_NO_WAIT);
+  int32_t rv = PR_Send(ssl_fd_.get(), data, len, 0, PR_INTERVAL_NO_WAIT);
 
   if (rv > 0) {
     // We have data
     MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Wrote " << rv << " bytes to SSL Layer");
     return rv;
   }
 
   if (rv == 0) {
@@ -1065,17 +1068,17 @@ SECStatus TransportLayerDtls::GetClientA
   stream->CheckThread();
 
   if (!stream->identity_) {
     MOZ_MTLOG(ML_ERROR, "No identity available");
     PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
     return SECFailure;
   }
 
-  *pRetCert = CERT_DupCertificate(stream->identity_->cert());
+  *pRetCert = CERT_DupCertificate(stream->identity_->cert().get());
   if (!*pRetCert) {
     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     return SECFailure;
   }
 
   *pRetKey = SECKEY_CopyPrivateKey(stream->identity_->privkey());
   if (!*pRetKey) {
     CERT_DestroyCertificate(*pRetCert);
@@ -1094,17 +1097,17 @@ nsresult TransportLayerDtls::SetSrtpCiph
   return NS_OK;
 }
 
 nsresult TransportLayerDtls::GetSrtpCipher(uint16_t *cipher) const {
   CheckThread();
   if (state_ != TS_OPEN) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, cipher);
+  SECStatus rv = SSL_GetSRTPCipher(ssl_fd_.get(), cipher);
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_DEBUG, "No SRTP cipher negotiated");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
@@ -1113,17 +1116,17 @@ nsresult TransportLayerDtls::ExportKeyin
                                                   const std::string& context,
                                                   unsigned char *out,
                                                   unsigned int outlen) {
   CheckThread();
   if (state_ != TS_OPEN) {
     MOZ_ASSERT(false, "Transport must be open for ExportKeyingMaterial");
     return NS_ERROR_NOT_AVAILABLE;
   }
-  SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_,
+  SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_.get(),
                                           label.c_str(),
                                           label.size(),
                                           use_context,
                                           reinterpret_cast<const unsigned char *>(
                                               context.c_str()),
                                           context.size(),
                                           out,
                                           outlen);
@@ -1140,19 +1143,18 @@ SECStatus TransportLayerDtls::AuthCertif
                                                   PRBool checksig,
                                                   PRBool isServer) {
   TransportLayerDtls *stream = reinterpret_cast<TransportLayerDtls *>(arg);
   stream->CheckThread();
   return stream->AuthCertificateHook(fd, checksig, isServer);
 }
 
 SECStatus
-TransportLayerDtls::CheckDigest(const RefPtr<VerificationDigest>&
-                                digest,
-                                CERTCertificate *peer_cert) {
+TransportLayerDtls::CheckDigest(const RefPtr<VerificationDigest>& digest,
+                                UniqueCERTCertificate& peer_cert) const {
   unsigned char computed_digest[kMaxDigestLength];
   size_t computed_digest_len;
 
   MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Checking digest, algorithm="
             << digest->algorithm_);
   nsresult res =
       DtlsIdentity::ComputeFingerprint(peer_cert,
                                        digest->algorithm_,
@@ -1184,40 +1186,36 @@ TransportLayerDtls::CheckDigest(const Re
   return SECSuccess;
 }
 
 
 SECStatus TransportLayerDtls::AuthCertificateHook(PRFileDesc *fd,
                                                   PRBool checksig,
                                                   PRBool isServer) {
   CheckThread();
-  ScopedCERTCertificate peer_cert;
-  peer_cert = SSL_PeerCertificate(fd);
-
+  UniqueCERTCertificate peer_cert(SSL_PeerCertificate(fd));
 
   // We are not set up to take this being called multiple
   // times. Change this if we ever add renegotiation.
   MOZ_ASSERT(!auth_hook_called_);
   if (auth_hook_called_) {
     PR_SetError(PR_UNKNOWN_ERROR, 0);
     return SECFailure;
   }
   auth_hook_called_ = true;
 
   MOZ_ASSERT(verification_mode_ != VERIFY_UNSET);
-  MOZ_ASSERT(peer_cert_ == nullptr);
 
   switch (verification_mode_) {
     case VERIFY_UNSET:
       // Break out to error exit
       PR_SetError(PR_UNKNOWN_ERROR, 0);
       break;
 
     case VERIFY_ALLOW_ALL:
-      peer_cert_ = peer_cert.forget();
       cert_ok_ = true;
       return SECSuccess;
 
     case VERIFY_DIGEST:
       {
         MOZ_ASSERT(digests_.size() != 0);
         // Check all the provided digests
 
@@ -1225,17 +1223,16 @@ SECStatus TransportLayerDtls::AuthCertif
         SECStatus rv = SECFailure;
         for (size_t i = 0; i < digests_.size(); i++) {
           RefPtr<VerificationDigest> digest = digests_[i];
           rv = CheckDigest(digest, peer_cert);
 
           // Matches a digest, we are good to go
           if (rv == SECSuccess) {
             cert_ok_ = true;
-            peer_cert = peer_cert.forget();
             return SECSuccess;
           }
         }
       }
       break;
     default:
       MOZ_CRASH();  // Can't happen
   }
--- a/media/mtransport/transportlayerdtls.h
+++ b/media/mtransport/transportlayerdtls.h
@@ -86,32 +86,28 @@ class TransportLayerDtls final : public 
   nsresult GetSrtpCipher(uint16_t *cipher) const;
 
   nsresult ExportKeyingMaterial(const std::string& label,
                                 bool use_context,
                                 const std::string& context,
                                 unsigned char *out,
                                 unsigned int outlen);
 
-  const CERTCertificate *GetPeerCert() const {
-    return peer_cert_;
-  }
-
   // Transport layer overrides.
   virtual nsresult InitInternal();
   virtual void WasInserted();
   virtual TransportResult SendPacket(const unsigned char *data, size_t len);
 
   // Signals
   void StateChange(TransportLayer *layer, State state);
   void PacketReceived(TransportLayer* layer, const unsigned char *data,
                       size_t len);
 
   // For testing use only.  Returns the fd.
-  PRFileDesc* internal_fd() { CheckThread(); return ssl_fd_.rwget(); }
+  PRFileDesc* internal_fd() { CheckThread(); return ssl_fd_.get(); }
 
   TRANSPORT_LAYER_ID("dtls")
 
   private:
   DISALLOW_COPY_ASSIGN(TransportLayerDtls);
 
   // A single digest to check
   class VerificationDigest {
@@ -133,18 +129,18 @@ class TransportLayerDtls final : public 
 
    private:
     ~VerificationDigest() {}
     DISALLOW_COPY_ASSIGN(VerificationDigest);
   };
 
 
   bool Setup();
-  bool SetupCipherSuites(PRFileDesc* ssl_fd) const;
-  bool SetupAlpn(PRFileDesc* ssl_fd) const;
+  bool SetupCipherSuites(UniquePRFileDesc& ssl_fd) const;
+  bool SetupAlpn(UniquePRFileDesc& ssl_fd) const;
   void Handshake();
 
   bool CheckAlpn();
 
   static SECStatus GetClientAuthDataHook(void *arg, PRFileDesc *fd,
                                          CERTDistNames *caNames,
                                          CERTCertificate **pRetCert,
                                          SECKEYPrivateKey **pRetKey);
@@ -154,17 +150,17 @@ class TransportLayerDtls final : public 
                                        PRBool isServer);
   SECStatus AuthCertificateHook(PRFileDesc *fd,
                                 PRBool checksig,
                                 PRBool isServer);
 
   static void TimerCallback(nsITimer *timer, void *arg);
 
   SECStatus CheckDigest(const RefPtr<VerificationDigest>& digest,
-                        CERTCertificate *cert);
+                        UniqueCERTCertificate& cert) const;
 
   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.
@@ -173,19 +169,18 @@ class TransportLayerDtls final : public 
 
   Role role_;
   Verification verification_mode_;
   std::vector<RefPtr<VerificationDigest> > 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_;
-  ScopedPRFileDesc ssl_fd_;
+  UniquePRFileDesc ssl_fd_;
 
-  ScopedCERTCertificate peer_cert_;
   nsCOMPtr<nsITimer> timer_;
   bool auth_hook_called_;
   bool cert_ok_;
 };
 
 
 }  // close namespace
 #endif
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -2836,23 +2836,22 @@ PeerConnectionImpl::GetParameters(
 }
 
 nsresult
 PeerConnectionImpl::CalculateFingerprint(
     const std::string& algorithm,
     std::vector<uint8_t>* fingerprint) const {
   uint8_t buf[DtlsIdentity::HASH_ALGORITHM_MAX_LENGTH];
   size_t len = 0;
-  CERTCertificate* cert;
 
   MOZ_ASSERT(fingerprint);
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
-  cert = mCertificate->Certificate();
+  const UniqueCERTCertificate& cert = mCertificate->Certificate();
 #else
-  cert = mIdentity->cert();
+  const UniqueCERTCertificate& cert = mIdentity->cert();
 #endif
   nsresult rv = DtlsIdentity::ComputeFingerprint(cert, algorithm,
                                                  &buf[0], sizeof(buf),
                                                  &len);
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "Unable to calculate certificate fingerprint, rv=%u",
                         static_cast<unsigned>(rv));
     return rv;
--- a/security/manager/ssl/ScopedNSSTypes.h
+++ b/security/manager/ssl/ScopedNSSTypes.h
@@ -54,19 +54,16 @@ MapSECStatus(SECStatus rv)
     return NS_OK;
   }
 
   return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
 }
 
 // Alphabetical order by NSS type
 // Deprecated: use the equivalent UniquePtr templates instead.
-MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc,
-                                          PRFileDesc,
-                                          PR_Close)
 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificate,
                                           CERTCertificate,
                                           CERT_DestroyCertificate)
 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificateList,
                                           CERTCertificateList,
                                           CERT_DestroyCertificateList)
 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificateRequest,
                                           CERTCertificateRequest,