Bug 307081 - Expose nsNSSCertificate.cpp GetKeyUsagesString() as the keyUsages attribute on nsIX509Cert. r=keeler draft
authorCykesiopka <cykesiopka.bmo@gmail.com>
Fri, 24 Jun 2016 00:12:06 -0700
changeset 381112 1c09b2b5f4c4281ab2e5cf73758bb6578e6c9c6e
parent 381111 11b25444f5c384bdc17b3b1e6deccaca75e53d71
child 381113 ab518fe6a325fe94e4d6583d282c055efb842e2d
push id21395
push usercykesiopka.bmo@gmail.com
push dateFri, 24 Jun 2016 07:13:10 +0000
reviewerskeeler
bugs307081
milestone50.0a1
Bug 307081 - Expose nsNSSCertificate.cpp GetKeyUsagesString() as the keyUsages attribute on nsIX509Cert. r=keeler This allows nsNSSCertificate::FormatUIStrings() to be reimplemented in JS, which is a necessary step for making nsIClientAuthDialogs::ChooseCertificate() pass an nsIArray of nsIX509Certs. Also removes some deprecated and unused constants. MozReview-Commit-ID: CJITKVlUEtP
security/manager/ssl/nsIX509Cert.idl
security/manager/ssl/nsNSSCertificate.cpp
security/manager/ssl/nsNSSCertificateFakeTransport.cpp
--- a/security/manager/ssl/nsIX509Cert.idl
+++ b/security/manager/ssl/nsIX509Cert.idl
@@ -178,34 +178,16 @@ interface nsIX509Cert : nsISupports {
   const unsigned long CERT_NOT_TRUSTED     = 1 << 3;
   const unsigned long ISSUER_NOT_TRUSTED   = 1 << 4;
   const unsigned long ISSUER_UNKNOWN       = 1 << 5;
   const unsigned long INVALID_CA           = 1 << 6;
   const unsigned long USAGE_NOT_ALLOWED    = 1 << 7;
   const unsigned long SIGNATURE_ALGORITHM_DISABLED = 1 << 8;
 
   /**
-   *  Constants that describe the certified usages of a certificate.
-   *
-   *  Deprecated and unused
-   */
-  const unsigned long CERT_USAGE_SSLClient = 0;
-  const unsigned long CERT_USAGE_SSLServer = 1;
-  const unsigned long CERT_USAGE_SSLServerWithStepUp = 2;
-  const unsigned long CERT_USAGE_SSLCA = 3;
-  const unsigned long CERT_USAGE_EmailSigner = 4;
-  const unsigned long CERT_USAGE_EmailRecipient = 5;
-  const unsigned long CERT_USAGE_ObjectSigner = 6;
-  const unsigned long CERT_USAGE_UserCertImport = 7;
-  const unsigned long CERT_USAGE_VerifyCA = 8;
-  const unsigned long CERT_USAGE_ProtectedObjectSigner = 9;
-  const unsigned long CERT_USAGE_StatusResponder = 10;
-  const unsigned long CERT_USAGE_AnyCA = 11;
-
-  /**
    *  Constants for specifying the chain mode when exporting a certificate
    */
   const unsigned long CMS_CHAIN_MODE_CertOnly = 1;
   const unsigned long CMS_CHAIN_MODE_CertChain = 2;
   const unsigned long CMS_CHAIN_MODE_CertChainWithRoot = 3;
 
   /**
    *  Obtain a list of certificates that contains this certificate
@@ -246,16 +228,23 @@ interface nsIX509Cert : nsISupports {
    *  @param localOnly Do not hit the network, even if revocation information
    *                   downloading is currently activated.
    *  @param verified The certificate verification result, see constants.
    *  @param purposes The string listing the usages.
    */
   void getUsagesString(in boolean localOnly, out uint32_t verified, out AString usages);
 
   /**
+   * A comma separated list of localized strings representing the contents of
+   * the certificate's key usage extension, if present. The empty string if the
+   * certificate doesn't have the key usage extension, or has an empty extension.
+   */
+  readonly attribute AString keyUsages;
+
+  /**
    *  This is the attribute which describes the ASN1 layout
    *  of the certificate.  This can be used when doing a
    *  "pretty print" of the certificate's ASN1 structure.
    */
   readonly attribute nsIASN1Object ASN1Structure;
 
   /**
    *  Obtain a raw binary encoding of this certificate
--- a/security/manager/ssl/nsNSSCertificate.cpp
+++ b/security/manager/ssl/nsNSSCertificate.cpp
@@ -6,16 +6,17 @@
 #include "nsNSSCertificate.h"
 
 #include "CertVerifier.h"
 #include "ExtendedValidation.h"
 #include "NSSCertDBTrustDomain.h"
 #include "certdb.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Casting.h"
+#include "mozilla/NotNull.h"
 #include "mozilla/unused.h"
 #include "nsArray.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsCertVerificationThread.h"
 #include "nsICertificateDialogs.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIObjectInputStream.h"
@@ -65,16 +66,18 @@ extern LazyLogModule gPIPNSSLog;
 // in the list to mean not yet initialized.
 #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
 
 NS_IMPL_ISUPPORTS(nsNSSCertificate,
                   nsIX509Cert,
                   nsISerializable,
                   nsIClassInfo)
 
+static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
+
 /*static*/ nsNSSCertificate*
 nsNSSCertificate::Create(CERTCertificate* cert, SECOidTag* evOidPolicy)
 {
   if (GeckoProcessType_Default != XRE_GetProcessType()) {
     NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
     return nullptr;
   }
   if (cert)
@@ -251,110 +254,102 @@ nsNSSCertificate::MarkForPermDeletion()
       return NS_ERROR_FAILURE;
     }
   }
 
   mPermDelete = true;
   return NS_OK;
 }
 
