Bug 1304587 - Avoid using types that correspond to char/char16_t strings in PKCS #11 IDL files. r=keeler draft
authorCykesiopka <cykesiopka.bmo@gmail.com>
Sat, 01 Oct 2016 00:46:13 +0800
changeset 419599 130c8b77a98d21d5b9a0efeccae8861d89fa8f02
parent 419592 138dd1cfe696eb4adfe6e1f2290b29a352b4f650
child 532607 f3b5270f035fd151261c4fd4e08b981d70b7ae5d
push id30965
push usercykesiopka.bmo@gmail.com
push dateFri, 30 Sep 2016 16:46:37 +0000
reviewerskeeler
bugs1304587
milestone52.0a1
Bug 1304587 - Avoid using types that correspond to char/char16_t strings in PKCS #11 IDL files. r=keeler Typically, the interfaces involved don't need to use raw char/char16_t strings, and hence can benefit from the additional safety of using the Mozilla string classes. In some places, this patch also changes some UTF-16 APIs to UTF-8 where the implementations can never actually support UTF-16. This reduces the amount of code and runtime conversion. MozReview-Commit-ID: y8o5wLBohe
security/manager/ssl/nsIPK11Token.idl
security/manager/ssl/nsIPK11TokenDB.idl
security/manager/ssl/nsIPKCS11Module.idl
security/manager/ssl/nsIPKCS11ModuleDB.idl
security/manager/ssl/nsIPKCS11Slot.idl
security/manager/ssl/nsPK11TokenDB.cpp
security/manager/ssl/nsPK11TokenDB.h
security/manager/ssl/nsPKCS11Slot.cpp
security/manager/ssl/nsPKCS11Slot.h
security/manager/ssl/nsPKCS12Blob.cpp
security/manager/ssl/tests/unit/test_pkcs11_slot.js
security/manager/ssl/tests/unit/test_pkcs11_token.js
--- a/security/manager/ssl/nsIPK11Token.idl
+++ b/security/manager/ssl/nsIPK11Token.idl
@@ -11,23 +11,31 @@ interface nsIPK11Token : nsISupports
 {
   const long ASK_EVERY_TIME  = -1;
   const long ASK_FIRST_TIME  =  0;
   const long ASK_EXPIRE_TIME =  1;
 
   /*
    * The name of the token
    */
-  readonly attribute wstring tokenName;
-
-  readonly attribute wstring tokenLabel;
-  readonly attribute wstring tokenManID;
-  readonly attribute wstring tokenHWVersion;
-  readonly attribute wstring tokenFWVersion;
-  readonly attribute wstring tokenSerialNumber;
+  readonly attribute AUTF8String tokenName;
+  readonly attribute AUTF8String tokenLabel;
+  /**
+   * Manufacturer ID of the token.
+   */
+  readonly attribute AUTF8String tokenManID;
+  /**
+   * Hardware version of the token.
+   */
+  readonly attribute AUTF8String tokenHWVersion;
+  /**
+   * Firmware version of the token.
+   */
+  readonly attribute AUTF8String tokenFWVersion;
+  readonly attribute AUTF8String tokenSerialNumber;
 
   /*
    * Login information
    */
   boolean isLoggedIn();
   void login(in boolean force);
   void logoutSimple();
   void logoutAndDropAuthenticatedResources();
@@ -37,19 +45,26 @@ interface nsIPK11Token : nsISupports
    */
   void reset();
 
   /*
    * Password information
    */
   readonly attribute long minimumPasswordLength;
   readonly attribute boolean needsUserInit;
-  boolean checkPassword(in wstring password);  /* Logs out if check fails */
-  void initPassword(in wstring initialPassword);
-  void changePassword(in wstring oldPassword, in wstring newPassword);
+  /**
+   * Checks whether the given password is correct. Logs the token out if an
+   * incorrect password is given.
+   *
+   * @param password The password to check.
+   * @return true if the password was correct, false otherwise.
+   */
+  boolean checkPassword(in AUTF8String password);
+  void initPassword(in AUTF8String initialPassword);
+  void changePassword(in AUTF8String oldPassword, in AUTF8String newPassword);
   long getAskPasswordTimes();
   long getAskPasswordTimeout();
   void setAskPasswordDefaults([const] in long askTimes, [const] in long timeout);
 
   /*
    * Other attributes
    */
   boolean isHardwareToken();
--- a/security/manager/ssl/nsIPK11TokenDB.idl
+++ b/security/manager/ssl/nsIPK11TokenDB.idl
@@ -28,15 +28,15 @@ interface nsIPK11TokenDB : nsISupports
   /*
    * Get the internal key database token
    */
   nsIPK11Token getInternalKeyToken();
 
   /*
    * Find a token by name
    */
-  nsIPK11Token findTokenByName(in wstring tokenName);
+  nsIPK11Token findTokenByName(in AUTF8String tokenName);
 
   /*
    * List all tokens
    */
   nsISimpleEnumerator listTokens();
 };
