From d41928522e534dd9a0996236faf1a714b84070a7 Mon Sep 17 00:00:00 2001 From: "javi%netscape.com" Date: Wed, 2 May 2001 05:38:26 +0000 Subject: [PATCH] Fix for Bug 78012 r=thayes sr=blizzard Make the cert viewer more functional. --- security/manager/pki/public/Makefile.in | 1 + security/manager/pki/public/makefile.win | 1 + .../manager/pki/public/nsIASN1Outliner.idl | 54 ++ security/manager/pki/public/nsIASN1Tree.idl | 54 ++ .../manager/pki/public/nsIPKIParamBlock.idl | 1 - .../pki/resources/content/certDump.xul | 35 +- .../pki/resources/content/certViewer.xul | 3 +- .../pki/resources/content/viewCertDetails.js | 182 ++-- .../pki/resources/content/viewCertDetails.xul | 5 +- .../resources/locale/en-US/certManager.dtd | 1 + .../resources/locale/en-US/pippki.properties | 4 + security/manager/pki/src/Makefile.in | 1 + security/manager/pki/src/makefile.win | 1 + security/manager/pki/src/nsASN1Outliner.cpp | 488 ++++++++++ security/manager/pki/src/nsASN1Outliner.h | 73 ++ security/manager/pki/src/nsASN1Tree.cpp | 488 ++++++++++ security/manager/pki/src/nsASN1Tree.h | 73 ++ security/manager/pki/src/nsNSSDialogs.cpp | 3 +- security/manager/pki/src/nsPKIModule.cpp | 9 + security/manager/pki/src/nsPKIParamBlock.cpp | 50 +- security/manager/pki/src/nsPKIParamBlock.h | 12 +- security/manager/ssl/public/nsIX509Cert.idl | 73 +- .../resources/locale/en-US/pipnss.properties | 60 +- security/manager/ssl/src/Makefile.in | 1 + security/manager/ssl/src/nsNSSASN1Object.cpp | 474 ++++++++++ security/manager/ssl/src/nsNSSASN1Object.h | 92 ++ security/manager/ssl/src/nsNSSCertificate.cpp | 880 +++++++++++++++++- security/manager/ssl/src/nsNSSCertificate.h | 6 + security/manager/ssl/src/nsNSSComponent.cpp | 6 +- 29 files changed, 2958 insertions(+), 173 deletions(-) create mode 100644 security/manager/pki/public/nsIASN1Outliner.idl create mode 100644 security/manager/pki/public/nsIASN1Tree.idl create mode 100644 security/manager/pki/src/nsASN1Outliner.cpp create mode 100644 security/manager/pki/src/nsASN1Outliner.h create mode 100644 security/manager/pki/src/nsASN1Tree.cpp create mode 100644 security/manager/pki/src/nsASN1Tree.h create mode 100644 security/manager/ssl/src/nsNSSASN1Object.cpp create mode 100644 security/manager/ssl/src/nsNSSASN1Object.h diff --git a/security/manager/pki/public/Makefile.in b/security/manager/pki/public/Makefile.in index 4fbf48a96de7..84750a0face6 100644 --- a/security/manager/pki/public/Makefile.in +++ b/security/manager/pki/public/Makefile.in @@ -43,6 +43,7 @@ include $(DEPTH)/config/autoconf.mk XPIDLSRCS = \ nsIPKIParamBlock.idl \ + nsIASN1Outliner.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/security/manager/pki/public/makefile.win b/security/manager/pki/public/makefile.win index 66f4360d995c..3e856b7da86f 100644 --- a/security/manager/pki/public/makefile.win +++ b/security/manager/pki/public/makefile.win @@ -50,6 +50,7 @@ XPIDL_INCLUDES=-I$(DEPTH)\dist\idl XPIDLSRCS= \ .\nsIPKIParamBlock.idl \ + .\nsIASN1Outliner.idl \ $(NULL) diff --git a/security/manager/pki/public/nsIASN1Outliner.idl b/security/manager/pki/public/nsIASN1Outliner.idl new file mode 100644 index 000000000000..803b1d661514 --- /dev/null +++ b/security/manager/pki/public/nsIASN1Outliner.idl @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Ian McGreer + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "nsISupports.idl" +#include "nsIOutlinerView.idl" +#include "nsIX509Cert.idl" + +[scriptable, uuid(c727b2f2-1dd1-11b2-95df-f63c15b4cd35)] +interface nsIASN1Outliner : nsIOutlinerView { + + void loadASN1Structure(in nsIASN1Object asn1Object); + + wstring getDisplayData(in unsigned long index); + +}; + +%{C++ + +#define NS_ASN1OUTLINER_CONTRACTID "@mozilla.org/security/nsASN1Outliner;1" + +%} + diff --git a/security/manager/pki/public/nsIASN1Tree.idl b/security/manager/pki/public/nsIASN1Tree.idl new file mode 100644 index 000000000000..803b1d661514 --- /dev/null +++ b/security/manager/pki/public/nsIASN1Tree.idl @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Ian McGreer + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "nsISupports.idl" +#include "nsIOutlinerView.idl" +#include "nsIX509Cert.idl" + +[scriptable, uuid(c727b2f2-1dd1-11b2-95df-f63c15b4cd35)] +interface nsIASN1Outliner : nsIOutlinerView { + + void loadASN1Structure(in nsIASN1Object asn1Object); + + wstring getDisplayData(in unsigned long index); + +}; + +%{C++ + +#define NS_ASN1OUTLINER_CONTRACTID "@mozilla.org/security/nsASN1Outliner;1" + +%} + diff --git a/security/manager/pki/public/nsIPKIParamBlock.idl b/security/manager/pki/public/nsIPKIParamBlock.idl index 7da062342a76..bf65181048b8 100644 --- a/security/manager/pki/public/nsIPKIParamBlock.idl +++ b/security/manager/pki/public/nsIPKIParamBlock.idl @@ -38,7 +38,6 @@ [scriptable, uuid(b6fe3d78-1dd1-11b2-9058-ced9016984c8)] interface nsIPKIParamBlock : nsISupports { - void setNumberISupports(in PRInt32 numISupports); void setISupportAtIndex(in PRInt32 index, in nsISupports object); nsISupports getISupportAtIndex(in PRInt32 index); }; diff --git a/security/manager/pki/resources/content/certDump.xul b/security/manager/pki/resources/content/certDump.xul index 667130073321..4d89ecc33abd 100644 --- a/security/manager/pki/resources/content/certDump.xul +++ b/security/manager/pki/resources/content/certDump.xul @@ -23,9 +23,7 @@ - Javier Delgadillo --> - - - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - diff --git a/security/manager/pki/resources/content/certViewer.xul b/security/manager/pki/resources/content/certViewer.xul index 6ce9e9ded8ec..e7dcba095567 100644 --- a/security/manager/pki/resources/content/certViewer.xul +++ b/security/manager/pki/resources/content/certViewer.xul @@ -25,10 +25,11 @@ + + - =0; i--) { - rows[i].appendChild(cells[i]); - items[i].appendChild(rows[i]); - child[i].appendChild(items[i]); + var child = document.getElementById(node); + var numCerts = chain.Count(); + var currCert; + var displayVal; + var addTwistie; + for (var i=numCerts-1; i>=0; i--) { + currCert = chain.GetElementAt(i); + currCert = currCert.QueryInterface(nsIX509Cert); + if (currCert.commonName) { + displayVal = currCert.commonName; + } else { + displayVal = currCert.windowTitle; + } + if (0 == i) { + addTwistie = false; + } else { + addTwistie = true; + } + child = addChildrenToTree(child, displayVal, null,addTwistie); } } @@ -76,13 +75,14 @@ function setWindowName() { // Get the cert from the cert database var certdb = Components.classes[nsX509CertDB].getService(nsIX509CertDB); - var windowReference=document.getElementById('certDetails'); myName = self.name; + bundle = srGetStrBundle("chrome://pippki/locale/pippki.properties"); var cert; + certDetails = bundle.GetStringFromName('certDetails'); if (myName != "_blank") { - windowReference.setAttribute("title","Certificate Detail: \""+myName+"\""); + windowReference.setAttribute("title",certDetails+'"'+myName+'"'); // Get the token // XXX ignore this for now. NSS will find the cert on a token // by "tokenname:certname", which is what we have. @@ -97,7 +97,7 @@ function setWindowName() var isupport = pkiParams.getISupportAtIndex(1); cert = isupport.QueryInterface(nsIX509Cert); windowReference.setAttribute("title", - "Certificate Detail: \""+cert.windowTitle+'"'); + certDetails+'"'+cert.windowTitle+'"'); } // @@ -105,66 +105,88 @@ function setWindowName() // // The chain of trust - var chainEnum = cert.getChain(); - chainEnum.first(); - var c = 0; - var chain = []; - try { - while (true) { - var node = chainEnum.currentItem(); - node = node.QueryInterface(nsIX509Cert); - chain[c++] = node.commonName; - chainEnum.next(); - } - } catch (e) {} - AddCertChain("chain", chain.reverse(),""); + var chain = cert.getChain(); + AddCertChain("chain", chain,""); AddCertChain("chainDump", chain,"dump_"); DisplayGeneralDataFromCert(cert); BuildPrettyPrint(cert); } -function addTreeItemToTreeChild(treeChild, label) + +function addChildrenToTree(parentTree,label,value,addTwistie) +{ + var treeChild1 = document.createElement("treechildren"); + var treeElement = addTreeItemToTreeChild(treeChild1,label,value,addTwistie); + parentTree.appendChild(treeChild1); + return treeElement; +} + +function addTreeItemToTreeChild(treeChild,label,value,addTwistie) { var treeElem1 = document.createElement("treeitem"); - treeElem1.setAttribute("container","true"); - treeElem1.setAttribute("open","true"); - treeElem1.setAttribute("class","treecell-indent"); + if (addTwistie) { + treeElem1.setAttribute("container","true"); + treeElem1.setAttribute("open","true"); + } var treeRow = document.createElement("treerow"); var treeCell = document.createElement("treecell"); treeCell.setAttribute("class", "treecell-indent"); treeCell.setAttribute("label",label); + if (value) + treeCell.setAttribute("display",value); treeRow.appendChild(treeCell); treeElem1.appendChild(treeRow); treeChild.appendChild(treeElem1); return treeElem1; } -function addChildrenToTree(parentTree,label) +function removeChildrenInTree(tree) { - var treeChild1 = document.createElement("treechildren"); - var treeElement = addTreeItemToTreeChild(treeChild1, label); - parentTree.appendChild(treeChild1); - return treeElement; + while (tree.firstChild) + tree.removeChild(tree.firstChild); +} + +function displaySelected() { + var asn1Outliner = document.getElementById('prettyDumpOutliner'). + outlinerBoxObject.view.QueryInterface(nsIASN1Outliner); + var items = asn1Outliner.selection; + if (items.currentIndex != -1) { + var certDumpVal = document.getElementById('certDumpVal'); + removeChildrenInTree(certDumpVal); + // Since the tree widget doesn't do the right thing for new lines, + // I'll interpret them here. + var value = asn1Outliner.getDisplayData(items.currentIndex); + var strings = value.split("\n"); + var i; + var children = document.createElement("treechildren"); + certDumpVal.appendChild(children); + for (i=0;strings[i]!=null;i++) { + addTreeItemToTreeChild(children,strings[i],null,false); + } + } } function BuildPrettyPrint(cert) { - // For now, I'm just gonna build some dummy stuff - // just to get the helper functions I need up and - // running. - var prettyPrintBox = document.getElementById("prettyPrintTree"); - var tree = document.createElement("tree"); - prettyPrintBox.appendChild(tree); - var treeChildren = addChildrenToTree(tree,"Top Level"); - var childOfFirstChild = addChildrenToTree(treeChildren, "Second Level:1"); - var levelone2 = addChildrenToTree(treeChildren,"Second Level:2"); - var levelthree1 = addChildrenToTree(childOfFirstChild,"Third Level:1"); + var certDumpOutliner = Components.classes[nsASN1Outliner]. + createInstance(nsIASN1Outliner); + certDumpOutliner.loadASN1Structure(cert.ASN1Structure); + document.getElementById('prettyDumpOutliner'). + outlinerBoxObject.view = certDumpOutliner; +} + +function addAttributeFromCert(nodeName, value) +{ + var node = document.getElementById(nodeName); + if (!value) { + value = bundle.GetStringFromName('notPresent'); + } + node.setAttribute('value',value) } function DisplayGeneralDataFromCert(cert) { // Verification and usage - var bundle = srGetStrBundle("chrome://pippki/locale/pippki.properties"); var verifystr = ""; var o1 = {}; var o2 = {}; @@ -197,37 +219,21 @@ function DisplayGeneralDataFromCert(cert) } // Common Name - var cn=document.getElementById('commonname'); - cn.setAttribute("value", cert.commonName); - + addAttributeFromCert('commonname', cert.commonName); // Organization - var org=document.getElementById('organization'); - org.setAttribute("value", cert.organization); + addAttributeFromCert('organization', cert.organization); // Organizational Unit - var ou=document.getElementById('orgunit'); - ou.setAttribute("value", cert.organizationalUnit); - + addAttributeFromCert('orgunit', cert.organizationalUnit); // Subject Name - var subn=document.getElementById('subjectname'); - subn.setAttribute("value", cert.subjectName); - + addAttributeFromCert('subjectname',cert.subjectName); // Issuer Name - var issn=document.getElementById('issuername'); - issn.setAttribute("value", cert.issuerName); - + addAttributeFromCert('issuername',cert.issuerName); // Serial Number - var sern=document.getElementById('serialnumber'); - sern.setAttribute("value", cert.serialNumber); - + addAttributeFromCert('serialnumber',cert.serialNumber); // RSA Public Modulus - var rsap=document.getElementById('rsapubmodulus'); - rsap.setAttribute("value", cert.rsaPubModulus); - + addAttributeFromCert('rsapubmodulus',cert.rsaPubModulus); // SHA1 Fingerprint - var sha1=document.getElementById('sha1fingerprint'); - sha1.setAttribute("value", cert.sha1Fingerprint); - + addAttributeFromCert('sha1fingerprint',cert.sha1Fingerprint); // MD5 Fingerprint - var md5=document.getElementById('md5fingerprint'); - md5.setAttribute("value", cert.md5Fingerprint); + addAttributeFromCert('md5fingerprint',cert.md5Fingerprint); } diff --git a/security/manager/pki/resources/content/viewCertDetails.xul b/security/manager/pki/resources/content/viewCertDetails.xul index f1e3f7906f79..e79ef3736ced 100644 --- a/security/manager/pki/resources/content/viewCertDetails.xul +++ b/security/manager/pki/resources/content/viewCertDetails.xul @@ -21,10 +21,7 @@ - Bob Lord - Ian McGreer --> - - - - + + diff --git a/security/manager/pki/resources/locale/en-US/pippki.properties b/security/manager/pki/resources/locale/en-US/pippki.properties index 95d15a50798b..d052c86055ca 100644 --- a/security/manager/pki/resources/locale/en-US/pippki.properties +++ b/security/manager/pki/resources/locale/en-US/pippki.properties @@ -55,3 +55,7 @@ certNotVerified_Unknown=Could not verify this certificate for unknown reasons. #Client auth clientAuthMessage1=Organization: "%S" clientAuthMessage2=Issued Under: "%S" + +#Cert Viewer +certDetails=Certificate Details: +notPresent= diff --git a/security/manager/pki/src/Makefile.in b/security/manager/pki/src/Makefile.in index 5d074fb58ef9..7e42ffad1264 100644 --- a/security/manager/pki/src/Makefile.in +++ b/security/manager/pki/src/Makefile.in @@ -52,6 +52,7 @@ CPPSRCS = \ nsNSSDialogs.cpp \ nsPKIModule.cpp \ nsPKIParamBlock.cpp \ + nsASN1Outliner.cpp \ $(NULL) REQUIRES = nspr security js xpcom string dom pref intl locale windowwatcher appshell necko pipnss diff --git a/security/manager/pki/src/makefile.win b/security/manager/pki/src/makefile.win index fe5726d72c53..45a8bb7899a6 100644 --- a/security/manager/pki/src/makefile.win +++ b/security/manager/pki/src/makefile.win @@ -63,6 +63,7 @@ OBJS = \ .\$(OBJDIR)\nsNSSDialogs.obj \ .\$(OBJDIR)\nsPKIModule.obj \ .\$(OBJDIR)\nsPKIParamBlock.obj \ + .\$(OBJDIR)\nsASN1Outliner.obj \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/security/manager/pki/src/nsASN1Outliner.cpp b/security/manager/pki/src/nsASN1Outliner.cpp new file mode 100644 index 000000000000..8618b50a88f2 --- /dev/null +++ b/security/manager/pki/src/nsASN1Outliner.cpp @@ -0,0 +1,488 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#include "nsASN1Outliner.h" +#include "nsIComponentManager.h" +#include "nsString.h" + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Outliner, nsIASN1Outliner, + nsIOutlinerView); + +nsNSSASN1Outliner::nsNSSASN1Outliner() +{ + NS_INIT_ISUPPORTS(); +} + +nsNSSASN1Outliner::~nsNSSASN1Outliner() +{ +} + +/* void loadASN1Structure (in nsIASN1Object asn1Object); */ +NS_IMETHODIMP +nsNSSASN1Outliner::LoadASN1Structure(nsIASN1Object *asn1Object) +{ + mASN1Object = asn1Object; + return NS_OK; +} + +/* wstring getDisplayData (in unsigned long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetDisplayData(PRUint32 index, PRUnichar **_retval) +{ + nsCOMPtr object; + GetASN1ObjectAtIndex(index, mASN1Object, getter_AddRefs(object)); + if (object) { + object->GetDisplayValue(_retval); + } else { + *_retval = nsnull; + } + return NS_OK; +} + +nsresult +nsNSSASN1Outliner::GetASN1ObjectAtIndex(PRUint32 index, + nsIASN1Object *sourceObject, + nsIASN1Object **retval) +{ + if (mASN1Object == nsnull) { + *retval = nsnull; + } else { + if (index == 0) { + *retval = sourceObject; + NS_IF_ADDREF(*retval); + return NS_OK; + } + // the source object better be an nsIASN1Sequence, otherwise, + // the index better be 1. If neither of these is ture, then + // someting bad has happened. + nsCOMPtr sequence = do_QueryInterface(sourceObject); + if (sequence == nsnull) { + //Something really bad has happened. bail out. + *retval = nsnull; + return NS_ERROR_FAILURE; + } else { + PRBool showObjects; + sequence->GetShowObjects(&showObjects); + if (!showObjects) { + *retval = nsnull; + return NS_OK; + } + nsCOMPtrasn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 numObjects; + asn1Objects->Count(&numObjects); + PRUint32 i; + nsCOMPtrisupports; + nsCOMPtrcurrObject; + PRUint32 numObjectsCounted = 0; + PRUint32 numObjToDisplay; + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + numObjToDisplay = CountNumberOfVisibleRows(currObject); + if ((numObjectsCounted+numObjToDisplay) >= index) { + return GetASN1ObjectAtIndex(index-numObjectsCounted-1, + currObject, retval); + } + numObjectsCounted += numObjToDisplay; + } + } + } + // We should never get here. + return NS_ERROR_FAILURE; +} + +PRUint32 +nsNSSASN1Outliner::CountNumberOfVisibleRows(nsIASN1Object *asn1Object) +{ + nsCOMPtr sequence; + PRUint32 count = 1; + + sequence = do_QueryInterface(asn1Object); + if (sequence) { + PRBool showObjects; + sequence->GetShowObjects(&showObjects); + if (showObjects) { + nsCOMPtr asn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 numObjects; + asn1Objects->Count(&numObjects); + PRUint32 i; + nsCOMPtr isupports; + nsCOMPtr currObject; + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + count += CountNumberOfVisibleRows(currObject); + } + } + } + return count; +} + +/* readonly attribute long rowCount; */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetRowCount(PRInt32 *aRowCount) +{ + if (mASN1Object) { + *aRowCount = CountNumberOfVisibleRows(mASN1Object); + } else { + *aRowCount = 0; + } + return NS_OK; +} + +/* attribute nsIOutlinerSelection selection; */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetSelection(nsIOutlinerSelection * *aSelection) +{ + *aSelection = mSelection; + NS_IF_ADDREF(*aSelection); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Outliner::SetSelection(nsIOutlinerSelection * aSelection) +{ + mSelection = aSelection; + return NS_OK; +} + +/* void getRowProperties (in long index, in nsISupportsArray properties); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetRowProperties(PRInt32 index, nsISupportsArray *properties) +{ + return NS_OK; +} + +/* void getCellProperties (in long row, in wstring colID, + in nsISupportsArray properties); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetCellProperties(PRInt32 row, const PRUnichar *colID, + nsISupportsArray *properties) +{ + return NS_OK; +} + +/* void getColumnProperties (in wstring colID, in nsIDOMElement colElt, + in nsISupportsArray properties); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetColumnProperties(const PRUnichar *colID, + nsIDOMElement *colElt, + nsISupportsArray *properties) +{ + return NS_OK; +} + +/* boolean isContainer (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsContainer(PRInt32 index, PRBool *_retval) +{ + nsCOMPtr object; + nsCOMPtr sequence; + + nsresult rv = GetASN1ObjectAtIndex(index, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + sequence = do_QueryInterface(object); + if (sequence != nsnull) { + sequence->GetProcessObjects(_retval); + } else { + *_retval = PR_FALSE; + } + return NS_OK; +} + +/* boolean isContainerOpen (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsContainerOpen(PRInt32 index, PRBool *_retval) +{ + nsCOMPtr object; + nsCOMPtr sequence; + + nsresult rv = GetASN1ObjectAtIndex(index, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + sequence = do_QueryInterface(object); + if (sequence == nsnull) { + *_retval = PR_FALSE; + } else { + sequence->GetShowObjects(_retval); + } + return NS_OK; +} + +/* boolean isContainerEmpty (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsContainerEmpty(PRInt32 index, PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +PRInt32 +nsNSSASN1Outliner::GetParentOfObjectAtIndex(PRUint32 index, + nsIASN1Object *sourceObject) +{ + if (index == 0) { + return -1; + } else { + PRUint32 numVisibleRows = CountNumberOfVisibleRows(sourceObject); + if (numVisibleRows > index) { + nsCOMPtrsequence(do_QueryInterface(sourceObject)); + if (sequence == nsnull) + return -2; + nsCOMPtrasn1Objects; + nsCOMPtrisupports; + nsCOMPtrcurrObject; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 indexCnt = 0; + PRUint32 i,numObjects; + asn1Objects->Count(&numObjects); + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + numVisibleRows = CountNumberOfVisibleRows(currObject); + if (numVisibleRows+indexCnt > index) { + //We're dealing with a sequence with visible elements + //that has the desired element. + PRInt32 subIndex = GetParentOfObjectAtIndex(index-indexCnt+1, + currObject); + if (subIndex == -1) { + return indexCnt+1; + } else if (subIndex == -2) { + return -2; + } else { + // This is a case where a subIndex was returned. + return indexCnt+1+subIndex; + } + } + indexCnt+=numVisibleRows; + if (indexCnt == index) { + // The passed in source object is the parent. + return -1; + } + } + }// the else case is an error, just let it fall through. + } + return -2; +} + +/* long getParentIndex (in long rowIndex); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval) +{ + *_retval = GetParentOfObjectAtIndex(rowIndex, mASN1Object); + return NS_OK; +} + +/* boolean hasNextSibling (in long rowIndex, in long afterIndex); */ +NS_IMETHODIMP +nsNSSASN1Outliner::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +PRInt32 +nsNSSASN1Outliner::GetLevelsTilIndex(PRUint32 index, + nsIASN1Object *sourceObject) +{ + if (index == 0) { + return 0; + } else { + nsCOMPtr sequence(do_QueryInterface(sourceObject)); + nsCOMPtrasn1Objects; + if (sequence == nsnull) + return -1; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 numObjects,i,indexCnt=0,numVisibleRows; + asn1Objects->Count(&numObjects); + nsCOMPtr isupports; + nsCOMPtr currObject; + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + numVisibleRows = CountNumberOfVisibleRows(currObject); + if ((numVisibleRows+indexCnt)>=index) { + PRInt32 numSubLayers; + numSubLayers = GetLevelsTilIndex(index-indexCnt-1, + currObject); + if (numSubLayers == -1) { + // This return value means the parent is not a child + // object, we're not adding any more layers to the nested + // levels. + return -1; + } else { + return 1+numSubLayers; + } + } + indexCnt += numVisibleRows; + } + } + return -2; +} + +/* long getLevel (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetLevel(PRInt32 index, PRInt32 *_retval) +{ + *_retval = GetLevelsTilIndex(index, mASN1Object); + return NS_OK; +} + +/* wstring getCellText (in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetCellText(PRInt32 row, const PRUnichar *colID, + PRUnichar **_retval) +{ + nsCOMPtr object; + *_retval = nsnull; + char *col = NS_CONST_CAST(char *, NS_ConvertUCS2toUTF8(colID).get()); + nsresult rv = NS_OK; + if (strcmp(col, "certDataCol") == 0) { + rv = GetASN1ObjectAtIndex(row, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + //There's only one column for ASN1 dump. + rv = object->GetDisplayName(_retval); + } + return rv; +} + +/* void setOutliner (in nsIOutlinerBoxObject outliner); */ +NS_IMETHODIMP +nsNSSASN1Outliner::SetOutliner(nsIOutlinerBoxObject *outliner) +{ + mOutliner = outliner; + return NS_OK; +} + +/* void toggleOpenState (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::ToggleOpenState(PRInt32 index) +{ + nsCOMPtr object; + + nsresult rv = GetASN1ObjectAtIndex(index, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr sequence(do_QueryInterface(object)); + if (sequence == nsnull) + return NS_ERROR_FAILURE; + + PRBool showObjects; + sequence->GetShowObjects(&showObjects); + PRInt32 rowCountChange; + if (showObjects) { + rowCountChange = 1-CountNumberOfVisibleRows(object); + sequence->SetShowObjects(PR_FALSE); + } else { + sequence->SetShowObjects(PR_TRUE); + rowCountChange = CountNumberOfVisibleRows(object)-1; + } + if (mOutliner) + mOutliner->RowCountChanged(index, rowCountChange); + return NS_OK; +} + +/* void cycleHeader (in wstring colID, in nsIDOMElement elt); */ +NS_IMETHODIMP +nsNSSASN1Outliner::CycleHeader(const PRUnichar *colID, nsIDOMElement *elt) +{ + return NS_OK; +} + +/* void selectionChanged (); */ +NS_IMETHODIMP +nsNSSASN1Outliner::SelectionChanged() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void cycleCell (in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::CycleCell(PRInt32 row, const PRUnichar *colID) +{ + return NS_OK; +} + +/* boolean isEditable (in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsEditable(PRInt32 row, const PRUnichar *colID, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +/* void setCellText (in long row, in wstring colID, in wstring value); */ +NS_IMETHODIMP +nsNSSASN1Outliner::SetCellText(PRInt32 row, const PRUnichar *colID, + const PRUnichar *value) +{ + return NS_OK; +} + +/* void performAction (in wstring action); */ +NS_IMETHODIMP +nsNSSASN1Outliner::PerformAction(const PRUnichar *action) +{ + return NS_OK; +} + +/* void performActionOnRow (in wstring action, in long row); */ +NS_IMETHODIMP +nsNSSASN1Outliner::PerformActionOnRow(const PRUnichar *action, PRInt32 row) +{ + return NS_OK; +} + +/* void performActionOnCell (in wstring action, in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::PerformActionOnCell(const PRUnichar *action, PRInt32 row, + const PRUnichar *colID) +{ + return NS_OK; +} + + diff --git a/security/manager/pki/src/nsASN1Outliner.h b/security/manager/pki/src/nsASN1Outliner.h new file mode 100644 index 000000000000..0e96b235418c --- /dev/null +++ b/security/manager/pki/src/nsASN1Outliner.h @@ -0,0 +1,73 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#ifndef _NSSASNOUTLINER_H_ +#define _NSSASNOUTLINER_H_ + +#include "nscore.h" +#include "nsIX509Cert.h" +#include "nsIASN1Outliner.h" +#include "nsIOutlinerView.h" +#include "nsIOutlinerBoxObject.h" +#include "nsIOutlinerSelection.h" +#include "nsCOMPtr.h" + +//4bfaa9f0-1dd2-11b2-afae-a82cbaa0b606 +#define NS_NSSASN1OUTINER_CID { \ + 0x4bfaa9f0, \ + 0x1dd2, \ + 0x11b2, \ + {0xaf,0xae,0xa8,0x2c,0xba,0xa0,0xb6,0x06} \ + } + + +class nsNSSASN1Outliner : public nsIASN1Outliner +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIASN1OUTLINER + NS_DECL_NSIOUTLINERVIEW + + nsNSSASN1Outliner(); + virtual ~nsNSSASN1Outliner(); +protected: + PRUint32 CountNumberOfVisibleRows(nsIASN1Object *asn1Object); + nsresult GetASN1ObjectAtIndex(PRUint32 index, nsIASN1Object *sourceObject, + nsIASN1Object **retval); + PRInt32 GetParentOfObjectAtIndex(PRUint32 index, nsIASN1Object *sourceObject); + PRInt32 GetLevelsTilIndex(PRUint32 index, nsIASN1Object *sourceObject); + nsCOMPtr mASN1Object; + nsCOMPtr mSelection; + nsCOMPtr mOutliner; +}; +#endif //_NSSASNOUTLINER_H_ diff --git a/security/manager/pki/src/nsASN1Tree.cpp b/security/manager/pki/src/nsASN1Tree.cpp new file mode 100644 index 000000000000..8618b50a88f2 --- /dev/null +++ b/security/manager/pki/src/nsASN1Tree.cpp @@ -0,0 +1,488 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#include "nsASN1Outliner.h" +#include "nsIComponentManager.h" +#include "nsString.h" + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Outliner, nsIASN1Outliner, + nsIOutlinerView); + +nsNSSASN1Outliner::nsNSSASN1Outliner() +{ + NS_INIT_ISUPPORTS(); +} + +nsNSSASN1Outliner::~nsNSSASN1Outliner() +{ +} + +/* void loadASN1Structure (in nsIASN1Object asn1Object); */ +NS_IMETHODIMP +nsNSSASN1Outliner::LoadASN1Structure(nsIASN1Object *asn1Object) +{ + mASN1Object = asn1Object; + return NS_OK; +} + +/* wstring getDisplayData (in unsigned long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetDisplayData(PRUint32 index, PRUnichar **_retval) +{ + nsCOMPtr object; + GetASN1ObjectAtIndex(index, mASN1Object, getter_AddRefs(object)); + if (object) { + object->GetDisplayValue(_retval); + } else { + *_retval = nsnull; + } + return NS_OK; +} + +nsresult +nsNSSASN1Outliner::GetASN1ObjectAtIndex(PRUint32 index, + nsIASN1Object *sourceObject, + nsIASN1Object **retval) +{ + if (mASN1Object == nsnull) { + *retval = nsnull; + } else { + if (index == 0) { + *retval = sourceObject; + NS_IF_ADDREF(*retval); + return NS_OK; + } + // the source object better be an nsIASN1Sequence, otherwise, + // the index better be 1. If neither of these is ture, then + // someting bad has happened. + nsCOMPtr sequence = do_QueryInterface(sourceObject); + if (sequence == nsnull) { + //Something really bad has happened. bail out. + *retval = nsnull; + return NS_ERROR_FAILURE; + } else { + PRBool showObjects; + sequence->GetShowObjects(&showObjects); + if (!showObjects) { + *retval = nsnull; + return NS_OK; + } + nsCOMPtrasn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 numObjects; + asn1Objects->Count(&numObjects); + PRUint32 i; + nsCOMPtrisupports; + nsCOMPtrcurrObject; + PRUint32 numObjectsCounted = 0; + PRUint32 numObjToDisplay; + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + numObjToDisplay = CountNumberOfVisibleRows(currObject); + if ((numObjectsCounted+numObjToDisplay) >= index) { + return GetASN1ObjectAtIndex(index-numObjectsCounted-1, + currObject, retval); + } + numObjectsCounted += numObjToDisplay; + } + } + } + // We should never get here. + return NS_ERROR_FAILURE; +} + +PRUint32 +nsNSSASN1Outliner::CountNumberOfVisibleRows(nsIASN1Object *asn1Object) +{ + nsCOMPtr sequence; + PRUint32 count = 1; + + sequence = do_QueryInterface(asn1Object); + if (sequence) { + PRBool showObjects; + sequence->GetShowObjects(&showObjects); + if (showObjects) { + nsCOMPtr asn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 numObjects; + asn1Objects->Count(&numObjects); + PRUint32 i; + nsCOMPtr isupports; + nsCOMPtr currObject; + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + count += CountNumberOfVisibleRows(currObject); + } + } + } + return count; +} + +/* readonly attribute long rowCount; */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetRowCount(PRInt32 *aRowCount) +{ + if (mASN1Object) { + *aRowCount = CountNumberOfVisibleRows(mASN1Object); + } else { + *aRowCount = 0; + } + return NS_OK; +} + +/* attribute nsIOutlinerSelection selection; */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetSelection(nsIOutlinerSelection * *aSelection) +{ + *aSelection = mSelection; + NS_IF_ADDREF(*aSelection); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Outliner::SetSelection(nsIOutlinerSelection * aSelection) +{ + mSelection = aSelection; + return NS_OK; +} + +/* void getRowProperties (in long index, in nsISupportsArray properties); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetRowProperties(PRInt32 index, nsISupportsArray *properties) +{ + return NS_OK; +} + +/* void getCellProperties (in long row, in wstring colID, + in nsISupportsArray properties); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetCellProperties(PRInt32 row, const PRUnichar *colID, + nsISupportsArray *properties) +{ + return NS_OK; +} + +/* void getColumnProperties (in wstring colID, in nsIDOMElement colElt, + in nsISupportsArray properties); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetColumnProperties(const PRUnichar *colID, + nsIDOMElement *colElt, + nsISupportsArray *properties) +{ + return NS_OK; +} + +/* boolean isContainer (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsContainer(PRInt32 index, PRBool *_retval) +{ + nsCOMPtr object; + nsCOMPtr sequence; + + nsresult rv = GetASN1ObjectAtIndex(index, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + sequence = do_QueryInterface(object); + if (sequence != nsnull) { + sequence->GetProcessObjects(_retval); + } else { + *_retval = PR_FALSE; + } + return NS_OK; +} + +/* boolean isContainerOpen (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsContainerOpen(PRInt32 index, PRBool *_retval) +{ + nsCOMPtr object; + nsCOMPtr sequence; + + nsresult rv = GetASN1ObjectAtIndex(index, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + sequence = do_QueryInterface(object); + if (sequence == nsnull) { + *_retval = PR_FALSE; + } else { + sequence->GetShowObjects(_retval); + } + return NS_OK; +} + +/* boolean isContainerEmpty (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsContainerEmpty(PRInt32 index, PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +PRInt32 +nsNSSASN1Outliner::GetParentOfObjectAtIndex(PRUint32 index, + nsIASN1Object *sourceObject) +{ + if (index == 0) { + return -1; + } else { + PRUint32 numVisibleRows = CountNumberOfVisibleRows(sourceObject); + if (numVisibleRows > index) { + nsCOMPtrsequence(do_QueryInterface(sourceObject)); + if (sequence == nsnull) + return -2; + nsCOMPtrasn1Objects; + nsCOMPtrisupports; + nsCOMPtrcurrObject; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 indexCnt = 0; + PRUint32 i,numObjects; + asn1Objects->Count(&numObjects); + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + numVisibleRows = CountNumberOfVisibleRows(currObject); + if (numVisibleRows+indexCnt > index) { + //We're dealing with a sequence with visible elements + //that has the desired element. + PRInt32 subIndex = GetParentOfObjectAtIndex(index-indexCnt+1, + currObject); + if (subIndex == -1) { + return indexCnt+1; + } else if (subIndex == -2) { + return -2; + } else { + // This is a case where a subIndex was returned. + return indexCnt+1+subIndex; + } + } + indexCnt+=numVisibleRows; + if (indexCnt == index) { + // The passed in source object is the parent. + return -1; + } + } + }// the else case is an error, just let it fall through. + } + return -2; +} + +/* long getParentIndex (in long rowIndex); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval) +{ + *_retval = GetParentOfObjectAtIndex(rowIndex, mASN1Object); + return NS_OK; +} + +/* boolean hasNextSibling (in long rowIndex, in long afterIndex); */ +NS_IMETHODIMP +nsNSSASN1Outliner::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +PRInt32 +nsNSSASN1Outliner::GetLevelsTilIndex(PRUint32 index, + nsIASN1Object *sourceObject) +{ + if (index == 0) { + return 0; + } else { + nsCOMPtr sequence(do_QueryInterface(sourceObject)); + nsCOMPtrasn1Objects; + if (sequence == nsnull) + return -1; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + PRUint32 numObjects,i,indexCnt=0,numVisibleRows; + asn1Objects->Count(&numObjects); + nsCOMPtr isupports; + nsCOMPtr currObject; + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + numVisibleRows = CountNumberOfVisibleRows(currObject); + if ((numVisibleRows+indexCnt)>=index) { + PRInt32 numSubLayers; + numSubLayers = GetLevelsTilIndex(index-indexCnt-1, + currObject); + if (numSubLayers == -1) { + // This return value means the parent is not a child + // object, we're not adding any more layers to the nested + // levels. + return -1; + } else { + return 1+numSubLayers; + } + } + indexCnt += numVisibleRows; + } + } + return -2; +} + +/* long getLevel (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetLevel(PRInt32 index, PRInt32 *_retval) +{ + *_retval = GetLevelsTilIndex(index, mASN1Object); + return NS_OK; +} + +/* wstring getCellText (in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::GetCellText(PRInt32 row, const PRUnichar *colID, + PRUnichar **_retval) +{ + nsCOMPtr object; + *_retval = nsnull; + char *col = NS_CONST_CAST(char *, NS_ConvertUCS2toUTF8(colID).get()); + nsresult rv = NS_OK; + if (strcmp(col, "certDataCol") == 0) { + rv = GetASN1ObjectAtIndex(row, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + //There's only one column for ASN1 dump. + rv = object->GetDisplayName(_retval); + } + return rv; +} + +/* void setOutliner (in nsIOutlinerBoxObject outliner); */ +NS_IMETHODIMP +nsNSSASN1Outliner::SetOutliner(nsIOutlinerBoxObject *outliner) +{ + mOutliner = outliner; + return NS_OK; +} + +/* void toggleOpenState (in long index); */ +NS_IMETHODIMP +nsNSSASN1Outliner::ToggleOpenState(PRInt32 index) +{ + nsCOMPtr object; + + nsresult rv = GetASN1ObjectAtIndex(index, mASN1Object, + getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr sequence(do_QueryInterface(object)); + if (sequence == nsnull) + return NS_ERROR_FAILURE; + + PRBool showObjects; + sequence->GetShowObjects(&showObjects); + PRInt32 rowCountChange; + if (showObjects) { + rowCountChange = 1-CountNumberOfVisibleRows(object); + sequence->SetShowObjects(PR_FALSE); + } else { + sequence->SetShowObjects(PR_TRUE); + rowCountChange = CountNumberOfVisibleRows(object)-1; + } + if (mOutliner) + mOutliner->RowCountChanged(index, rowCountChange); + return NS_OK; +} + +/* void cycleHeader (in wstring colID, in nsIDOMElement elt); */ +NS_IMETHODIMP +nsNSSASN1Outliner::CycleHeader(const PRUnichar *colID, nsIDOMElement *elt) +{ + return NS_OK; +} + +/* void selectionChanged (); */ +NS_IMETHODIMP +nsNSSASN1Outliner::SelectionChanged() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void cycleCell (in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::CycleCell(PRInt32 row, const PRUnichar *colID) +{ + return NS_OK; +} + +/* boolean isEditable (in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::IsEditable(PRInt32 row, const PRUnichar *colID, + PRBool *_retval) +{ + *_retval = PR_FALSE; + return NS_OK; +} + +/* void setCellText (in long row, in wstring colID, in wstring value); */ +NS_IMETHODIMP +nsNSSASN1Outliner::SetCellText(PRInt32 row, const PRUnichar *colID, + const PRUnichar *value) +{ + return NS_OK; +} + +/* void performAction (in wstring action); */ +NS_IMETHODIMP +nsNSSASN1Outliner::PerformAction(const PRUnichar *action) +{ + return NS_OK; +} + +/* void performActionOnRow (in wstring action, in long row); */ +NS_IMETHODIMP +nsNSSASN1Outliner::PerformActionOnRow(const PRUnichar *action, PRInt32 row) +{ + return NS_OK; +} + +/* void performActionOnCell (in wstring action, in long row, in wstring colID); */ +NS_IMETHODIMP +nsNSSASN1Outliner::PerformActionOnCell(const PRUnichar *action, PRInt32 row, + const PRUnichar *colID) +{ + return NS_OK; +} + + diff --git a/security/manager/pki/src/nsASN1Tree.h b/security/manager/pki/src/nsASN1Tree.h new file mode 100644 index 000000000000..0e96b235418c --- /dev/null +++ b/security/manager/pki/src/nsASN1Tree.h @@ -0,0 +1,73 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#ifndef _NSSASNOUTLINER_H_ +#define _NSSASNOUTLINER_H_ + +#include "nscore.h" +#include "nsIX509Cert.h" +#include "nsIASN1Outliner.h" +#include "nsIOutlinerView.h" +#include "nsIOutlinerBoxObject.h" +#include "nsIOutlinerSelection.h" +#include "nsCOMPtr.h" + +//4bfaa9f0-1dd2-11b2-afae-a82cbaa0b606 +#define NS_NSSASN1OUTINER_CID { \ + 0x4bfaa9f0, \ + 0x1dd2, \ + 0x11b2, \ + {0xaf,0xae,0xa8,0x2c,0xba,0xa0,0xb6,0x06} \ + } + + +class nsNSSASN1Outliner : public nsIASN1Outliner +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIASN1OUTLINER + NS_DECL_NSIOUTLINERVIEW + + nsNSSASN1Outliner(); + virtual ~nsNSSASN1Outliner(); +protected: + PRUint32 CountNumberOfVisibleRows(nsIASN1Object *asn1Object); + nsresult GetASN1ObjectAtIndex(PRUint32 index, nsIASN1Object *sourceObject, + nsIASN1Object **retval); + PRInt32 GetParentOfObjectAtIndex(PRUint32 index, nsIASN1Object *sourceObject); + PRInt32 GetLevelsTilIndex(PRUint32 index, nsIASN1Object *sourceObject); + nsCOMPtr mASN1Object; + nsCOMPtr mSelection; + nsCOMPtr mOutliner; +}; +#endif //_NSSASNOUTLINER_H_ diff --git a/security/manager/pki/src/nsNSSDialogs.cpp b/security/manager/pki/src/nsNSSDialogs.cpp index 8a1647e6a4a0..e2714b38f914 100644 --- a/security/manager/pki/src/nsNSSDialogs.cpp +++ b/security/manager/pki/src/nsNSSDialogs.cpp @@ -116,7 +116,8 @@ NS_IMPL_THREADSAFE_ISUPPORTS6(nsNSSDialogs, nsINSSDialogs, nsISecurityWarningDialogs, nsIBadCertListener, nsICertificateDialogs, - nsIClientAuthDialogs) + nsIClientAuthDialogs); + nsresult nsNSSDialogs::Init() { diff --git a/security/manager/pki/src/nsPKIModule.cpp b/security/manager/pki/src/nsPKIModule.cpp index bc0d7e675dc4..277aa31c765b 100644 --- a/security/manager/pki/src/nsPKIModule.cpp +++ b/security/manager/pki/src/nsPKIModule.cpp @@ -26,9 +26,11 @@ #include "nsNSSDialogs.h" #include "nsPKIParamBlock.h" +#include "nsASN1Outliner.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNSSDialogs, Init) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPKIParamBlock, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSASN1Outliner) static nsModuleComponentInfo components[] = { @@ -39,6 +41,13 @@ static nsModuleComponentInfo components[] = nsNSSDialogsConstructor }, + { + "ASN1 Outliner", + NS_NSSASN1OUTINER_CID, + NS_ASN1OUTLINER_CONTRACTID, + nsNSSASN1OutlinerConstructor + }, + { "PKI Parm Block", NS_PKIPARAMBLOCK_CID, NS_PKIPARAMBLOCK_CONTRACTID, diff --git a/security/manager/pki/src/nsPKIParamBlock.cpp b/security/manager/pki/src/nsPKIParamBlock.cpp index 5ad6812e4a69..05410ce70dcb 100644 --- a/security/manager/pki/src/nsPKIParamBlock.cpp +++ b/security/manager/pki/src/nsPKIParamBlock.cpp @@ -40,7 +40,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsPKIParamBlock, nsIPKIParamBlock, nsIDialogParamBlock) -nsPKIParamBlock::nsPKIParamBlock() : mSupports(nsnull),mNumISupports(0) +nsPKIParamBlock::nsPKIParamBlock() { NS_INIT_REFCNT(); } @@ -54,17 +54,6 @@ nsPKIParamBlock::Init() nsPKIParamBlock::~nsPKIParamBlock() { - if (mNumISupports > 0) { - NS_ASSERTION (mSupports, "mNumISupports and mSupports out of sync"); - if (mSupports) { - PRIntn i; - - for (i=0; iSetString(inIndex, inString); } -/* void setNumberISupports (in PRInt32 numISupports); */ -NS_IMETHODIMP -nsPKIParamBlock::SetNumberISupports(PRInt32 numISupports) -{ - if (mSupports) { - return NS_ERROR_ALREADY_INITIALIZED; - } - - NS_ASSERTION(numISupports > 0, "passing in invalid number"); - mNumISupports = numISupports; - mSupports = new nsISupports*[mNumISupports]; - if (mSupports == nsnull) { - mNumISupports = 0; - return NS_ERROR_OUT_OF_MEMORY; - } - memset(mSupports, 0, sizeof(nsISupports*)*mNumISupports); - return NS_OK; -} - /* void setISupportAtIndex (in PRInt32 index, in nsISupports object); */ NS_IMETHODIMP nsPKIParamBlock::SetISupportAtIndex(PRInt32 index, nsISupports *object) { if (!mSupports) { - mNumISupports = kNumISupports; - mSupports = new nsISupports*[mNumISupports]; + mSupports = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID); if (mSupports == nsnull) { return NS_ERROR_OUT_OF_MEMORY; } - memset(mSupports, 0, sizeof(nsISupports*)*mNumISupports); } - nsresult rv = InBounds(index, mNumISupports); - if (rv != NS_OK) - return rv; - - mSupports[index] = object; - NS_IF_ADDREF(mSupports[index]); - return NS_OK; + return mSupports->InsertElementAt(object, index-1); } /* nsISupports getISupportAtIndex (in PRInt32 index); */ @@ -144,12 +106,8 @@ NS_IMETHODIMP nsPKIParamBlock::GetISupportAtIndex(PRInt32 index, nsISupports **_retval) { NS_ENSURE_ARG(_retval); - nsresult rv = InBounds(index, mNumISupports); - if (rv != NS_OK) - return rv; - *_retval = mSupports[index]; - NS_IF_ADDREF(*_retval); + *_retval = mSupports->ElementAt(index-1); return NS_OK; } diff --git a/security/manager/pki/src/nsPKIParamBlock.h b/security/manager/pki/src/nsPKIParamBlock.h index 6b13e456a145..5308ab40fc67 100644 --- a/security/manager/pki/src/nsPKIParamBlock.h +++ b/security/manager/pki/src/nsPKIParamBlock.h @@ -37,6 +37,7 @@ #include "nsCOMPtr.h" #include "nsIPKIParamBlock.h" #include "nsIDialogParamBlock.h" +#include "nsISupportsArray.h" #define NS_PKIPARAMBLOCK_CID \ { 0x0bec75a8, 0x1dd2, 0x11b2, \ @@ -48,7 +49,6 @@ class nsPKIParamBlock : public nsIPKIParamBlock, public nsIDialogParamBlock { public: - enum { kNumISupports = 4 }; nsPKIParamBlock(); virtual ~nsPKIParamBlock(); @@ -58,16 +58,8 @@ public: NS_DECL_NSIDIALOGPARAMBLOCK NS_DECL_ISUPPORTS private: - nsresult InBounds( PRInt32 inIndex, PRInt32 inMax ) - { - if ( inIndex >= 0 && inIndex< inMax ) - return NS_OK; - else - return NS_ERROR_ILLEGAL_VALUE; - } nsCOMPtr mDialogParamBlock; - nsISupports **mSupports; - PRIntn mNumISupports; + nsCOMPtr mSupports; }; #endif //_NSPKIPARAMBLOCK_ diff --git a/security/manager/ssl/public/nsIX509Cert.idl b/security/manager/ssl/public/nsIX509Cert.idl index e4727893d67e..6082d9e7cf0c 100644 --- a/security/manager/ssl/public/nsIX509Cert.idl +++ b/security/manager/ssl/public/nsIX509Cert.idl @@ -34,7 +34,7 @@ */ #include "nsISupports.idl" -#include "nsIEnumerator.idl" +#include "nsISupportsArray.idl" [scriptable, uuid(e701dfd8-1dd1-11b2-a172-ffa6cc6156ad)] interface nsIX509CertValidity : nsISupports { @@ -42,6 +42,68 @@ interface nsIX509CertValidity : nsISupports { readonly attribute PRTime notAfter; }; +// +// Overview of how this ASN1 interface is intended to +// work. +// +// First off, the nsIASN1Sequence is any type in ASN1 +// that consists of sub-elements (ie SEQUENCE, SET) +// nsIASN1Printable Items are all the other types that +// can be viewed by themselves without interpreting further. +// Examples would include INTEGER, UTF-8 STRING, OID. +// These are not intended to directly reflect the numberous +// types that exist in ASN1, but merely an interface to ease +// producing a tree display the ASN1 structure of any DER +// object. +// + +[scriptable, uuid(ba8bf582-1dd1-11b2-898c-f40246bc9a63)] +interface nsIASN1Object : nsISupports { + const unsigned long ASN1_END_CONTENTS = 0; + const unsigned long ASN1_BOOLEAN = 1; + const unsigned long ASN1_INTEGER = 2; + const unsigned long ASN1_BIT_STRING = 3; + const unsigned long ASN1_OCTET_STRING = 4; + const unsigned long ASN1_NULL = 5; + const unsigned long ASN1_OBJECT_ID = 6; + const unsigned long ASN1_ENUMERATED = 10; + const unsigned long ASN1_UTF8_STRING = 12; + const unsigned long ASN1_SEQUENCE = 16; + const unsigned long ASN1_SET = 17; + const unsigned long ASN1_PRINTABLE_STRING = 19; + const unsigned long ASN1_T61_STRING = 20; + const unsigned long ASN1_IA5_STRING = 22; + const unsigned long ASN1_UTC_TIME = 23; + const unsigned long ASN1_GEN_TIME = 24; + const unsigned long ASN1_VISIBLE_STRING = 26; + const unsigned long ASN1_UNIVERSAL_STRING = 28; + const unsigned long ASN1_BMP_STRING = 30; + const unsigned long ASN1_HIGH_TAG_NUMBER = 31; + const unsigned long ASN1_CONTEXT_SPECIFIC = 32; + const unsigned long ASN1_APPLICATION = 33; + const unsigned long ASN1_PRIVATE = 34; + + // This will be either one of the const + // values above. + attribute unsigned long type; + attribute unsigned long tag; + attribute wstring displayName; + attribute wstring displayValue; +}; + +[scriptable, uuid(b6b957e6-1dd1-11b2-89d7-e30624f50b00)] +interface nsIASN1Sequence : nsIASN1Object { + attribute nsISupportsArray ASN1Objects; + attribute boolean processObjects; + attribute boolean showObjects; +}; + +[scriptable, uuid(114e1142-1dd2-11b2-ac26-b6db19d9184a)] +interface nsIASN1PrintableItem : nsIASN1Object { + [noscript] void setData(in charPtr data, in unsigned long len); + [noscript] void getData(out charPtr data, out unsigned long len); +}; + [scriptable, uuid(f0980f60-ee3d-11d4-998b-00b0d02354a0)] interface nsIX509Cert : nsISupports { @@ -89,7 +151,7 @@ interface nsIX509Cert : nsISupports { /* * accessors for certs */ - nsIEnumerator getChain(); + nsISupportsArray getChain(); void getUsages(out PRUint32 verified, out PRUint32 count, @@ -105,6 +167,13 @@ interface nsIX509Cert : nsISupports { */ void view(); + /* + * 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; + [noscript] unsigned long getRawDER(out charPtr result); }; diff --git a/security/manager/ssl/resources/locale/en-US/pipnss.properties b/security/manager/ssl/resources/locale/en-US/pipnss.properties index 8242d785651d..0d3ce8aa8d0a 100644 --- a/security/manager/ssl/resources/locale/en-US/pipnss.properties +++ b/security/manager/ssl/resources/locale/en-US/pipnss.properties @@ -16,7 +16,10 @@ # Copyright (C) 1998 Netscape Communications Corporation. All # Rights Reserved. # -# Contributor(s): +# Contributor(s): +# Javier Delgadillo +# Brian Ryner +# Terry Hayes # SignedBy=Signed by %S @@ -43,6 +46,61 @@ VerifyUserImport=User Import Cert VerifyCAVerifier=CA Verifier VerifyStatusResponder=Status Responder Certificate VerifyAnyCA=Any Certificate Authority +#These are the strings set for the ASN1 objects in a certificate. +CertDumpCertificate=Certificate +CertDumpVersion=Version +CertDumpVersion1=Version 1 +CertDumpVersion2=Version 2 +CertDumpVersion3=Version 3 +CertDumpSerialNo=Serial Number +CertDumpOID=Object Identifier +CertDumpMD2WithRSA=PKCS #1 MD2 With RSA Encryption +CertDumpMD5WithRSA=PKCS #1 MD5 With RSA Encryption +CertDumpSHA1WithRSA=PKCS #1 SHA-1 With RSA Encryption +CertDumpDefOID=Object Identifier (%S) +CertDumpNULL=NULL +CertDumpIssuer=Issuer +CertDumpSubject=Subect +CertDumpRDN=Relative Distinguished Name +CertDumpATV=Attribute Type and Value +CertDumpAVACountry=Country Name +CertDumpAVAState=State Or Province Name +CertDumpAVALocality=Locality Name +CertDumpAVAOrg=Organization Name +CertDumpAVAOU=Organizational Unit Name +CertDumpAVACN=Common Name +CertDumpUserID=RFC1274 User ID +CertDumpPK9Email=PKCS #9 Email Address +CertDumpAVADN=Distinguished Name Qualifier +CertDumpAVADC=Domain Component +CertDumpValidity=Validity +CertDumpNotBefore=Not Before +CertDumpNotAfter=Not After +CertDumpSPKI=Subject Public Key Info +CertDumpSPKIAlg=Subject Public Key Algorithm +CertDumpAlgID=Algorithm Identifier +CertDumpParams=Algorithm Parameters +CertDumpRSAEncr=PKCS #1 RSA Encryption +CertDumpIssuerUniqueID=Issuer Unique ID +CertDumpSubjPubKey=Subject's Public Key +CertDumpSubjectUniqueID=Subject Unique ID +CertDumpExtensions=Extensions +CertDumpCertType=Netscape Ceritficate Type +CertDumpKeyUsage=Certifcate Key Usage +CertDumpAuthKeyID=Certificate Authority Key Identifier +CertDumpCertTypeEmail=Email +CertDumpEmailCA=Email Certificate Authority +CertDumpKUSign=Signing +CertDumpKUNonRep=Non-repudiation +CertDumpKUEnc=Key Encipherment +CertDumpKUDEnc=Data Encipherment +CertDumpKUKA=Key Agreement +CertDumpKUCertSign=Certificate Signer +CertDumpKUCRLSigner=CRL Signer +CertDumpCritical=Critical +CertDumpNonCritical=Not Critical +CertDumpSigAlg=Certificate Signature Algorithm +CertDumpCertSig=Certificate Signature Value VerifySSLClient_p=Client VerifySSLServer_p=Server VerifySSLStepUp_p=Step-up diff --git a/security/manager/ssl/src/Makefile.in b/security/manager/ssl/src/Makefile.in index 285a4a9055fe..c30488ce5911 100644 --- a/security/manager/ssl/src/Makefile.in +++ b/security/manager/ssl/src/Makefile.in @@ -60,6 +60,7 @@ CPPSRCS = \ nsPK11TokenDB.cpp \ nsNSSCertificate.cpp \ nsPKCS12Blob.cpp \ + nsNSSASN1Object.cpp \ nsCertOutliner.cpp \ $(NULL) diff --git a/security/manager/ssl/src/nsNSSASN1Object.cpp b/security/manager/ssl/src/nsNSSASN1Object.cpp new file mode 100644 index 000000000000..d80b3ffa5398 --- /dev/null +++ b/security/manager/ssl/src/nsNSSASN1Object.cpp @@ -0,0 +1,474 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#include "nsNSSASN1Object.h" +#include "nsIComponentManager.h" +#include "secasn1.h" + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Sequence, nsIASN1Sequence, + nsIASN1Object); +NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1PrintableItem, nsIASN1PrintableItem, + nsIASN1Object); + +// This function is used to interpret an integer that +// was encoded in a DER buffer. This function is used +// when converting a DER buffer into a nsIASN1Object +// structure. This interprets the buffer in data +// as defined by the DER (Distinguised Encoding Rules) of +// ASN1. +static int +getInteger256(unsigned char *data, unsigned int nb) +{ + int val; + + switch (nb) { + case 1: + val = data[0]; + break; + case 2: + val = (data[0] << 8) | data[1]; + break; + case 3: + val = (data[0] << 16) | (data[1] << 8) | data[2]; + break; + case 4: + val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + break; + default: + return -1; + } + + return val; +} + +// This function is used to retrieve the lenght of a DER encoded +// item. It looks to see if this a multibyte length and then +// interprets the buffer accordingly to get the actual length value. +// This funciton is used mostly while parsing the DER headers. +// +// A DER encoded item has the following structure: +// +// +static PRInt32 +getDERItemLength(unsigned char *data, unsigned char *end, + unsigned long *bytesUsed, PRBool *indefinite) +{ + unsigned char lbyte = *data++; + PRInt32 length = -1; + + *indefinite = PR_FALSE; + if (lbyte >= 0x80) { + // Multibyte length + unsigned nb = (unsigned) (lbyte & 0x7f); + if (nb > 4) { + return -1; + } + if (nb > 0) { + + if ((data+nb) > end) { + return -1; + } + length = getInteger256(data, nb); + if (length < 0) + return -1; + } else { + *indefinite = PR_TRUE; + length = 0; + } + *bytesUsed = nb+1; + } else { + length = lbyte; + *bytesUsed = 1; + } + return length; +} + +static nsresult +buildASN1ObjectFromDER(unsigned char *data, + unsigned char *end, + nsIASN1Sequence *parent) +{ + nsresult rv; + nsCOMPtr sequence; + nsCOMPtr printableItem; + nsCOMPtr asn1Obj; + nsCOMPtr parentObjects; + + NS_ENSURE_ARG_POINTER(parent); + if (data >= end) + return NS_OK; + + unsigned char code, tagnum; + + // A DER item has the form of |tag|len|data + // tag is one byte and describes the type of elment + // we are dealing with. + // len is a DER encoded int telling us how long the data is + // data is a buffer that is len bytes long and has to be + // interpreted according to its type. + unsigned long bytesUsed; + PRBool indefinite; + PRInt32 len; + PRUint32 type; + + if (parent == nsnull) { + parent = new nsNSSASN1Sequence(); + NS_IF_ADDREF(parent); + } + if (parent == nsnull) + return NS_ERROR_FAILURE; + + rv = parent->GetASN1Objects(getter_AddRefs(parentObjects)); + if (NS_FAILED(rv) || parentObjects == nsnull) + return NS_ERROR_FAILURE; + while (data < end) { + code = *data; + tagnum = code & SEC_ASN1_TAGNUM_MASK; + + /* + * NOTE: This code does not (yet) handle the high-tag-number form! + */ + if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) { + return NS_ERROR_FAILURE; + } + data++; + len = getDERItemLength(data, end, &bytesUsed, &indefinite); + data += bytesUsed; + if ((len < 0) || ((data+len) > end)) + return NS_ERROR_FAILURE; + + if (code & SEC_ASN1_CONSTRUCTED) { + if (len > 0 || indefinite) { + sequence = new nsNSSASN1Sequence(); + switch (code & SEC_ASN1_CLASS_MASK) { + case SEC_ASN1_UNIVERSAL: + type = tagnum; + break; + case SEC_ASN1_APPLICATION: + type = nsIASN1Object::ASN1_APPLICATION; + break; + case SEC_ASN1_CONTEXT_SPECIFIC: + type = nsIASN1Object::ASN1_CONTEXT_SPECIFIC; + break; + case SEC_ASN1_PRIVATE: + type = nsIASN1Object::ASN1_PRIVATE; + break; + default: + NS_ASSERTION(0,"Bad DER"); + return NS_ERROR_FAILURE; + } + sequence->SetTag(tagnum); + sequence->SetType(type); + rv = buildASN1ObjectFromDER(data, (len == 0) ? end : data + len, + sequence); + asn1Obj = sequence; + } + } else { + printableItem = new nsNSSASN1PrintableItem(); + + asn1Obj = printableItem; + asn1Obj->SetType(tagnum); + asn1Obj->SetTag(tagnum); + printableItem->SetData((char*)data, len); + } + data += len; + parentObjects->AppendElement(asn1Obj); + } + + return NS_OK; +} + +nsresult +CreateFromDER(unsigned char *data, + unsigned int len, + nsIASN1Object **retval) +{ + nsCOMPtr sequence = new nsNSSASN1Sequence; + *retval = nsnull; + + nsresult rv = buildASN1ObjectFromDER(data, data+len, sequence); + + if (NS_SUCCEEDED(rv)) { + // The actual object will be the first element inserted + // into the sequence of the sequence variable we created. + nsCOMPtr elements; + + sequence->GetASN1Objects(getter_AddRefs(elements)); + nsCOMPtr isupports = dont_AddRef(elements->ElementAt(0)); + nsCOMPtr asn1Obj(do_QueryInterface(isupports)); + *retval = asn1Obj; + if (*retval == nsnull) + return NS_ERROR_FAILURE; + + NS_ADDREF(*retval); + + } + return rv; +} + +nsNSSASN1Sequence::nsNSSASN1Sequence() : mProcessObjects(PR_TRUE), + mShowObjects(PR_TRUE) +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ +} + +nsNSSASN1Sequence::~nsNSSASN1Sequence() +{ + /* destructor code */ +} + +/* attribute nsISupportsArray ASN1Objects; */ +NS_IMETHODIMP +nsNSSASN1Sequence::GetASN1Objects(nsISupportsArray * *aASN1Objects) +{ + if (mASN1Objects == nsnull) { + mASN1Objects = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID); + } + *aASN1Objects = mASN1Objects; + NS_IF_ADDREF(*aASN1Objects); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::SetASN1Objects(nsISupportsArray * aASN1Objects) +{ + mASN1Objects = aASN1Objects; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::GetTag(PRUint32 *aTag) +{ + *aTag = mTag; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::SetTag(PRUint32 aTag) +{ + mTag = aTag; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::GetType(PRUint32 *aType) +{ + *aType = mType; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::SetType(PRUint32 aType) +{ + mType = aType; + return NS_OK; +} + +/* attribute wstring displayName; */ +NS_IMETHODIMP +nsNSSASN1Sequence::GetDisplayName(PRUnichar * *aDisplayName) +{ + NS_ENSURE_ARG_POINTER(aDisplayName); + *aDisplayName = mDisplayName.ToNewUnicode(); + return (*aDisplayName) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::SetDisplayName(const PRUnichar * aDisplayName) +{ + mDisplayName.Assign(aDisplayName); + return NS_OK; +} + +/* attribute wstring displayValue; */ +NS_IMETHODIMP +nsNSSASN1Sequence::GetDisplayValue(PRUnichar * *aDisplayValue) +{ + NS_ENSURE_ARG_POINTER(aDisplayValue); + *aDisplayValue = mDisplayValue.ToNewUnicode(); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::SetDisplayValue(const PRUnichar * aDisplayValue) +{ + mDisplayValue.Assign(aDisplayValue); + return NS_OK; +} + +/* attribute boolean processObjects; */ +NS_IMETHODIMP +nsNSSASN1Sequence::GetProcessObjects(PRBool *aProcessObjects) +{ + NS_ENSURE_ARG_POINTER(aProcessObjects); + *aProcessObjects = mProcessObjects; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::SetProcessObjects(PRBool aProcessObjects) +{ + mProcessObjects = aProcessObjects; + SetShowObjects(mProcessObjects); + return NS_OK; +} + +/* attribute boolean showObjects; */ +NS_IMETHODIMP +nsNSSASN1Sequence::GetShowObjects(PRBool *aShowObjects) +{ + NS_ENSURE_ARG_POINTER(aShowObjects); + *aShowObjects = mShowObjects; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Sequence::SetShowObjects(PRBool aShowObjects) +{ + mShowObjects = aShowObjects; + return NS_OK; +} + + +nsNSSASN1PrintableItem::nsNSSASN1PrintableItem() : mData(nsnull), + mLen(0) +{ + NS_INIT_ISUPPORTS(); + /* member initializers and constructor code */ +} + +nsNSSASN1PrintableItem::~nsNSSASN1PrintableItem() +{ + /* destructor code */ + if (mData) + nsMemory::Free(mData); +} + +/* readonly attribute wstring value; */ +NS_IMETHODIMP +nsNSSASN1PrintableItem::GetDisplayValue(PRUnichar * *aValue) +{ + *aValue = mValue.ToNewUnicode(); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::SetDisplayValue(const PRUnichar * aValue) +{ + mValue.Assign(aValue); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::GetTag(PRUint32 *aTag) +{ + *aTag = mTag; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::SetTag(PRUint32 aTag) +{ + mTag = aTag; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::GetType(PRUint32 *aType) +{ + *aType = mType; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::SetType(PRUint32 aType) +{ + mType = aType; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::SetData(char *data, PRUint32 len) +{ + if (len > 0) { + if (mData) { + if (mLen < len) + nsMemory::Realloc(mData, len); + } else { + mData = (unsigned char*)nsMemory::Alloc(len); + } + + if (mData == nsnull) + return NS_ERROR_FAILURE; + nsCRT::memcpy(mData, data, len); + } else if (len == 0) { + if (mData) { + nsMemory::Free(mData); + mData = nsnull; + } + } else { + NS_ASSERTION(0,"Passed in invalid buffer length to SetData"); + return NS_ERROR_FAILURE; + } + mLen = len; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::GetData(char **outData, PRUint32 *outLen) +{ + NS_ENSURE_ARG_POINTER(outData); + NS_ENSURE_ARG_POINTER(outLen); + + *outData = (char*)mData; + *outLen = mLen; + return NS_OK; +} + +/* attribute wstring displayName; */ +NS_IMETHODIMP +nsNSSASN1PrintableItem::GetDisplayName(PRUnichar * *aDisplayName) +{ + NS_ENSURE_ARG_POINTER(aDisplayName); + *aDisplayName = mDisplayName.ToNewUnicode(); + return (*aDisplayName) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsNSSASN1PrintableItem::SetDisplayName(const PRUnichar * aDisplayName) +{ + mDisplayName.Assign(aDisplayName); + return NS_OK; +} + diff --git a/security/manager/ssl/src/nsNSSASN1Object.h b/security/manager/ssl/src/nsNSSASN1Object.h new file mode 100644 index 000000000000..8b4a35900af7 --- /dev/null +++ b/security/manager/ssl/src/nsNSSASN1Object.h @@ -0,0 +1,92 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#ifndef _NSSASN_H_ +#define _NSSASN_H_ + +#include "nscore.h" +#include "nsIX509Cert.h" +#include "nsIASN1Outliner.h" +#include "nsIOutlinerView.h" +#include "nsIOutlinerSelection.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +// +// Read comments in nsIX509Cert.idl for a description of the desired +// purpose for this ASN1 interface implementation. +// + +class nsNSSASN1Sequence : public nsIASN1Sequence +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIASN1SEQUENCE + NS_DECL_NSIASN1OBJECT + + nsNSSASN1Sequence(); + virtual ~nsNSSASN1Sequence(); + /* additional members */ +private: + nsCOMPtr mASN1Objects; + nsString mDisplayName; + nsString mDisplayValue; + PRUint32 mType; + PRUint32 mTag; + PRBool mProcessObjects; + PRBool mShowObjects; +}; + +class nsNSSASN1PrintableItem : public nsIASN1PrintableItem +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIASN1PRINTABLEITEM + NS_DECL_NSIASN1OBJECT + + nsNSSASN1PrintableItem(); + virtual ~nsNSSASN1PrintableItem(); + /* additional members */ +private: + nsString mDisplayName; + nsString mValue; + PRUint32 mType; + PRUint32 mTag; + unsigned char *mData; + PRUint32 mLen; +}; + +nsresult CreateFromDER(unsigned char *data, + unsigned int len, + nsIASN1Object **retval); +#endif //_NSSASN_H_ diff --git a/security/manager/ssl/src/nsNSSCertificate.cpp b/security/manager/ssl/src/nsNSSCertificate.cpp index c521b6a43e5a..b2a0f1bbe276 100644 --- a/security/manager/ssl/src/nsNSSCertificate.cpp +++ b/security/manager/ssl/src/nsNSSCertificate.cpp @@ -32,11 +32,12 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: nsNSSCertificate.cpp,v 1.16 2001/05/01 23:23:20 mcgreer%netscape.com Exp $ + * $Id: nsNSSCertificate.cpp,v 1.17 2001/05/02 05:38:26 javi%netscape.com Exp $ */ #include "prmem.h" #include "prerror.h" +#include "prprf.h" #include "nsNSSComponent.h" // for PIPNSS string bundle calls. #include "nsCOMPtr.h" @@ -46,16 +47,20 @@ #include "nsPKCS12Blob.h" #include "nsIX509Cert.h" #include "nsINSSDialogs.h" +#include "nsNSSASN1Object.h" #include "nsString.h" -#include "nsILocaleService.h" +#include "nsXPIDLString.h" #include "nsIDateTimeFormat.h" #include "nsDateTimeFormatCID.h" +#include "nsILocaleService.h" #include "pk11func.h" #include "certdb.h" #include "cert.h" #include "secerr.h" #include "nssb64.h" +#include "secasn1.h" +#include "secder.h" #ifdef PR_LOGGING extern PRLogModuleInfo* gPIPNSSLog; @@ -609,7 +614,7 @@ nsNSSCertificate::GetOrganizationalUnit(PRUnichar **aOrganizationalUnit) * nsIEnumerator getChain(); */ NS_IMETHODIMP -nsNSSCertificate::GetChain(nsIEnumerator **_rvChain) +nsNSSCertificate::GetChain(nsISupportsArray **_rvChain) { nsresult rv; CERTCertListNode *node; @@ -632,7 +637,9 @@ nsNSSCertificate::GetChain(nsIEnumerator **_rvChain) nsCOMPtr cert = new nsNSSCertificate(node->cert); array->AppendElement(cert); } - rv = array->Enumerate(_rvChain); + *_rvChain = array; + NS_IF_ADDREF(*_rvChain); + rv = NS_OK; done: if (nssChain) CERT_DestroyCertList(nssChain); @@ -1002,6 +1009,477 @@ verify_failed: return NS_OK; } +static nsresult +GetIntValue(SECItem *versionItem, + unsigned long *version) +{ + SECStatus srv; + + srv = SEC_ASN1DecodeInteger(versionItem,version); + if (srv != SECSuccess) { + NS_ASSERTION(0,"Could not decode version of cert"); + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +static nsresult +ProcessVersion(SECItem *versionItem, + nsINSSComponent *nssComponent, + nsIASN1PrintableItem **retItem) +{ + nsresult rv; + nsString text; + nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion").get(), + text); + rv = printableItem->SetDisplayName(text.get()); + if (NS_FAILED(rv)) + return rv; + + // Now to figure out what version this certificate is. + unsigned long version; + + rv = GetIntValue(versionItem, &version); + if (NS_FAILED(rv)) + return rv; + + switch (version){ + case 0: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion1").get(), + text); + break; + case 1: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion2").get(), + text); + break; + case 2: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion3").get(), + text); + break; + default: + NS_ASSERTION(0,"Bad value for cert version"); + rv = NS_ERROR_FAILURE; + } + + if (NS_FAILED(rv)) + return rv; + + rv = printableItem->SetDisplayValue(text.get()); + if (NS_FAILED(rv)) + return rv; + + *retItem = printableItem; + NS_ADDREF(*retItem); + return NS_OK; +} + +nsresult +ProcessSerialNumber(SECItem *serialItem, + nsINSSComponent *nssComponent, + nsIASN1PrintableItem **retItem) +{ + nsresult rv; + nsString text; + nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); + + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSerialNo").get(), + text); + if (NS_FAILED(rv)) + return rv; + + rv = printableItem->SetDisplayName(text.get()); + if (NS_FAILED(rv)) + return rv; + + nsXPIDLCString serialNumber; + serialNumber = CERT_Hexify(serialItem, 1); + if (serialNumber == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + rv = printableItem->SetDisplayValue(NS_ConvertASCIItoUCS2(serialNumber).get()); + *retItem = printableItem; + NS_ADDREF(*retItem); + return rv; +} + +static nsresult +GetDefaultOIDFormat(SECItem *oid, + nsString &outString) +{ + char buf[300]; + int len, written; + + unsigned long val = oid->data[0]; + unsigned int i = val % 40; + val /= 40; + written = PR_snprintf(buf, 300, "%lu %u ", val, i); + if (written < 0) + return NS_ERROR_FAILURE; + len = written; + + val = 0; + for (i = 1; i < oid->len; ++i) { + // In this loop, we have to parse a DER formatted + // If the first bit is a 1, then the integer is + // represented by more than one byte. If the + // first bit is set then we continue on and add + // the values of the later bytes until we get + // a byte without the first bit set. + unsigned long j; + + j = oid->data[i]; + val = (val << 7) | (j & 0x7f); + if (j & 0x80) + continue; + written = PR_snprintf(&buf[len], sizeof(buf)-len, "%lu ", val); + if (written < 0) + return NS_ERROR_FAILURE; + + len += written; + NS_ASSERTION(len < sizeof(buf), "OID data to big to display in 300 chars."); + val = 0; + } + + outString = NS_ConvertASCIItoUCS2(buf).get(); + return NS_OK; +} + +static nsresult +GetOIDText(SECItem *oid, nsINSSComponent *nssComponent, nsString &text) +{ + nsresult rv; + SECOidTag oidTag = SECOID_FindOIDTag(oid); + + switch (oidTag) { + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpMD2WithRSA").get(), + text); + break; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpMD5WithRSA").get(), + text); + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSHA1WithRSA").get(), + text); + break; + case SEC_OID_AVA_COUNTRY_NAME: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVACountry").get(), + text); + break; + case SEC_OID_AVA_COMMON_NAME: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVACN").get(), + text); + break; + case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVAOU").get(), + text); + break; + case SEC_OID_AVA_ORGANIZATION_NAME: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVAOrg").get(), + text); + break; + case SEC_OID_AVA_LOCALITY: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVALocality").get(), + text); + break; + case SEC_OID_AVA_DN_QUALIFIER: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVADN").get(), + text); + break; + case SEC_OID_AVA_DC: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVADC").get(), + text); + break; + case SEC_OID_AVA_STATE_OR_PROVINCE: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVAState").get(), + text); + break; + case SEC_OID_PKCS1_RSA_ENCRYPTION: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpRSAEncr").get(), + text); + break; + case SEC_OID_X509_KEY_USAGE: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKeyUsage").get(), + text); + break; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertType").get(), + text); + break; + case SEC_OID_X509_AUTH_KEY_ID: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAuthKeyID").get(), + text); + break; + case SEC_OID_RFC1274_UID: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpUserID").get(), + text); + break; + case SEC_OID_PKCS9_EMAIL_ADDRESS: + rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpPK9Email").get(), + text); + break; + default: + rv = GetDefaultOIDFormat(oid, text); + if (NS_FAILED(rv)) + return rv; + + const PRUnichar *params[1] = {text.get()}; + nsXPIDLString text2; + rv = nssComponent->PIPBundleFormatStringFromName(NS_LITERAL_STRING("CertDumpDefOID").get(), + params, 1, + getter_Copies(text2)); + text = text2; + break; + } + return rv; +} + +#define SEPARATOR "\n" + +static nsresult +ProcessRawBytes(SECItem *data, nsString &text) +{ + // This function is used to display some DER bytes + // that we have not added support for decoding. + // It prints the value of the byte out into a + // string that can later be displayed as a byte + // string. We place a new line after 24 bytes + // to break up extermaly long sequence of bytes. + PRUint32 i; + char buffer[5]; + for (i=0; ilen; i++) { + PR_snprintf(buffer, 5, "%02x ", data->data[i]); + text.Append(NS_ConvertASCIItoUCS2(buffer).get()); + if ((i+1)%24 == 0) { + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + } + return NS_OK; +} + +static nsresult +ProcessNSCertTypeExtensions(SECItem *extData, + nsString &text, + nsINSSComponent *nssComponent) +{ + SECItem decoded; + decoded.data = nsnull; + decoded.len = 0; + SEC_ASN1DecodeItem(nsnull, &decoded, SEC_BitStringTemplate, extData); + unsigned char nsCertType = decoded.data[0]; + nsString local; + nsMemory::Free(decoded.data); + if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifySSLClient").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (nsCertType & NS_CERT_TYPE_SSL_SERVER) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifySSLServer").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (nsCertType & NS_CERT_TYPE_EMAIL) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertTypeEmail").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifyObjSign").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (nsCertType & NS_CERT_TYPE_SSL_CA) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifySSLCA").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (nsCertType & NS_CERT_TYPE_EMAIL_CA) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpEmailCA").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifyObjSign").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + return NS_OK; +} + +static nsresult +ProcessKeyUsageExtension(SECItem *extData, nsString &text, + nsINSSComponent *nssComponent) +{ + SECItem decoded; + decoded.data = nsnull; + decoded.len = 0; + SEC_ASN1DecodeItem(nsnull, &decoded, SEC_BitStringTemplate, extData); + unsigned char keyUsage = decoded.data[0]; + nsString local; + nsMemory::Free(decoded.data); + if (keyUsage & KU_DIGITAL_SIGNATURE) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUSign").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (keyUsage & KU_NON_REPUDIATION) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUNonRep").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (keyUsage & KU_KEY_ENCIPHERMENT) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUEnc").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (keyUsage & KU_DATA_ENCIPHERMENT) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUDEnc").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (keyUsage & KU_KEY_AGREEMENT) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUKA").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (keyUsage & KU_KEY_CERT_SIGN) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUCertSign").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + if (keyUsage & KU_CRL_SIGN) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUCRLSign").get(), + local); + text.Append(local.get()); + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + } + + return NS_OK; +} + +static nsresult +ProcessExtensionData(SECOidTag oidTag, SECItem *extData, + nsString &text, nsINSSComponent *nssComponent) +{ + nsresult rv; + switch (oidTag) { + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + rv = ProcessNSCertTypeExtensions(extData, text, nssComponent); + break; + case SEC_OID_X509_KEY_USAGE: + rv = ProcessKeyUsageExtension(extData, text, nssComponent); + break; + default: + rv = ProcessRawBytes(extData, text); + break; + } + return rv; +} + +static nsresult +ProcessSingleExtension(CERTCertExtension *extension, + nsINSSComponent *nssComponent, + nsIASN1PrintableItem **retExtension) +{ + nsString text; + GetOIDText(&extension->id, nssComponent, text); + nsCOMPtrextensionItem = new nsNSSASN1PrintableItem(); + if (extensionItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + extensionItem->SetDisplayName(text.get()); + SECOidTag oidTag = SECOID_FindOIDTag(&extension->id); + text.Truncate(); + if (extension->critical.data != nsnull) { + if (extension->critical.data[0]) { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCritical").get(), + text); + } else { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNonCritical").get(), + text); + } + } else { + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNonCritical").get(), + text); + } + text.Append(NS_LITERAL_STRING(SEPARATOR).get()); + nsresult rv = ProcessExtensionData(oidTag, &extension->value, text, + nssComponent); + if (NS_FAILED(rv)) + return rv; + + extensionItem->SetDisplayValue(text.get()); + *retExtension = extensionItem; + NS_ADDREF(*retExtension); + return NS_OK; +} + +#ifdef DEBUG_javi +void +DumpASN1Object(nsIASN1Object *object, unsigned int level) +{ + PRUnichar *dispNameU, *dispValU; + unsigned int i; + nsCOMPtr asn1Objects; + nsCOMPtr isupports; + nsCOMPtr currObject; + PRBool processObjects; + PRUint32 numObjects; + + for (i=0; iGetDisplayName(&dispNameU); + nsCOMPtr sequence(do_QueryInterface(object)); + if (sequence) { + printf ("%s ", NS_ConvertUCS2toUTF8(dispNameU).get()); + sequence->GetProcessObjects(&processObjects); + if (processObjects) { + printf("\n"); + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + asn1Objects->Count(&numObjects); + for (i=0; iElementAt(i)); + currObject = do_QueryInterface(isupports); + DumpASN1Object(currObject, level+1); + } + } else { + object->GetDisplayValue(&dispValU); + printf("= %s\n", NS_ConvertUCS2toUTF8(dispValU).get()); + PR_Free(dispValU); + } + } else { + object->GetDisplayValue(&dispValU); + printf("%s = %s\n",NS_ConvertUCS2toUTF8(dispNameU).get(), + NS_ConvertUCS2toUTF8(dispValU).get()); + PR_Free(dispValU); + } + PR_Free(dispNameU); +} +#endif + /* * void getUsages(out PRUint32 verified, * out PRUint32 count, @@ -1053,7 +1531,7 @@ nsNSSCertificate::GetPurposes(PRUint32 *_verified, } /* void view (); */ -NS_IMETHODIMP +NS_IMETHODIMP nsNSSCertificate::View() { nsresult rv; @@ -1064,6 +1542,398 @@ nsNSSCertificate::View() return certDialogs->ViewCert(this); } +static nsresult +ProcessSECAlgorithmID(SECAlgorithmID *algID, + nsINSSComponent *nssComponent, + nsIASN1Sequence **retSequence) +{ + nsCOMPtr sequence = new nsNSSASN1Sequence(); + if (sequence == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + *retSequence = nsnull; + nsString text; + GetOIDText(&algID->algorithm, nssComponent, text); + if (algID->parameters.data[0] == nsIASN1Object::ASN1_NULL) { + sequence->SetDisplayValue(text.get()); + sequence->SetProcessObjects(PR_FALSE); + } else { + nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); + printableItem->SetDisplayValue(text.get()); + nsCOMPtrasn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + asn1Objects->AppendElement(printableItem); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAlgID").get(), + text); + printableItem->SetDisplayName(text.get()); + printableItem = new nsNSSASN1PrintableItem(); + asn1Objects->AppendElement(printableItem); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpParams").get(), + text); + printableItem->SetDisplayName(text.get()); + ProcessRawBytes(&algID->parameters,text); + printableItem->SetDisplayValue(text.get()); + } + *retSequence = sequence; + NS_ADDREF(*retSequence); + return NS_OK; +} + +static nsresult +ProcessTime(PRTime dispTime, const PRUnichar *displayName, + nsIASN1Sequence *parentSequence) +{ + nsresult rv; + nsCOMPtr dateFormatter = + do_CreateInstance(kDateTimeFormatCID, &rv); + if (NS_FAILED(rv)) + return rv; + + nsString text; + dateFormatter->FormatPRTime(nsnull, kDateFormatShort, kTimeFormatNone, + dispTime, text); + nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + printableItem->SetDisplayValue(text.get()); + printableItem->SetDisplayName(displayName); + nsCOMPtr asn1Objects; + parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + asn1Objects->AppendElement(printableItem); + return NS_OK; +} + +static nsresult +ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki, + nsIASN1Sequence *parentSequence, + nsINSSComponent *nssComponent) +{ + nsCOMPtr spkiSequence = new nsNSSASN1Sequence(); + + if (spkiSequence == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + nsString text; + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSPKI").get(), + text); + spkiSequence->SetDisplayName(text.get()); + + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSPKIAlg").get(), + text); + nsCOMPtr sequenceItem; + nsresult rv = ProcessSECAlgorithmID(&spki->algorithm, nssComponent, + getter_AddRefs(sequenceItem)); + if (NS_FAILED(rv)) + return rv; + sequenceItem->SetDisplayName(text.get()); + nsCOMPtr asn1Objects; + spkiSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + asn1Objects->AppendElement(sequenceItem); + + // The subjectPublicKey field is encoded as a bit string. + // ProcessRawBytes expects the lenght to be in bytes, so + // let's convert the lenght into a temporary SECItem. + SECItem data; + data.data = spki->subjectPublicKey.data; + data.len = spki->subjectPublicKey.len / 8; + text.Truncate(); + ProcessRawBytes(&data, text); + nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + printableItem->SetDisplayValue(text.get()); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubjPubKey").get(), + text); + printableItem->SetDisplayName(text.get()); + asn1Objects->AppendElement(printableItem); + + parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + asn1Objects->AppendElement(spkiSequence); + return NS_OK; +} + +static nsresult +ProcessExtensions(CERTCertExtension **extensions, + nsIASN1Sequence *parentSequence, + nsINSSComponent *nssComponent) +{ + nsCOMPtr extensionSequence = new nsNSSASN1Sequence; + if (extensionSequence == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + nsString text; + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpExtensions").get(), + text); + extensionSequence->SetDisplayName(text.get()); + PRInt32 i; + nsresult rv; + nsCOMPtr newExtension; + nsCOMPtr asn1Objects; + extensionSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + for (i=0; extensions[i] != nsnull; i++) { + rv = ProcessSingleExtension(extensions[i], nssComponent, + getter_AddRefs(newExtension)); + if (NS_FAILED(rv)) + return rv; + + asn1Objects->AppendElement(newExtension); + } + parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + asn1Objects->AppendElement(extensionSequence); + return NS_OK; +} + +nsresult +nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence, + nsINSSComponent *nssComponent) +{ + // + // TBSCertificate ::= SEQUENCE { + // version [0] EXPLICIT Version DEFAULT v1, + // serialNumber CertificateSerialNumber, + // signature AlgorithmIdentifier, + // issuer Name, + // validity Validity, + // subject Name, + // subjectPublicKeyInfo SubjectPublicKeyInfo, + // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + // -- If present, version shall be v2 or v3 + // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + // -- If present, version shall be v2 or v3 + // extensions [3] EXPLICIT Extensions OPTIONAL + // -- If present, version shall be v3 + // } + // + // This is the ASN1 structure we should be dealing with at this point. + // The code in this method will assert this is the structure we're dealing + // and then add more user friendly text for that field. + nsCOMPtr sequence = new nsNSSASN1Sequence(); + if (sequence == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + nsString text; + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertificate").get(), + text); + sequence->SetDisplayName(text.get()); + nsCOMPtr printableItem; + + nsCOMPtr asn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + + nsresult rv = ProcessVersion(&mCert->version, nssComponent, + getter_AddRefs(printableItem)); + if (NS_FAILED(rv)) + return rv; + + asn1Objects->AppendElement(printableItem); + + rv = ProcessSerialNumber(&mCert->serialNumber, nssComponent, + getter_AddRefs(printableItem)); + + if (NS_FAILED(rv)) + return rv; + asn1Objects->AppendElement(printableItem); + + nsCOMPtr algID; + rv = ProcessSECAlgorithmID(&mCert->signature, + nssComponent, getter_AddRefs(algID)); + if (NS_FAILED(rv)) + return rv; + + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSigAlg").get(), + text); + algID->SetDisplayName(text.get()); + asn1Objects->AppendElement(algID); + + nsXPIDLString value; + GetIssuerName(getter_Copies(value)); + + printableItem = new nsNSSASN1PrintableItem(); + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + printableItem->SetDisplayValue(value); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpIssuer").get(), + text); + printableItem->SetDisplayName(text.get()); + asn1Objects->AppendElement(printableItem); + + nsCOMPtr validitySequence = new nsNSSASN1Sequence(); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpValidity").get(), + text); + validitySequence->SetDisplayName(text.get()); + asn1Objects->AppendElement(validitySequence); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNotBefore").get(), + text); + nsCOMPtr validityData; + GetValidity(getter_AddRefs(validityData)); + PRTime notBefore, notAfter; + + validityData->GetNotBefore(¬Before); + validityData->GetNotAfter(¬After); + validityData = 0; + rv = ProcessTime(notBefore, text.get(), validitySequence); + if (NS_FAILED(rv)) + return rv; + + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNotAfter").get(), + text); + rv = ProcessTime(notAfter, text.get(), validitySequence); + if (NS_FAILED(rv)) + return rv; + + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubject").get(), + text); + + printableItem = new nsNSSASN1PrintableItem(); + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + printableItem->SetDisplayName(text.get()); + GetSubjectName(getter_Copies(value)); + printableItem->SetDisplayValue(value); + asn1Objects->AppendElement(printableItem); + + rv = ProcessSubjectPublicKeyInfo(&mCert->subjectPublicKeyInfo, sequence, + nssComponent); + if (NS_FAILED(rv)) + return rv; + + SECItem data; + // Is there an issuerUniqueID? + if (mCert->issuerID.data != nsnull) { + // The issuerID is encoded as a bit string. + // The function ProcessRawBytes expects the + // length to be in bytes, so let's convert the + // length in a temporary SECItem + data.data = mCert->issuerID.data; + data.len = mCert->issuerID.len / 8; + + ProcessRawBytes(&data, text); + printableItem = new nsNSSASN1PrintableItem(); + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + printableItem->SetDisplayValue(text.get()); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpIssuerUniqueID").get(), + text); + printableItem->SetDisplayName(text.get()); + asn1Objects->AppendElement(printableItem); + } + + if (mCert->subjectID.data) { + // The subjectID is encoded as a bit string. + // The function ProcessRawBytes expects the + // length to be in bytes, so let's convert the + // length in a temporary SECItem + data.data = mCert->issuerID.data; + data.len = mCert->issuerID.len / 8; + + ProcessRawBytes(&data, text); + printableItem = new nsNSSASN1PrintableItem(); + if (printableItem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + printableItem->SetDisplayValue(text.get()); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubjectUniqueID").get(), + text); + printableItem->SetDisplayName(text.get()); + asn1Objects->AppendElement(printableItem); + + } + if (mCert->extensions) { + rv = ProcessExtensions(mCert->extensions, sequence, nssComponent); + if (NS_FAILED(rv)) + return rv; + } + *retSequence = sequence; + NS_ADDREF(*retSequence); + return NS_OK; +} + +nsresult +nsNSSCertificate::CreateASN1Struct() +{ + nsCOMPtr sequence = new nsNSSASN1Sequence(); + + mASN1Structure = sequence; + if (mASN1Structure == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsCOMPtr asn1Objects; + sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); + nsXPIDLCString title; + GetWindowTitle(getter_Copies(title)); + + mASN1Structure->SetDisplayName(NS_ConvertASCIItoUCS2(title).get()); + // This sequence will be contain the tbsCertificate, signatureAlgorithm, + // and signatureValue. + nsresult rv; + nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + rv = CreateTBSCertificateASN1Struct(getter_AddRefs(sequence), + nssComponent); + if (NS_FAILED(rv)) + return rv; + + asn1Objects->AppendElement(sequence); + nsCOMPtr algID; + + rv = ProcessSECAlgorithmID(&mCert->signatureWrap.signatureAlgorithm, + nssComponent, getter_AddRefs(algID)); + if (NS_FAILED(rv)) + return rv; + nsString text; + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSigAlg").get(), + text); + algID->SetDisplayName(text.get()); + asn1Objects->AppendElement(algID); + nsCOMPtrprintableItem = new nsNSSASN1PrintableItem(); + nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertSig").get(), + text); + printableItem->SetDisplayName(text.get()); + // The signatureWrap is encoded as a bit string. + // The function ProcessRawBytes expects the + // length to be in bytes, so let's convert the + // length in a temporary SECItem + SECItem temp; + temp.data = mCert->signatureWrap.signature.data; + temp.len = mCert->signatureWrap.signature.len / 8; + text.Truncate(); + ProcessRawBytes(&temp,text); + printableItem->SetDisplayValue(text.get()); + asn1Objects->AppendElement(printableItem); + return NS_OK; +} + +/* readonly attribute nsIASN1Object ASN1Structure; */ +NS_IMETHODIMP +nsNSSCertificate::GetASN1Structure(nsIASN1Object * *aASN1Structure) +{ + nsresult rv = NS_OK; + NS_ENSURE_ARG_POINTER(aASN1Structure); + if (mASN1Structure == nsnull) { + // First create the recursive structure os ASN1Objects + // which tells us the layout of the cert. + rv = CreateASN1Struct(); + if (NS_FAILED(rv)) { + return rv; + } +#ifdef DEBUG_javi + DumpASN1Object(mASN1Structure, 0); +#endif + } + *aASN1Structure = mASN1Structure; + NS_IF_ADDREF(*aASN1Structure); + return rv; +} + + /* nsNSSCertificateDB */ NS_IMPL_ISUPPORTS1(nsNSSCertificateDB, nsIX509CertDB) diff --git a/security/manager/ssl/src/nsNSSCertificate.h b/security/manager/ssl/src/nsNSSCertificate.h index 6788024ad86b..8de4d44e55cc 100644 --- a/security/manager/ssl/src/nsNSSCertificate.h +++ b/security/manager/ssl/src/nsNSSCertificate.h @@ -44,6 +44,8 @@ #include "cert.h" #include "secitem.h" +class nsINSSComponent; + /* Certificate */ class nsNSSCertificate : public nsIX509Cert { @@ -59,6 +61,10 @@ public: private: CERTCertificate *mCert; + nsCOMPtr mASN1Structure; + nsresult CreateASN1Struct(); + nsresult CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence, + nsINSSComponent *nssComponent); PRBool verifyFailed(PRUint32 *_verified); diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp index 4039b70efb31..baccefb9a6f0 100644 --- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -161,6 +161,9 @@ nsNSSComponent::GetPIPNSSBundleString(const PRUnichar *name, } else { outString.SetLength(0); } + if (ptrv) + nsMemory::Free(ptrv); + return NS_ERROR_FAILURE; } @@ -178,7 +181,8 @@ nsNSSComponent::InstallLoadableRoots() hasRoot = PR_TRUE; break; } - } + } + PK11_FreeSlotList(slotList); } if (!hasRoot) { nsresult rv;