-nsresult
-GetKeyUsagesString(CERTCertificate* cert, nsINSSComponent* nssComponent,
-                   nsString& text)
+/**
+ * Appends a pipnss bundle string to the given string.
+ *
+ * @param nssComponent For accessing the string bundle.
+ * @param bundleKey Key for the string to append.
+ * @param currentText The text to append to, using commas as separators.
+ */
+template<size_t N>
+void
+AppendBundleString(const NotNull<nsCOMPtr<nsINSSComponent>>& nssComponent,
+                   const char (&bundleKey)[N],
+        /*in/out*/ nsAString& currentText)
+{
+  nsAutoString bundleString;
+  nsresult rv = nssComponent->GetPIPNSSBundleString(bundleKey, bundleString);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  if (!currentText.IsEmpty()) {
+    currentText.Append(',');
+  }
+  currentText.Append(bundleString);
+}
+
+NS_IMETHODIMP
+nsNSSCertificate::GetKeyUsages(nsAString& text)
 {
   text.Truncate();
 
-  SECItem keyUsageItem;
-  keyUsageItem.data = nullptr;
-  keyUsageItem.len = 0;
+  nsCOMPtr<nsINSSComponent> nssComponent = do_GetService(kNSSComponentCID);
+  if (!nssComponent) {
+    return NS_ERROR_FAILURE;
+  }
 
-  SECStatus srv;
+  if (!mCert) {
+    return NS_ERROR_FAILURE;
+  }
 
-  // There is no extension, v1 or v2 certificate
-  if (!cert->extensions)
+  if (!mCert->extensions) {
     return NS_OK;
-
+  }
 
-  srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
-  if (srv == SECFailure) {
-    if (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND)
-      return NS_OK;
-    else
-      return NS_ERROR_FAILURE;
+  ScopedAutoSECItem keyUsageItem;
+  if (CERT_FindKeyUsageExtension(mCert.get(), &keyUsageItem) != SECSuccess) {
+    return PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND ? NS_OK
+                                                            : NS_ERROR_FAILURE;
   }
+
   unsigned char keyUsage = 0;
   if (keyUsageItem.len) {
     keyUsage = keyUsageItem.data[0];
   }
 
-  nsAutoString local;
-  nsresult rv;
-  const char16_t comma = ',';
-
+  NotNull<nsCOMPtr<nsINSSComponent>> wrappedNSSComponent =
+    WrapNotNull(nssComponent);
   if (keyUsage & KU_DIGITAL_SIGNATURE) {
-    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local);
-    if (NS_SUCCEEDED(rv)) {
-      if (!text.IsEmpty()) text.Append(comma);
-      text.Append(local.get());
-    }
+    AppendBundleString(wrappedNSSComponent, "CertDumpKUSign", text);
   }
   if (keyUsage & KU_NON_REPUDIATION) {
-    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local);
-    if (NS_SUCCEEDED(rv)) {
-      if (!text.IsEmpty()) text.Append(comma);
-      text.Append(local.get());
-    }
+    AppendBundleString(wrappedNSSComponent, "CertDumpKUNonRep", text);
   }
   if (keyUsage & KU_KEY_ENCIPHERMENT) {
-    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local);
-    if (NS_SUCCEEDED(rv)) {
-      if (!text.IsEmpty()) text.Append(comma);
-      text.Append(local.get());
-    }
+    AppendBundleString(wrappedNSSComponent, "CertDumpKUEnc", text);
   }
   if (keyUsage & KU_DATA_ENCIPHERMENT) {
-    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local);
-    if (NS_SUCCEEDED(rv)) {
-      if (!text.IsEmpty()) text.Append(comma);
-      text.Append(local.get());
-    }
+    AppendBundleString(wrappedNSSComponent, "CertDumpKUDEnc", text);
   }
   if (keyUsage & KU_KEY_AGREEMENT) {
-    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local);
-    if (NS_SUCCEEDED(rv)) {
-      if (!text.IsEmpty()) text.Append(comma);
-      text.Append(local.get());
-    }
+    AppendBundleString(wrappedNSSComponent, "CertDumpKUKA", text);
   }
   if (keyUsage & KU_KEY_CERT_SIGN) {
-    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local);
-    if (NS_SUCCEEDED(rv)) {
-      if (!text.IsEmpty()) text.Append(comma);
-      text.Append(local.get());
-    }
+    AppendBundleString(wrappedNSSComponent, "CertDumpKUCertSign", text);
   }
   if (keyUsage & KU_CRL_SIGN) {
-    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local);
-    if (NS_SUCCEEDED(rv)) {
-      if (!text.IsEmpty()) text.Append(comma);
-      text.Append(local.get());
-    }
+    AppendBundleString(wrappedNSSComponent, "CertDumpKUCRLSign", text);
   }
 