--- a/security/manager/ssl/nsIPKCS11Module.idl
+++ b/security/manager/ssl/nsIPKCS11Module.idl
@@ -7,15 +7,15 @@
 #include "nsISupports.idl"
 
 interface nsIPKCS11Slot;
 interface nsISimpleEnumerator;
 
 [scriptable, uuid(8a44bdf9-d1a5-4734-bd5a-34ed7fe564c2)]
 interface nsIPKCS11Module : nsISupports
 {
-  readonly attribute wstring name;
-  readonly attribute wstring libName;
+  readonly attribute AUTF8String name;
+  readonly attribute AUTF8String libName;
 
-  nsIPKCS11Slot findSlotByName(in wstring name);
+  nsIPKCS11Slot findSlotByName(in AUTF8String name);
 
   nsISimpleEnumerator listSlots();
 };
--- a/security/manager/ssl/nsIPKCS11ModuleDB.idl
+++ b/security/manager/ssl/nsIPKCS11ModuleDB.idl
@@ -16,19 +16,19 @@ interface nsISimpleEnumerator;
 
 [scriptable, uuid(ff9fbcd7-9517-4334-b97a-ceed78909974)]
 interface nsIPKCS11ModuleDB : nsISupports
 {
   nsIPKCS11Module getInternal();
 
   nsIPKCS11Module getInternalFIPS();
 
-  nsIPKCS11Module findModuleByName(in wstring name);
+  nsIPKCS11Module findModuleByName(in AUTF8String name);
 
-  nsIPKCS11Slot findSlotByName(in wstring name);
+  nsIPKCS11Slot findSlotByName(in AUTF8String name);
 
   nsISimpleEnumerator listModules();
 
   readonly attribute boolean canToggleFIPS;
 
   void toggleFIPSMode();
 
   readonly attribute boolean isFIPSEnabled;
--- a/security/manager/ssl/nsIPKCS11Slot.idl
+++ b/security/manager/ssl/nsIPKCS11Slot.idl
@@ -5,34 +5,40 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIPK11Token;
 
 [scriptable, uuid(c2d4f296-ee60-11d4-998b-00b0d02354a0)]
 interface nsIPKCS11Slot : nsISupports {
-
-  readonly attribute wstring name;
-  readonly attribute wstring desc;
-  readonly attribute wstring manID;
-  readonly attribute wstring HWVersion;
-  readonly attribute wstring FWVersion;
+  readonly attribute AUTF8String name;
+  readonly attribute AUTF8String desc;
+  /**
+   * Manufacturer ID of the slot.
+   */
+  readonly attribute AUTF8String manID;
+  /**
+   * Hardware version of the slot.
+   */
+  readonly attribute AUTF8String HWVersion;
+  /**
+   * Firmware version of the slot.
+   */
+  readonly attribute AUTF8String FWVersion;
 
   const unsigned long SLOT_DISABLED      = 0;
   const unsigned long SLOT_NOT_PRESENT   = 1;
   const unsigned long SLOT_UNINITIALIZED = 2;
   const unsigned long SLOT_NOT_LOGGED_IN = 3;
   const unsigned long SLOT_LOGGED_IN     = 4;
   const unsigned long SLOT_READY         = 5;
   readonly attribute unsigned long status;
 
   /* This is really a workaround for now.  All of the "slot" functions
    * (isTokenPresent(), etc.) are in nsIPK11Token.  For now, return the
    * token and handle those things there.
    */
   nsIPK11Token getToken();
 
   /* more fun with workarounds - we're referring to everything by token name */
-  readonly attribute wstring tokenName;
-
+  readonly attribute AUTF8String tokenName;
 };
-
--- a/security/manager/ssl/nsPK11TokenDB.cpp
+++ b/security/manager/ssl/nsPK11TokenDB.cpp
@@ -1,24 +1,25 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * 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 http://mozilla.org/MPL/2.0/. */
 #include "nsPK11TokenDB.h"
 
+#include "ScopedNSSTypes.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Unused.h"
 #include "nsIMutableArray.h"
 #include "nsISupports.h"
 #include "nsNSSComponent.h"
+#include "nsPromiseFlatString.h"
 #include "nsReadableUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "prerror.h"
-#include "ScopedNSSTypes.h"
 #include "secerr.h"
 
 extern mozilla::LazyLogModule gPIPNSSLog;
 
 NS_IMPL_ISUPPORTS(nsPK11Token, nsIPK11Token)
 
 nsPK11Token::nsPK11Token(PK11SlotInfo* slot)
   : mUIContext(new PipUIContext())
@@ -33,58 +34,56 @@ nsPK11Token::nsPK11Token(PK11SlotInfo* s
   mSeries = PK11_GetSlotSeries(slot);
 
   Unused << refreshTokenInfo(locker);
 }
 
 nsresult
 nsPK11Token::refreshTokenInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/)
 {
-  mTokenName = NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot.get()));
+  mTokenName = PK11_GetTokenName(mSlot.get());
 
   CK_TOKEN_INFO tokInfo;
   nsresult rv = MapSECStatus(PK11_GetTokenInfo(mSlot.get(), &tokInfo));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Set the Label field
   const char* ccLabel = mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(tokInfo.label);
-  const nsACString& cLabel = Substring(
-    ccLabel,
-    ccLabel + PL_strnlen(ccLabel, sizeof(tokInfo.label)));
-  mTokenLabel = NS_ConvertUTF8toUTF16(cLabel);
+  // TODO(Bug 1305930): Stop using PL_strnlen() if/when all our supported
+  //                    platforms provide strnlen().
+  mTokenLabel.Assign(ccLabel, PL_strnlen(ccLabel, sizeof(tokInfo.label)));
   mTokenLabel.Trim(" ", false, true);
 
   // Set the Manufacturer field
   const char* ccManID =
     mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(tokInfo.manufacturerID);
-  const nsACString& cManID = Substring(
+  mTokenManufacturerID.Assign(
     ccManID,
-    ccManID + PL_strnlen(ccManID, sizeof(tokInfo.manufacturerID)));
-  mTokenManID = NS_ConvertUTF8toUTF16(cManID);
-  mTokenManID.Trim(" ", false, true);
+    PL_strnlen(ccManID, sizeof(tokInfo.manufacturerID)));
+  mTokenManufacturerID.Trim(" ", false, true);
 
   // Set the Hardware Version field
+  mTokenHWVersion.Truncate();
   mTokenHWVersion.AppendInt(tokInfo.hardwareVersion.major);
   mTokenHWVersion.Append('.');
   mTokenHWVersion.AppendInt(tokInfo.hardwareVersion.minor);
 
   // Set the Firmware Version field
+  mTokenFWVersion.Truncate();
   mTokenFWVersion.AppendInt(tokInfo.firmwareVersion.major);
   mTokenFWVersion.Append('.');
   mTokenFWVersion.AppendInt(tokInfo.firmwareVersion.minor);
 
   // Set the Serial Number field
   const char* ccSerial =
     mozilla::BitwiseCast<char*, CK_CHAR*>(tokInfo.serialNumber);