-  PORT_Free (keyUsageItem.data);
   return NS_OK;
 }
 
 nsresult
 nsNSSCertificate::FormatUIStrings(const nsAutoString& nickname,
                                   nsAutoString& nickWithSerial,
                                   nsAutoString& details)
 {
-  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
-
   if (!NS_IsMainThread()) {
     NS_ERROR("nsNSSCertificate::FormatUIStrings called off the main thread");
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
@@ -416,18 +411,17 @@ nsNSSCertificate::FormatUIStrings(const 
         details.Append(char16_t(' '));
       }
       details.Append(temp1);
     }
 
     details.Append(char16_t('\n'));
   }
 
-  if (NS_SUCCEEDED(GetKeyUsagesString(mCert.get(), nssComponent, temp1)) &&
-      !temp1.IsEmpty()) {
+  if (NS_SUCCEEDED(GetKeyUsages(temp1)) && !temp1.IsEmpty()) {
     details.AppendLiteral("  ");
     if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpKeyUsage", info))) {
       details.Append(info);
       details.AppendLiteral(": ");
     }
     details.Append(temp1);
     details.Append(char16_t('\n'));
   }
@@ -580,18 +574,16 @@ nsNSSCertificate::GetWindowTitle(nsAStri
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSCertificate::GetNickname(nsAString& aNickname)
 {
-  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
   if (mCert->nickname) {
     CopyUTF8toUTF16(mCert->nickname, aNickname);
   } else {
     nsresult rv;
@@ -602,18 +594,16 @@ nsNSSCertificate::GetNickname(nsAString&
     nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
 {
-  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
   if (mCert->emailAddr) {
     CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
   } else {
     nsresult rv;
@@ -1049,18 +1039,16 @@ NS_IMETHODIMP
 nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
 {
   return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
 }
 
 NS_IMETHODIMP
 nsNSSCertificate::GetTokenName(nsAString& aTokenName)
 {
-  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
-
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
   aTokenName.Truncate();
   if (mCert) {
     // HACK alert
     // When the trust of a builtin cert is modified, NSS copies it into the
--- a/security/manager/ssl/nsNSSCertificateFakeTransport.cpp
+++ b/security/manager/ssl/nsNSSCertificateFakeTransport.cpp
@@ -1,22 +1,22 @@
 /* -*- 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 "nsNSSCertificateFakeTransport.h"
 
+#include "mozilla/Assertions.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsISupportsPrimitives.h"
 #include "nsNSSCertificate.h"
 #include "nsString.h"
-#include "nsXPIDLString.h"
 
 NS_IMPL_ISUPPORTS(nsNSSCertificateFakeTransport,
                   nsIX509Cert,
                   nsISerializable,
                   nsIClassInfo)
 
 nsNSSCertificateFakeTransport::nsNSSCertificateFakeTransport()
   : mCertSerialization(nullptr)
@@ -195,16 +195,23 @@ nsNSSCertificateFakeTransport::GetUsages
 NS_IMETHODIMP
 nsNSSCertificateFakeTransport::GetUsagesString(bool, uint32_t*, nsAString&)
 {
   NS_NOTREACHED("Unimplemented on content process");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsNSSCertificateFakeTransport::GetKeyUsages(nsAString&)
+{
+  MOZ_ASSERT_UNREACHABLE("Unimplemented on content process");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsNSSCertificateFakeTransport::GetASN1Structure(nsIASN1Object**)
 {
   NS_NOTREACHED("Unimplemented on content process");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsNSSCertificateFakeTransport::Equals(nsIX509Cert*, bool*)