-  const nsACString& cSerial = Substring(
-    ccSerial,
-    ccSerial + PL_strnlen(ccSerial, sizeof(tokInfo.serialNumber)));
-  mTokenSerialNum = NS_ConvertUTF8toUTF16(cSerial);
+  mTokenSerialNum.Assign(ccSerial,
+                         PL_strnlen(ccSerial, sizeof(tokInfo.serialNumber)));
   mTokenSerialNum.Trim(" ", false, true);
 
   return NS_OK;
 }
 
 nsPK11Token::~nsPK11Token()
 {
   nsNSSShutDownPreventionLock locker;
@@ -102,147 +101,71 @@ nsPK11Token::virtualDestroyNSSReference(
 }
 
 void
 nsPK11Token::destructorSafeDestroyNSSReference()
 {
   mSlot = nullptr;
 }
 
-NS_IMETHODIMP
-nsPK11Token::GetTokenName(char16_t** aTokenName)
+nsresult
+nsPK11Token::GetAttributeHelper(const nsACString& attribute,
+                        /*out*/ nsACString& xpcomOutParam)
 {
-  NS_ENSURE_ARG_POINTER(aTokenName);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // handle removals/insertions
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshTokenInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  *aTokenName = ToNewUnicode(mTokenName);
-  if (!*aTokenName) return NS_ERROR_OUT_OF_MEMORY;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPK11Token::GetTokenLabel(char16_t** aTokLabel)
-{
-  NS_ENSURE_ARG_POINTER(aTokLabel);
-
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  // handle removals/insertions
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshTokenInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  *aTokLabel = ToNewUnicode(mTokenLabel);
-  if (!*aTokLabel) return NS_ERROR_OUT_OF_MEMORY;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPK11Token::GetTokenManID(char16_t** aTokManID)
-{
-  NS_ENSURE_ARG_POINTER(aTokManID);
-
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  // handle removals/insertions
+  // Handle removals/insertions.
   if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
     nsresult rv = refreshTokenInfo(locker);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
-  *aTokManID = ToNewUnicode(mTokenManID);
-  if (!*aTokManID) return NS_ERROR_OUT_OF_MEMORY;
-  return NS_OK;
-}
 
-NS_IMETHODIMP
-nsPK11Token::GetTokenHWVersion(char16_t** aTokHWVersion)
-{
-  NS_ENSURE_ARG_POINTER(aTokHWVersion);
-
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  // handle removals/insertions
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshTokenInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  *aTokHWVersion = ToNewUnicode(mTokenHWVersion);
-  if (!*aTokHWVersion) return NS_ERROR_OUT_OF_MEMORY;
+  xpcomOutParam = attribute;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPK11Token::GetTokenFWVersion(char16_t** aTokFWVersion)
+nsPK11Token::GetTokenName(/*out*/ nsACString& tokenName)
 {
-  NS_ENSURE_ARG_POINTER(aTokFWVersion);
-
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
+  return GetAttributeHelper(mTokenName, tokenName);
+}
 
-  // handle removals/insertions
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshTokenInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  *aTokFWVersion = ToNewUnicode(mTokenFWVersion);
-  if (!*aTokFWVersion) return NS_ERROR_OUT_OF_MEMORY;
-  return NS_OK;
+NS_IMETHODIMP
+nsPK11Token::GetTokenLabel(/*out*/ nsACString& tokenLabel)
+{
+  return GetAttributeHelper(mTokenLabel, tokenLabel);
 }
 
 NS_IMETHODIMP
-nsPK11Token::GetTokenSerialNumber(char16_t** aTokSerialNum)
+nsPK11Token::GetTokenManID(/*out*/ nsACString& tokenManufacturerID)
 {
-  NS_ENSURE_ARG_POINTER(aTokSerialNum);
+  return GetAttributeHelper(mTokenManufacturerID, tokenManufacturerID);
+}
 
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
+NS_IMETHODIMP
+nsPK11Token::GetTokenHWVersion(/*out*/ nsACString& tokenHWVersion)
+{
+  return GetAttributeHelper(mTokenHWVersion, tokenHWVersion);
+}
 
-  // handle removals/insertions
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshTokenInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  *aTokSerialNum = ToNewUnicode(mTokenSerialNum);
-  if (!*aTokSerialNum) return NS_ERROR_OUT_OF_MEMORY;
-  return NS_OK;
+NS_IMETHODIMP
+nsPK11Token::GetTokenFWVersion(/*out*/ nsACString& tokenFWVersion)
+{
+  return GetAttributeHelper(mTokenFWVersion, tokenFWVersion);
+}
+
+NS_IMETHODIMP
+nsPK11Token::GetTokenSerialNumber(/*out*/ nsACString& tokenSerialNum)
+{
+  return GetAttributeHelper(mTokenSerialNum, tokenSerialNum);
 }
 
 NS_IMETHODIMP
 nsPK11Token::IsLoggedIn(bool* _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
@@ -338,52 +261,48 @@ nsPK11Token::GetNeedsUserInit(bool* aNee
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
   *aNeedsUserInit = PK11_NeedUserInit(mSlot.get());
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPK11Token::CheckPassword(const char16_t* password, bool* _retval)
+nsPK11Token::CheckPassword(const nsACString& password, bool* _retval)
 {
-  // Note: It's OK for |password| to be null.
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
-  NS_ConvertUTF16toUTF8 utf8Password(password);
   SECStatus srv =
-    PK11_CheckUserPassword(mSlot.get(), const_cast<char*>(utf8Password.get()));
+    PK11_CheckUserPassword(mSlot.get(), PromiseFlatCString(password).get());
   if (srv != SECSuccess) {
     *_retval =  false;
     PRErrorCode error = PR_GetError();
     if (error != SEC_ERROR_BAD_PASSWORD) {
       /* something really bad happened - throw an exception */
       return mozilla::psm::GetXPCOMFromNSSError(error);
     }
   } else {
     *_retval =  true;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPK11Token::InitPassword(const char16_t* initialPassword)
+nsPK11Token::InitPassword(const nsACString& initialPassword)
 {
-  // Note: It's OK for |initialPassword| to be null.
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
-  NS_ConvertUTF16toUTF8 utf8Password(initialPassword);
   return MapSECStatus(
-    PK11_InitPin(mSlot.get(), "", const_cast<char*>(utf8Password.get())));
+    PK11_InitPin(mSlot.get(), "", PromiseFlatCString(initialPassword).get()));
 }
 
 NS_IMETHODIMP
 nsPK11Token::GetAskPasswordTimes(int32_t* askTimes)
 {
   NS_ENSURE_ARG_POINTER(askTimes);
 
   nsNSSShutDownPreventionLock locker;
@@ -417,35 +336,31 @@ nsPK11Token::SetAskPasswordDefaults(cons
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
   PK11_SetSlotPWValues(mSlot.get(), askTimes, askTimeout);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPK11Token::ChangePassword(const char16_t* oldPassword,
-                            const char16_t* newPassword)
+nsPK11Token::ChangePassword(const nsACString& oldPassword,
+                            const nsACString& newPassword)
 {
-  // Note: It's OK for |oldPassword| and |newPassword| to be null.
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
-  NS_ConvertUTF16toUTF8 utf8OldPassword(oldPassword);
-  NS_ConvertUTF16toUTF8 utf8NewPassword(newPassword);
-
-  // nsCString.get() will return an empty string instead of nullptr even if it
-  // was initialized with nullptr. PK11_ChangePW() has different semantics for
-  // the empty string and for nullptr, so we can't just use get().
+  // PK11_ChangePW() has different semantics for the empty string and for
+  // nullptr. In order to support this difference, we need to check IsVoid() to
+  // find out if our caller supplied null/undefined args or just empty strings.
   // See Bug 447589.
   return MapSECStatus(PK11_ChangePW(
     mSlot.get(),
-    (oldPassword ? const_cast<char*>(utf8OldPassword.get()) : nullptr),
-    (newPassword ? const_cast<char*>(utf8NewPassword.get()) : nullptr)));
+    oldPassword.IsVoid() ? nullptr : PromiseFlatCString(oldPassword).get(),
+    newPassword.IsVoid() ? nullptr : PromiseFlatCString(newPassword).get()));
 }
 
 NS_IMETHODIMP
 nsPK11Token::IsHardwareToken(bool* _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
@@ -520,29 +435,28 @@ nsPK11TokenDB::GetInternalKeyToken(nsIPK
 
   nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot.get());
   token.forget(_retval);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPK11TokenDB::FindTokenByName(const char16_t* tokenName, nsIPK11Token** _retval)
+nsPK11TokenDB::FindTokenByName(const nsACString& tokenName,
+                       /*out*/ nsIPK11Token** _retval)
 {
-  // Note: It's OK for |tokenName| to be null.
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  NS_ConvertUTF16toUTF8 utf8TokenName(tokenName);
   UniquePK11SlotInfo slot(
-    PK11_FindSlotByName(const_cast<char*>(utf8TokenName.get())));
+    PK11_FindSlotByName(PromiseFlatCString(tokenName).get()));
   if (!slot) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot.get());
   token.forget(_retval);
 
   return NS_OK;
--- a/security/manager/ssl/nsPK11TokenDB.h
+++ b/security/manager/ssl/nsPK11TokenDB.h
@@ -28,24 +28,29 @@ public:
 
 protected:
   virtual ~nsPK11Token();
 
 private:
   friend class nsPK11TokenDB;
   nsresult refreshTokenInfo(const nsNSSShutDownPreventionLock& proofOfLock);
 
-  nsString mTokenName;
-  nsString mTokenLabel, mTokenManID, mTokenHWVersion, mTokenFWVersion;
-  nsString mTokenSerialNum;
+  nsCString mTokenName;
+  nsCString mTokenLabel;
+  nsCString mTokenManufacturerID;
+  nsCString mTokenHWVersion;
+  nsCString mTokenFWVersion;
+  nsCString mTokenSerialNum;
   mozilla::UniquePK11SlotInfo mSlot;
   int mSeries;
   nsCOMPtr<nsIInterfaceRequestor> mUIContext;
   virtual void virtualDestroyNSSReference() override;
   void destructorSafeDestroyNSSReference();
+  nsresult GetAttributeHelper(const nsACString& attribute,
+                      /*out*/ nsACString& xpcomOutParam);
 };
 
 class nsPK11TokenDB : public nsIPK11TokenDB
                     , public nsNSSShutDownObject
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPK11TOKENDB
--- a/security/manager/ssl/nsPKCS11Slot.cpp
+++ b/security/manager/ssl/nsPKCS11Slot.cpp
@@ -6,16 +6,17 @@
 
 #include "mozilla/Casting.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Unused.h"
 #include "nsCOMPtr.h"
 #include "nsIMutableArray.h"
 #include "nsPK11TokenDB.h"
+#include "nsPromiseFlatString.h"
 #include "secmod.h"
 
 using mozilla::LogLevel;
 
 extern mozilla::LazyLogModule gPIPNSSLog;
 
 NS_IMPL_ISUPPORTS(nsPKCS11Slot, nsIPKCS11Slot)
 
@@ -39,39 +40,37 @@ nsPKCS11Slot::refreshSlotInfo(const nsNS
   nsresult rv = MapSECStatus(PK11_GetSlotInfo(mSlot.get(), &slotInfo));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Set the Description field
   const char* ccDesc =
     mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(slotInfo.slotDescription);
-  const nsACString& cDesc = Substring(
-    ccDesc,
-    ccDesc + PL_strnlen(ccDesc, sizeof(slotInfo.slotDescription)));
-  mSlotDesc = NS_ConvertUTF8toUTF16(cDesc);
+  // TODO(Bug 1305930): Stop using PL_strnlen() if/when all our supported
+  //                    platforms provide strnlen().
+  mSlotDesc.Assign(ccDesc, PL_strnlen(ccDesc, sizeof(slotInfo.slotDescription)));
   mSlotDesc.Trim(" ", false, true);
 
   // Set the Manufacturer field
   const char* ccManID =
     mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(slotInfo.manufacturerID);
-  const nsACString& cManID = Substring(
+  mSlotManufacturerID.Assign(
     ccManID,
-    ccManID + PL_strnlen(ccManID, sizeof(slotInfo.manufacturerID)));
-  mSlotManID = NS_ConvertUTF8toUTF16(cManID);
-  mSlotManID.Trim(" ", false, true);
+    PL_strnlen(ccManID, sizeof(slotInfo.manufacturerID)));
+  mSlotManufacturerID.Trim(" ", false, true);
 
   // Set the Hardware Version field
-  mSlotHWVersion = EmptyString();
+  mSlotHWVersion.Truncate();
   mSlotHWVersion.AppendInt(slotInfo.hardwareVersion.major);
   mSlotHWVersion.Append('.');
   mSlotHWVersion.AppendInt(slotInfo.hardwareVersion.minor);
 
   // Set the Firmware Version field
-  mSlotFWVersion = EmptyString();
+  mSlotFWVersion.Truncate();
   mSlotFWVersion.AppendInt(slotInfo.firmwareVersion.major);
   mSlotFWVersion.Append('.');
   mSlotFWVersion.AppendInt(slotInfo.firmwareVersion.minor);
 
   return NS_OK;
 }
 
 nsPKCS11Slot::~nsPKCS11Slot()
@@ -91,124 +90,82 @@ nsPKCS11Slot::virtualDestroyNSSReference
 }
 
 void
 nsPKCS11Slot::destructorSafeDestroyNSSReference()
 {
   mSlot = nullptr;
 }
 
-NS_IMETHODIMP
-nsPKCS11Slot::GetName(char16_t** aName)
+nsresult
+nsPKCS11Slot::GetAttributeHelper(const nsACString& attribute,
+                         /*out*/ nsACString& xpcomOutParam)
 {
-  NS_ENSURE_ARG_POINTER(aName);
-
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown())
-    return NS_ERROR_NOT_AVAILABLE;
-
-  // |csn| is non-owning.
-  char* csn = PK11_GetSlotName(mSlot.get());
-  if (*csn) {
-    *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(csn));
-  } else if (PK11_HasRootCerts(mSlot.get())) {
-    // This is a workaround to an Root Module bug - the root certs module has
-    // no slot name.  Not bothering to localize, because this is a workaround
-    // and for now all the slot names returned by NSS are char * anyway.
-    *aName = ToNewUnicode(NS_LITERAL_STRING("Root Certificates"));
-  } else {
-    // same as above, this is a catch-all
-    *aName = ToNewUnicode(NS_LITERAL_STRING("Unnamed Slot"));
-  }
-  if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPKCS11Slot::GetDesc(char16_t** aDesc)
-{
-  NS_ENSURE_ARG_POINTER(aDesc);
-
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown())
-    return NS_ERROR_NOT_AVAILABLE;
-
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshSlotInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-
-  *aDesc = ToNewUnicode(mSlotDesc);
-  if (!*aDesc) return NS_ERROR_OUT_OF_MEMORY;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPKCS11Slot::GetManID(char16_t** aManID)
-{
-  NS_ENSURE_ARG_POINTER(aManID);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
     nsresult rv = refreshSlotInfo(locker);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
-  *aManID = ToNewUnicode(mSlotManID);
-  if (!*aManID) return NS_ERROR_OUT_OF_MEMORY;
+
+  xpcomOutParam = attribute;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPKCS11Slot::GetHWVersion(char16_t** aHWVersion)
+nsPKCS11Slot::GetName(/*out*/ nsACString& name)
 {
-  NS_ENSURE_ARG_POINTER(aHWVersion);
+  nsNSSShutDownPreventionLock locker;
+  if (isAlreadyShutDown())
+    return NS_ERROR_NOT_AVAILABLE;
 
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown()) {
-    return NS_ERROR_NOT_AVAILABLE;
+  // |csn| is non-owning.
+  char* csn = PK11_GetSlotName(mSlot.get());
+  if (csn && *csn) {
+    name = csn;
+  } else if (PK11_HasRootCerts(mSlot.get())) {
+    // This is a workaround to an Root Module bug - the root certs module has
+    // no slot name.  Not bothering to localize, because this is a workaround
+    // and for now all the slot names returned by NSS are char * anyway.
+    name = NS_LITERAL_CSTRING("Root Certificates");
+  } else {
+    // same as above, this is a catch-all
+    name = NS_LITERAL_CSTRING("Unnamed Slot");
   }
 
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshSlotInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  *aHWVersion = ToNewUnicode(mSlotHWVersion);
-  if (!*aHWVersion) return NS_ERROR_OUT_OF_MEMORY;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPKCS11Slot::GetFWVersion(char16_t** aFWVersion)
+nsPKCS11Slot::GetDesc(/*out*/ nsACString& desc)
 {
-  NS_ENSURE_ARG_POINTER(aFWVersion);
+  return GetAttributeHelper(mSlotDesc, desc);
+}
 
-  nsNSSShutDownPreventionLock locker;
-  if (isAlreadyShutDown()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
+NS_IMETHODIMP
+nsPKCS11Slot::GetManID(/*out*/ nsACString& manufacturerID)
+{
+  return GetAttributeHelper(mSlotManufacturerID, manufacturerID);
+}
 
-  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
-    nsresult rv = refreshSlotInfo(locker);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  *aFWVersion = ToNewUnicode(mSlotFWVersion);
-  if (!*aFWVersion) return NS_ERROR_OUT_OF_MEMORY;
-  return NS_OK;
+NS_IMETHODIMP
+nsPKCS11Slot::GetHWVersion(/*out*/ nsACString& hwVersion)
+{
+  return GetAttributeHelper(mSlotHWVersion, hwVersion);
+}
+
+NS_IMETHODIMP
+nsPKCS11Slot::GetFWVersion(/*out*/ nsACString& fwVersion)
+{
+  return GetAttributeHelper(mSlotFWVersion, fwVersion);
 }
 
 NS_IMETHODIMP
 nsPKCS11Slot::GetToken(nsIPK11Token** _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
@@ -216,38 +173,35 @@ nsPKCS11Slot::GetToken(nsIPK11Token** _r
     return NS_ERROR_NOT_AVAILABLE;
 
   nsCOMPtr<nsIPK11Token> token = new nsPK11Token(mSlot.get());
   token.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPKCS11Slot::GetTokenName(char16_t** aName)
+nsPKCS11Slot::GetTokenName(/*out*/ nsACString& tokenName)
 {
-  NS_ENSURE_ARG_POINTER(aName);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
   if (!PK11_IsPresent(mSlot.get())) {
-    *aName = nullptr;
+    tokenName.SetIsVoid(true);
     return NS_OK;
   }
 
   if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
     nsresult rv = refreshSlotInfo(locker);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
-  *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot.get())));
-  if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
+  tokenName = PK11_GetTokenName(mSlot.get());
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPKCS11Slot::GetStatus(uint32_t* _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
 
@@ -303,73 +257,69 @@ nsPKCS11Module::virtualDestroyNSSReferen
 
 void
 nsPKCS11Module::destructorSafeDestroyNSSReference()
 {
   mModule = nullptr;
 }
 
 NS_IMETHODIMP
-nsPKCS11Module::GetName(char16_t** aName)
+nsPKCS11Module::GetName(/*out*/ nsACString& name)
 {
-  NS_ENSURE_ARG_POINTER(aName);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
-  *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->commonName));
+  name = mModule->commonName;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPKCS11Module::GetLibName(char16_t** aName)
+nsPKCS11Module::GetLibName(/*out*/ nsACString& libName)
 {
-  NS_ENSURE_ARG_POINTER(aName);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
-  if ( mModule->dllName ) {
-    *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->dllName));
+  if (mModule->dllName) {
+    libName = mModule->dllName;
   } else {
-    *aName = nullptr;
+    libName.SetIsVoid(true);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPKCS11Module::FindSlotByName(const char16_t* aName, nsIPKCS11Slot** _retval)
+nsPKCS11Module::FindSlotByName(const nsACString& name,
+                       /*out*/ nsIPKCS11Slot** _retval)
 {
-  // Note: It's OK for |aName| to be null.
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
-  NS_ConvertUTF16toUTF8 asciiname(aName);
-  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Getting \"%s\"\n", asciiname.get()));
+  const nsCString& flatName = PromiseFlatCString(name);
+  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Getting \"%s\"", flatName.get()));
   UniquePK11SlotInfo slotInfo;
   UniquePK11SlotList slotList(PK11_FindSlotsByNames(mModule->dllName,
-                                                    asciiname.get() /*slotName*/,
+                                                    flatName.get() /*slotName*/,
                                                     nullptr /*tokenName*/,
                                                     false));
   if (!slotList) {
     /* name must be the token name */
     slotList.reset(PK11_FindSlotsByNames(mModule->dllName, nullptr /*slotName*/,
-                                         asciiname.get() /*tokenName*/, false));
+                                         flatName.get() /*tokenName*/, false));
   }
   if (slotList && slotList->head && slotList->head->slot) {
     slotInfo.reset(PK11_ReferenceSlot(slotList->head->slot));
   }
   if (!slotInfo) {
     // workaround - the builtin module has no name
-    if (!asciiname.EqualsLiteral("Root Certificates")) {
+    if (!flatName.EqualsLiteral("Root Certificates")) {
       // Give up.
       return NS_ERROR_FAILURE;
     }
 
     slotInfo.reset(PK11_ReferenceSlot(mModule->slots[0]));
   }
 
   nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotInfo.get());
@@ -464,56 +414,52 @@ nsPKCS11ModuleDB::GetInternalFIPS(nsIPKC
   }
 
   nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod.get());
   module.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPKCS11ModuleDB::FindModuleByName(const char16_t* aName,
-                                   nsIPKCS11Module** _retval)
+nsPKCS11ModuleDB::FindModuleByName(const nsACString& name,
+                           /*out*/ nsIPKCS11Module** _retval)
 {
-  // Note: It's OK for |aName| to be null.
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  NS_ConvertUTF16toUTF8 utf8Name(aName);
-  UniqueSECMODModule mod(SECMOD_FindModule(const_cast<char*>(utf8Name.get())));
+  UniqueSECMODModule mod(SECMOD_FindModule(PromiseFlatCString(name).get()));
   if (!mod) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(mod.get());
   module.forget(_retval);
   return NS_OK;
 }
 
 /* This is essentially the same as nsIPK11Token::findTokenByName, except
  * that it returns an nsIPKCS11Slot, which may be desired.
  */
 NS_IMETHODIMP
-nsPKCS11ModuleDB::FindSlotByName(const char16_t* aName,
-                                 nsIPKCS11Slot** _retval)
+nsPKCS11ModuleDB::FindSlotByName(const nsACString& name,
+                         /*out*/ nsIPKCS11Slot** _retval)
 {
-  // Note: It's OK for |aName| to be null.
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  NS_ConvertUTF16toUTF8 utf8Name(aName);
   UniquePK11SlotInfo slotInfo(
-    PK11_FindSlotByName(const_cast<char*>(utf8Name.get())));
+    PK11_FindSlotByName(PromiseFlatCString(name).get()));
   if (!slotInfo) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotInfo.get());
   slot.forget(_retval);
   return NS_OK;
 }
--- a/security/manager/ssl/nsPKCS11Slot.h
+++ b/security/manager/ssl/nsPKCS11Slot.h
@@ -26,22 +26,27 @@ public:
 
   explicit nsPKCS11Slot(PK11SlotInfo* slot);
 
 protected:
   virtual ~nsPKCS11Slot();
 
 private:
   mozilla::UniquePK11SlotInfo mSlot;
-  nsString mSlotDesc, mSlotManID, mSlotHWVersion, mSlotFWVersion;
+  nsCString mSlotDesc;
+  nsCString mSlotManufacturerID;
+  nsCString mSlotHWVersion;
+  nsCString mSlotFWVersion;
   int mSeries;
 
   virtual void virtualDestroyNSSReference() override;
   void destructorSafeDestroyNSSReference();
   nsresult refreshSlotInfo(const nsNSSShutDownPreventionLock& proofOfLock);
+  nsresult GetAttributeHelper(const nsACString& attribute,
+                      /*out*/ nsACString& xpcomOutParam);
 };
 
 class nsPKCS11Module : public nsIPKCS11Module,
                        public nsNSSShutDownObject
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPKCS11MODULE
--- a/security/manager/ssl/nsPKCS12Blob.cpp
+++ b/security/manager/ssl/nsPKCS12Blob.cpp
@@ -138,17 +138,17 @@ nsPKCS12Blob::ImportFromFileHelper(nsIFi
 {
   nsNSSShutDownPreventionLock locker;
   nsresult rv = NS_OK;
   SECStatus srv = SECSuccess;
   SEC_PKCS12DecoderContext *dcx = nullptr;
   SECItem unicodePw;
 
   UniquePK11SlotInfo slot;
-  nsXPIDLString tokenName;
+  nsAutoCString tokenName;
   unicodePw.data = nullptr;
 
   aWantRetry = rr_do_not_retry;
 
   if (aImportMode == im_try_zero_length_secitem)
   {
     unicodePw.len = 0;
   }
@@ -158,21 +158,21 @@ nsPKCS12Blob::ImportFromFileHelper(nsIFi
     rv = getPKCS12FilePassword(&unicodePw);
     if (NS_FAILED(rv)) goto finish;
     if (!unicodePw.data) {
       handleError(PIP_PKCS12_USER_CANCELED);
       return NS_OK;
     }
   }
 
-  mToken->GetTokenName(getter_Copies(tokenName));
-  {
-    NS_ConvertUTF16toUTF8 tokenNameCString(tokenName);
-    slot = UniquePK11SlotInfo(PK11_FindSlotByName(tokenNameCString.get()));
+  rv = mToken->GetTokenName(tokenName);
+  if (NS_FAILED(rv)) {
+    goto finish;
   }
+  slot = UniquePK11SlotInfo(PK11_FindSlotByName(tokenName.get()));
   if (!slot) {
     srv = SECFailure;
     goto finish;
   }
 
   // initialize the decoder
   dcx = SEC_PKCS12DecoderStart(&unicodePw, slot.get(), nullptr, nullptr,
                                nullptr, nullptr, nullptr, nullptr);
--- a/security/manager/ssl/tests/unit/test_pkcs11_slot.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_slot.js
@@ -18,16 +18,19 @@ function run_test() {
   do_register_cleanup(() => {
     pkcs11.deleteModule("PKCS11 Test Module");
   });
   pkcs11.addModule("PKCS11 Test Module", libraryFile.path, 0, 0);
 
   let moduleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
                    .getService(Ci.nsIPKCS11ModuleDB);
   let testModule = moduleDB.findModuleByName("PKCS11 Test Module");
+  // TODO(Bug 1306632): Add a slot to the PSM PKCS 11 test module with a name
+  //                    with high codepoints, then add a test to ensure
+  //                    findSlotByName() is able to find the slot.
   let testSlot = testModule.findSlotByName("Test PKCS11 Slot");
 
   equal(testSlot.name, "Test PKCS11 Slot",
         "Actual and expected name should match");
   equal(testSlot.desc, "Test PKCS11 Slot",
         "Actual and expected description should match");
   equal(testSlot.manID, "Test PKCS11 Manufacturer ID",
         "Actual and expected manufacturer ID should match");
--- a/security/manager/ssl/tests/unit/test_pkcs11_token.js
+++ b/security/manager/ssl/tests/unit/test_pkcs11_token.js
@@ -54,18 +54,18 @@ function checkPasswordFeaturesAndResetPa
   token.setAskPasswordDefaults(10, 20);
   equal(token.getAskPasswordTimes(), 10,
         "Actual and expected ask password times should match");
   equal(token.getAskPasswordTimeout(), 20,
         "Actual and expected ask password timeout should match");
 
   ok(token.checkPassword(initialPW),
      "checkPassword() should succeed if the correct initial password is given");
-  token.changePassword(initialPW, "newPW");
-  ok(token.checkPassword("newPW"),
+  token.changePassword(initialPW, "newPW ÿ 一二三");
+  ok(token.checkPassword("newPW ÿ 一二三"),
      "checkPassword() should succeed if the correct new password is given");
 
   ok(!token.checkPassword("wrongPW"),
      "checkPassword() should fail if an incorrect password is given");
   ok(!token.isLoggedIn(),
      "Token should be logged out after an incorrect password was given");
   ok(!token.needsUserInit,
      "Token should still be init with a password even if an incorrect " +