diff --git a/security/manager/pki/resources/content/choosetoken.js b/security/manager/pki/resources/content/choosetoken.js
new file mode 100644
index 00000000000..478a5619ab4
--- /dev/null
+++ b/security/manager/pki/resources/content/choosetoken.js
@@ -0,0 +1,58 @@
+/* -*- 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) 2001 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ * David Drinan.
+ */
+
+
+const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
+
+var dialogParams;
+
+function onLoad()
+{
+ dialogParams = window.arguments[0].QueryInterface(nsIDialogParamBlock);
+ var selectElement = document.getElementById("tokens");
+ for (var i=1; i <= dialogParams.GetInt(1); i++) {
+ var menuItemNode = document.createElement("menuitem");
+ var token = dialogParams.GetString(i);
+ menuItemNode.setAttribute("value", token);
+ menuItemNode.setAttribute("label", token);
+ selectElement.firstChild.appendChild(menuItemNode);
+ if (i == 1) {
+ selectElement.selectedItem = menuItemNode;
+ }
+ }
+}
+
+function doOK()
+{
+ var tokenList = document.getElementById("tokens");
+ var token = tokenList.value;
+ dialogParams.SetInt(1,1);
+ dialogParams.SetString(1, token);
+ window.close();
+}
+
+function doCancel()
+{
+ dialogParams.SetInt(1,0);
+ window.close();
+}
diff --git a/security/manager/pki/resources/content/choosetoken.xul b/security/manager/pki/resources/content/choosetoken.xul
new file mode 100644
index 00000000000..da6735a9acd
--- /dev/null
+++ b/security/manager/pki/resources/content/choosetoken.xul
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+%pippkiDTD;
+]>
+
+
+
+
+
+
+
+
+
+ &chooseToken.message1;
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/security/manager/pki/resources/jar.mn b/security/manager/pki/resources/jar.mn
index bf842b2ed80..42a5835c641 100644
--- a/security/manager/pki/resources/jar.mn
+++ b/security/manager/pki/resources/jar.mn
@@ -34,6 +34,8 @@ pippki.jar:
content/pippki/clientauthask.js (content/clientauthask.js)
content/pippki/certViewer.xul (content/certViewer.xul)
content/pippki/certDump.xul (content/certDump.xul)
+ content/pippki/choosetoken.xul (content/choosetoken.xul)
+ content/pippki/choosetoken.js (content/choosetoken.js)
locale/en-US/pippki/contents.rdf (locale/en-US/contents.rdf)
locale/en-US/pippki/pippki.dtd (locale/en-US/pippki.dtd)
locale/en-US/pippki/pref-ssl.dtd (locale/en-US/pref-ssl.dtd)
diff --git a/security/manager/pki/resources/locale/en-US/pippki.dtd b/security/manager/pki/resources/locale/en-US/pippki.dtd
index 1ba258c4995..9f713778840 100644
--- a/security/manager/pki/resources/locale/en-US/pippki.dtd
+++ b/security/manager/pki/resources/locale/en-US/pippki.dtd
@@ -90,3 +90,6 @@
+
+
+
diff --git a/security/manager/pki/src/nsNSSDialogs.cpp b/security/manager/pki/src/nsNSSDialogs.cpp
index e2714b38f91..62b7d2ae661 100644
--- a/security/manager/pki/src/nsNSSDialogs.cpp
+++ b/security/manager/pki/src/nsNSSDialogs.cpp
@@ -111,12 +111,13 @@ nsNSSDialogs::~nsNSSDialogs()
{
}
-NS_IMPL_THREADSAFE_ISUPPORTS6(nsNSSDialogs, nsINSSDialogs,
+NS_IMPL_THREADSAFE_ISUPPORTS7(nsNSSDialogs, nsINSSDialogs,
nsITokenPasswordDialogs,
nsISecurityWarningDialogs,
nsIBadCertListener,
nsICertificateDialogs,
- nsIClientAuthDialogs);
+ nsIClientAuthDialogs,
+ nsITokenDialogs);
nsresult
nsNSSDialogs::Init()
@@ -735,3 +736,43 @@ nsNSSDialogs::ViewCert(nsIX509Cert *cert)
block);
return rv;
}
+
+NS_IMETHODIMP
+nsNSSDialogs::ChooseToken(nsIInterfaceRequestor *aCtx, const PRUnichar **aTokenList, PRUint32 aCount, PRUnichar **aTokenChosen, PRBool *aCanceled) {
+ nsresult rv;
+ PRUint32 i;
+
+ *aCanceled = PR_FALSE;
+
+ // Get the parent window for the dialog
+ nsCOMPtr parent = do_GetInterface(aCtx);
+
+ nsCOMPtr block(do_CreateInstance("@mozilla.org/embedcomp/dialogparam;1"));
+ if (!block) return NS_ERROR_FAILURE;
+
+ for (i = 0; i < aCount; i++) {
+ rv = block->SetString(i+1, aTokenList[i]);
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ rv = block->SetInt(1, aCount);
+ if (NS_FAILED(rv)) return rv;
+
+ rv = nsNSSDialogHelper::openDialog(nsnull,
+ "chrome://pippki/content/choosetoken.xul",
+ block);
+ if (NS_FAILED(rv)) return rv;
+
+ PRInt32 status;
+
+ rv = block->GetInt(1, &status);
+ if (NS_FAILED(rv)) return rv;
+
+ *aCanceled = (status == 0)?PR_TRUE:PR_FALSE;
+ if (!*aCanceled) {
+ // retrieve the nickname
+ rv = block->GetString(1, aTokenChosen);
+ }
+ return rv;
+}
+
diff --git a/security/manager/pki/src/nsNSSDialogs.h b/security/manager/pki/src/nsNSSDialogs.h
index 0cfdb2a042f..44cd93183d2 100644
--- a/security/manager/pki/src/nsNSSDialogs.h
+++ b/security/manager/pki/src/nsNSSDialogs.h
@@ -41,7 +41,8 @@ class nsNSSDialogs
public nsIBadCertListener,
public nsISecurityWarningDialogs,
public nsICertificateDialogs,
- public nsIClientAuthDialogs
+ public nsIClientAuthDialogs,
+ public nsITokenDialogs
{
public:
NS_DECL_ISUPPORTS
@@ -51,6 +52,7 @@ public:
NS_DECL_NSISECURITYWARNINGDIALOGS
NS_DECL_NSICERTIFICATEDIALOGS
NS_DECL_NSICLIENTAUTHDIALOGS
+ NS_DECL_NSITOKENDIALOGS
nsNSSDialogs();
virtual ~nsNSSDialogs();
diff --git a/security/manager/ssl/public/nsINSSDialogs.idl b/security/manager/ssl/public/nsINSSDialogs.idl
index 6abd2b3346a..bb55d015db5 100644
--- a/security/manager/ssl/public/nsINSSDialogs.idl
+++ b/security/manager/ssl/public/nsINSSDialogs.idl
@@ -144,13 +144,23 @@ interface nsIClientAuthDialogs : nsISupports
* UI shown when a user is asked to do SSL client auth.
*/
void ChooseCertificate(in nsIInterfaceRequestor ctx,
- in wstring cn,
- in wstring organization,
- in wstring issuer,
- [array, size_is(count)] in wstring certNickList,
- in PRUint32 count,
- out wstring certNick,
- out boolean canceled);
+ in wstring cn,
+ in wstring organization,
+ in wstring issuer,
+ [array, size_is(count)] in wstring certNickList,
+ in PRUint32 count,
+ out wstring certNick,
+ out boolean canceled);
+};
+
+[scriptable, uuid(bb4bae9c-39c5-11d5-ba26-00108303b117)]
+interface nsITokenDialogs : nsISupports
+{
+ void ChooseToken(in nsIInterfaceRequestor ctx,
+ [array, size_is(count)] in wstring tokenNameList,
+ in PRUint32 count,
+ out wstring tokenName,
+ out boolean canceled);
};
/**
diff --git a/security/manager/ssl/public/nsIX509CertDB.idl b/security/manager/ssl/public/nsIX509CertDB.idl
index 11e601c69ba..b5aa0fe8b5f 100644
--- a/security/manager/ssl/public/nsIX509CertDB.idl
+++ b/security/manager/ssl/public/nsIX509CertDB.idl
@@ -43,6 +43,7 @@ interface nsISupportsArray;
interface nsIX509Cert;
interface nsIPK11Token;
interface nsILocalFile;
+interface nsIInterfaceRequestor;
%{C++
@@ -123,6 +124,15 @@ interface nsIX509CertDB : nsISupports {
in unsigned long trust,
in wstring nickname);
+ /*
+ * importCertificate
+ *
+ * Import a user certificate into the database.
+ * XXX This method and the importCertificate should be merged into one.
+ */
+ [noscript] void importUserCertificate(in charPtr data,
+ in unsigned long length,
+ in nsIInterfaceRequestor ctx);
/*
* deleteCertificate
*
diff --git a/security/manager/ssl/resources/locale/en-US/pipnss.properties b/security/manager/ssl/resources/locale/en-US/pipnss.properties
index 0d3ce8aa8d0..2569ffe878c 100644
--- a/security/manager/ssl/resources/locale/en-US/pipnss.properties
+++ b/security/manager/ssl/resources/locale/en-US/pipnss.properties
@@ -46,6 +46,11 @@ VerifyUserImport=User Import Cert
VerifyCAVerifier=CA Verifier
VerifyStatusResponder=Status Responder Certificate
VerifyAnyCA=Any Certificate Authority
+HighGrade=2048 (High Grade)
+MediumGrade=1024 (Medium Grade)
+LowGrade= 512 (Low Grade)
+nick_template=%1$s's %2$s ID
+nick_template_with_num=%1$s's %2$s ID #%3$d
#These are the strings set for the ASN1 objects in a certificate.
CertDumpCertificate=Certificate
CertDumpVersion=Version
diff --git a/security/manager/ssl/src/Makefile.in b/security/manager/ssl/src/Makefile.in
index c30488ce591..6239bb59a8c 100644
--- a/security/manager/ssl/src/Makefile.in
+++ b/security/manager/ssl/src/Makefile.in
@@ -62,6 +62,7 @@ CPPSRCS = \
nsPKCS12Blob.cpp \
nsNSSASN1Object.cpp \
nsCertOutliner.cpp \
+ nsKeygenHandler.cpp \
$(NULL)
REQUIRES = nspr security xpcom string necko uriloader pref caps dom intl locale profile windowwatcher js docshell widget layout gfx2
diff --git a/security/manager/ssl/src/makefile.win b/security/manager/ssl/src/makefile.win
index c491d8adddf..ad54e4a36f2 100644
--- a/security/manager/ssl/src/makefile.win
+++ b/security/manager/ssl/src/makefile.win
@@ -88,6 +88,7 @@ OBJS = \
.\$(OBJDIR)\nsPK11TokenDB.obj \
.\$(OBJDIR)\nsNSSCertificate.obj \
.\$(OBJDIR)\nsPKCS12Blob.obj \
+ .\$(OBJDIR)\nsKeygenHandler.obj \
.\$(OBJDIR)\nsCertOutliner.obj \
.\$(OBJDIR)\nsNSSASN1Object.obj \
$(NULL)
diff --git a/security/manager/ssl/src/nsKeygenHandler.cpp b/security/manager/ssl/src/nsKeygenHandler.cpp
new file mode 100644
index 00000000000..40bd67071a5
--- /dev/null
+++ b/security/manager/ssl/src/nsKeygenHandler.cpp
@@ -0,0 +1,519 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * The contents of this file are subject to the Netscape 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/NPL/
+ *
+ * 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):
+ */
+
+extern "C" {
+#include "secdert.h"
+#include "keydbt.h"
+}
+#include "nspr.h"
+#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
+#include "keyhi.h"
+#include "secder.h"
+#include "cryptohi.h"
+#include "base64.h"
+#include "secasn1.h"
+#include "nsProxiedService.h"
+#include "nsKeygenHandler.h"
+#include "nsVoidArray.h"
+#include "nsSecureBrowserUIImpl.h"
+#include "nsIServiceManager.h"
+#include "nsIDOMHTMLSelectElement.h"
+#include "nsIContent.h"
+#include "nsINSSDialogs.h"
+
+//These defines are taken from the PKCS#11 spec
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010
+
+//All possible key size choices.
+static SECKeySizeChoiceInfo SECKeySizeChoiceList[] = {
+ { nsnull, 2048 },
+ { nsnull, 1024 },
+ { nsnull, 512 },
+ { nsnull, 0 },
+};
+
+
+DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
+ { DER_SEQUENCE,
+ 0, nsnull, sizeof(CERTSubjectPublicKeyInfo) },
+ { DER_INLINE,
+ offsetof(CERTSubjectPublicKeyInfo,algorithm),
+ SECAlgorithmIDTemplate, },
+ { DER_BIT_STRING,
+ offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
+ { 0, }
+};
+
+DERTemplate CERTPublicKeyAndChallengeTemplate[] =
+{
+ { DER_SEQUENCE, 0, nsnull, sizeof(CERTPublicKeyAndChallenge) },
+ { DER_ANY, offsetof(CERTPublicKeyAndChallenge,spki), },
+ { DER_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge), },
+ { 0, }
+};
+
+static NS_DEFINE_IID(kFormProcessorIID, NS_IFORMPROCESSOR_IID);
+static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
+static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
+
+static const char *mozKeyGen = "-mozilla-keygen";
+
+static PQGParams *
+decode_pqg_params(char *aStr)
+{
+ unsigned char *buf;
+ unsigned int len;
+ PRArenaPool *arena;
+ PQGParams *params;
+ SECStatus status;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena)
+ return nsnull;
+
+ params = NS_STATIC_CAST(PQGParams*, PORT_ArenaZAlloc(arena, sizeof(PQGParams)));
+ if (!params)
+ goto loser;
+ params->arena = arena;
+
+ buf = ATOB_AsciiToData(aStr, &len);
+ if ((!buf) || (len == 0))
+ goto loser;
+
+ status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, (const char*)buf, len);
+ if (status != SECSuccess)
+ goto loser;
+
+ return params;
+
+loser:
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ if (buf) {
+ PR_Free(buf);
+ }
+ return nsnull;
+}
+
+static int
+pqg_prime_bits(char *str)
+{
+ PQGParams *params = nsnull;
+ int primeBits = 0, i;
+
+ params = decode_pqg_params(str);
+ if (!params)
+ goto done; /* lose */
+
+ for (i = 0; params->prime.data[i] == 0; i++)
+ /* empty */;
+ primeBits = (params->prime.len - i) * 8;
+
+done:
+ if (params)
+ PQG_DestroyParams(params);
+ return primeBits;
+}
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenFormProcessor, nsIFormProcessor);
+MOZ_DECL_CTOR_COUNTER(nsKeygenFormProcessor)
+
+nsKeygenFormProcessor::nsKeygenFormProcessor()
+{
+ NS_INIT_REFCNT();
+ MOZ_COUNT_CTOR(nsKeygenFormProcessor);
+ m_ctx = new PipUIContext();
+
+}
+
+nsKeygenFormProcessor::~nsKeygenFormProcessor()
+{
+ MOZ_COUNT_DTOR(nsKeygenFormProcessor);
+}
+
+NS_METHOD
+nsKeygenFormProcessor::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
+{
+ nsresult rv;
+ NS_ENSURE_NO_AGGREGATION(aOuter);
+ nsKeygenFormProcessor* formProc = new nsKeygenFormProcessor();
+ if (!formProc)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsCOMPtr stabilize = formProc;
+ rv = formProc->Init();
+ if (NS_SUCCEEDED(rv)) {
+ rv = formProc->QueryInterface(aIID, aResult);
+ }
+ return rv;
+}
+
+nsresult
+nsKeygenFormProcessor::Init()
+{
+ nsresult rv;
+ nsAutoString str;
+
+ // Get the key strings //
+ nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv));
+
+ nssComponent->GetPIPNSSBundleString(
+ NS_LITERAL_STRING("HighGrade").get(),
+ str);
+ SECKeySizeChoiceList[0].name = str.ToNewUnicode();
+
+ nssComponent->GetPIPNSSBundleString(
+ NS_LITERAL_STRING("MediumGrade").get(),
+ str);
+ SECKeySizeChoiceList[1].name = str.ToNewUnicode();
+
+ nssComponent->GetPIPNSSBundleString(
+ NS_LITERAL_STRING("LowGrade").get(),
+ str);
+ SECKeySizeChoiceList[2].name = str.ToNewUnicode();
+
+ return NS_OK;
+}
+
+nsresult
+nsKeygenFormProcessor::GetSlot(PRUint32 aMechanism, PK11SlotInfo** aSlot)
+{
+ PK11SlotList * slotList = nsnull;
+ PRUnichar** tokenNameList = nsnull;
+ nsITokenDialogs * dialogs;
+ PRUnichar *unicodeTokenChosen;
+ PK11SlotListElement *slotElement, *tmpSlot;
+ PRUint32 numSlots = 0, i = 0;
+ PRBool canceled;
+ nsresult rv = NS_OK;
+
+ *aSlot = nsnull;
+
+ // Get the slot
+ slotList = PK11_GetAllTokens(aMechanism,
+ PR_TRUE, PR_TRUE, m_ctx);
+ if (!slotList || !slotList->head) {
+ rv = NS_ERROR_FAILURE;
+ goto loser;
+ }
+
+ if (!slotList->head->next) {
+ /* only one slot available, just return it */
+ *aSlot = slotList->head->slot;
+ } else {
+ // Gerenate a list of slots and ask the user to choose //
+ tmpSlot = slotList->head;
+ while (tmpSlot) {
+ numSlots++;
+ tmpSlot = tmpSlot->next;
+ }
+
+ // Allocate the slot name buffer //
+ tokenNameList = NS_STATIC_CAST(PRUnichar**, nsMemory::Alloc(sizeof(PRUnichar *) * numSlots));
+ i = 0;
+ slotElement = PK11_GetFirstSafe(slotList);
+ while (slotElement) {
+ tokenNameList[i] = NS_ConvertUTF8toUCS2(PK11_GetTokenName(slotElement->slot)).ToNewUnicode();
+ slotElement = PK11_GetNextSafe(slotList, slotElement, PR_FALSE);
+ i++;
+ }
+
+ /* Throw up the token list dialog and get back the token */
+ rv = getNSSDialogs((void**)&dialogs,
+ NS_GET_IID(nsITokenDialogs));
+
+ if (NS_FAILED(rv)) goto loser;
+
+ rv = dialogs->ChooseToken(nsnull, (const PRUnichar**)tokenNameList, numSlots, &unicodeTokenChosen, &canceled);
+ NS_RELEASE(dialogs);
+ if (NS_FAILED(rv)) goto loser;
+
+ if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
+
+ // Get the slot //
+ slotElement = PK11_GetFirstSafe(slotList);
+ nsAutoString tokenStr(unicodeTokenChosen);
+ while (slotElement) {
+ if (tokenStr.Equals(NS_ConvertUTF8toUCS2(PK11_GetTokenName(slotElement->slot)))) {
+ *aSlot = slotElement->slot;
+ break;
+ }
+ slotElement = PK11_GetNextSafe(slotList, slotElement, PR_FALSE);
+ }
+ if(!(*aSlot)) {
+ rv = NS_ERROR_FAILURE;
+ goto loser;
+ }
+ }
+
+ // Get a reference to the slot //
+ PK11_ReferenceSlot(*aSlot);
+loser:
+ if (slotList) {
+ PK11_FreeSlotList(slotList);
+ }
+ if (tokenNameList) {
+ nsMemory::Free(tokenNameList);
+ }
+ return rv;
+}
+
+nsresult
+nsKeygenFormProcessor::GetPublicKey(nsString& aValue, nsString& aChallenge,
+ nsString& aKeyType,
+ nsString& aOutPublicKey, nsString& aPqg)
+{
+ nsresult rv = NS_ERROR_FAILURE;
+ char *emptyCString = "null";
+ char *keystring = nsnull;
+ char *pqgString = nsnull, *str = nsnull;
+ nsAutoString rsaStr;
+ nsAutoString dsaStr;
+ KeyType type;
+ PRUint32 keyGenMechanism;
+ PRInt32 primeBits;
+ PQGParams *pqgParams;
+ PK11SlotInfo *slot = nsnull;
+ PK11RSAGenParams rsaParams;
+ SECOidTag algTag;
+ int keysize = 0;
+ void *params;
+ SECKEYPrivateKey *privateKey = nsnull;
+ SECKEYPublicKey *publicKey = nsnull;
+ CERTSubjectPublicKeyInfo *spkInfo = nsnull;
+ PRArenaPool *arena = nsnull;
+ SECStatus sec_rv = SECFailure;
+ SECItem spkiItem;
+ SECItem pkacItem;
+ SECItem signedItem;
+ CERTPublicKeyAndChallenge pkac;
+ SECKeySizeChoiceInfo *choice = SECKeySizeChoiceList;
+
+ // Get the key size //
+ while (choice) {
+ if (aValue.Equals(choice->name)) {
+ keysize = choice->size;
+ break;
+ }
+ choice++;
+ }
+ if (!choice) {
+ goto loser;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ goto loser;
+ }
+
+ // Set the keygen mechanism
+ rsaStr.AssignWithConversion("rsa");
+ dsaStr.AssignWithConversion("dsa");
+ if (aKeyType.IsEmpty() || aKeyType.Equals(rsaStr)) {
+ type = rsaKey;
+ keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+ } else if (aKeyType.Equals(dsaStr)) {
+ char * end;
+ pqgString = aPqg.ToNewCString();
+ type = dsaKey;
+ keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
+ if (strcmp(pqgString, "null") == 0)
+ goto loser;
+ str = pqgString;
+ do {
+ end = strchr(str, ',');
+ if (end != nsnull)
+ *end = '\0';
+ primeBits = pqg_prime_bits(str);
+ if (choice->size == primeBits)
+ goto found_match;
+ str = end + 1;
+ } while (end != nsnull);
+ goto loser;
+found_match:
+ pqgParams = decode_pqg_params(str);
+ } else {
+ goto loser;
+ }
+
+ // Get the slot
+ rv = GetSlot(keyGenMechanism, &slot);
+ if (NS_FAILED(rv)) {
+ goto loser;
+ }
+ switch (keyGenMechanism) {
+ case CKM_RSA_PKCS_KEY_PAIR_GEN:
+ rsaParams.keySizeInBits = keysize;
+ rsaParams.pe = 65537L;
+ algTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
+ params = &rsaParams;
+ break;
+ case CKM_DSA_KEY_PAIR_GEN:
+ // XXX Fix this! XXX //
+ goto loser;
+ default:
+ goto loser;
+ }
+
+ sec_rv = PK11_Authenticate(slot, PR_TRUE, m_ctx);
+ if (sec_rv != SECSuccess) {
+ goto loser;
+ }
+
+ privateKey = PK11_GenerateKeyPair(slot, keyGenMechanism, params,
+ &publicKey, PR_TRUE, PR_TRUE, nsnull);
+ if (!privateKey) {
+ goto loser;
+ }
+ // just in case we'll need to authenticate to the db -jp //
+ privateKey->wincx = m_ctx;
+
+ /*
+ * Create a subject public key info from the public key.
+ */
+ spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
+ if ( !spkInfo ) {
+ goto loser;
+ }
+
+ /*
+ * Now DER encode the whole subjectPublicKeyInfo.
+ */
+ sec_rv=DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, spkInfo);
+ if (sec_rv != SECSuccess) {
+ goto loser;
+ }
+
+ /*
+ * set up the PublicKeyAndChallenge data structure, then DER encode it
+ */
+ pkac.spki = spkiItem;
+ pkac.challenge.len = aChallenge.Length();
+ pkac.challenge.data = (unsigned char *)aChallenge.ToNewCString();
+
+ sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac);
+ if ( sec_rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /*
+ * now sign the DER encoded PublicKeyAndChallenge
+ */
+ sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
+ privateKey, algTag);
+ if ( sec_rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /*
+ * Convert the signed public key and challenge into base64/ascii.
+ */
+ keystring = BTOA_DataToAscii(signedItem.data, signedItem.len);
+
+ aOutPublicKey.AssignWithConversion(keystring);
+ nsCRT::free(keystring);
+
+ rv = NS_OK;
+loser:
+ if ( sec_rv != SECSuccess ) {
+ if ( privateKey ) {
+ PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
+ SECKEY_DestroyPrivateKey(privateKey);
+ }
+ if ( publicKey ) {
+ PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID);
+ }
+ }
+ if ( spkInfo ) {
+ SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
+ }
+ if ( publicKey ) {
+ SECKEY_DestroyPublicKey(publicKey);
+ }
+ if ( arena ) {
+ PORT_FreeArena(arena, PR_TRUE);
+ }
+ if (slot != nsnull) {
+ PK11_FreeSlot(slot);
+ }
+ return rv;
+}
+
+NS_METHOD
+nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement *aElement,
+ const nsString& aName,
+ nsString& aValue)
+{
+ nsresult rv = NS_OK;
+ nsCOMPtrselectElement;
+ nsresult res = aElement->QueryInterface(kIDOMHTMLSelectElementIID,
+ getter_AddRefs(selectElement));
+ if (NS_SUCCEEDED(res)) {
+ nsAutoString keygenvalue;
+ nsAutoString challengeValue;
+ nsAutoString keyTypeValue;
+ nsAutoString pqgValue;
+ nsString publicKey;
+
+ res = selectElement->GetAttribute(NS_LITERAL_STRING("_moz-type"), keygenvalue);
+ if (NS_CONTENT_ATTR_HAS_VALUE == res && keygenvalue.Equals(NS_LITERAL_STRING("-mozilla-keygen"))) {
+
+ res = selectElement->GetAttribute(NS_LITERAL_STRING("pqg"), pqgValue);
+ res = selectElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
+ if (NS_FAILED(res) || keyTypeValue.IsEmpty()) {
+ // If this field is not present, we default to rsa.
+ keyTypeValue.AssignWithConversion("rsa");
+ }
+ res = selectElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
+ rv = GetPublicKey(aValue, challengeValue, keyTypeValue,
+ publicKey, pqgValue);
+ aValue = publicKey;
+ }
+ }
+
+ return rv;
+}
+
+NS_METHOD nsKeygenFormProcessor::ProvideContent(const nsString& aFormType,
+ nsVoidArray& aContent,
+ nsString& aAttribute)
+{
+ nsString selectKey;
+ SECKeySizeChoiceInfo *choice = SECKeySizeChoiceList;
+
+ selectKey.AssignWithConversion("SELECT");
+ if (Compare(aFormType, NS_LITERAL_STRING("SELECT"),
+ nsCaseInsensitiveStringComparator()) == 0) {
+ for (SECKeySizeChoiceInfo* choice = SECKeySizeChoiceList; choice && choice->name; ++choice) {
+ nsString *str = new nsString(choice->name);
+ aContent.AppendElement(str);
+ }
+ aAttribute.AssignWithConversion(mozKeyGen);
+ }
+ return NS_OK;
+}
+
+
+
diff --git a/security/manager/ssl/src/nsKeygenHandler.h b/security/manager/ssl/src/nsKeygenHandler.h
new file mode 100644
index 00000000000..545707822f6
--- /dev/null
+++ b/security/manager/ssl/src/nsKeygenHandler.h
@@ -0,0 +1,62 @@
+/* -*- 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) 2001 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ * David Drinan. (ddrinan@netscape.com)
+ *
+ */
+
+#ifndef _NSKEYGENHANDLER_H_
+#define _NSKEYGENHANDLER_H_
+// Form Processor
+#include "nsIFormProcessor.h"
+
+typedef struct SECKeySizeChoiceInfoStr {
+ PRUnichar *name;
+ int size;
+} SECKeySizeChoiceInfo;
+
+class nsKeygenFormProcessor : public nsIFormProcessor {
+public:
+ nsKeygenFormProcessor();
+ virtual ~nsKeygenFormProcessor();
+ nsresult Init();
+
+ NS_IMETHOD ProcessValue(nsIDOMHTMLElement *aElement,
+ const nsString& aName,
+ nsString& aValue);
+
+ NS_IMETHOD ProvideContent(const nsString& aFormType,
+ nsVoidArray& aContent,
+ nsString& aAttribute);
+ NS_DECL_ISUPPORTS
+
+ static NS_METHOD Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult);
+
+protected:
+ nsresult GetPublicKey(nsString& aValue, nsString& aChallenge,
+ nsString& akeyType, nsString& aOutPublicKey,
+ nsString& aPqg);
+ nsresult GetSlot(PRUint32 aMechanism, PK11SlotInfo** aSlot);
+private:
+ nsCOMPtr m_ctx;
+
+};
+
+#endif //_NSKEYGENHANDLER_H_
diff --git a/security/manager/ssl/src/nsNSSCertificate.cpp b/security/manager/ssl/src/nsNSSCertificate.cpp
index 241ff3c6227..c05ebeea33c 100644
--- a/security/manager/ssl/src/nsNSSCertificate.cpp
+++ b/security/manager/ssl/src/nsNSSCertificate.cpp
@@ -32,7 +32,7 @@
* may use your version of this file under either the MPL or the
* GPL.
*
- * $Id: nsNSSCertificate.cpp,v 1.20 2001-05-02 22:27:47 javi%netscape.com Exp $
+ * $Id: nsNSSCertificate.cpp,v 1.21 2001-05-03 01:00:56 ddrinan%netscape.com Exp $
*/
#include "prmem.h"
@@ -54,6 +54,7 @@
#include "nsDateTimeFormatCID.h"
#include "nsILocaleService.h"
+#include "nspr.h"
extern "C" {
#include "pk11func.h"
#include "certdb.h"
@@ -2160,6 +2161,234 @@ done:
return (srv) ? NS_ERROR_FAILURE : NS_OK;
}
+static char *
+default_nickname(CERTCertificate *cert, nsIInterfaceRequestor* ctx)
+{
+ nsresult rv;
+ char *username = NULL;
+ char *caname = NULL;
+ char *nickname = NULL;
+ char *tmp = NULL;
+ int count;
+ char *nickFmt=NULL, *nickFmtWithNum = NULL;
+ CERTCertificate *dummycert;
+ PK11SlotInfo *slot=NULL;
+ CK_OBJECT_HANDLE keyHandle;
+ nsAutoString tmpNickFmt;
+ nsAutoString tmpNickFmtWithNum;
+
+ CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
+ nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv));
+ if (NS_FAILED(rv)) goto loser;
+
+ username = CERT_GetCommonName(&cert->subject);
+ if ( username == NULL )
+ username = PL_strdup("");
+
+ if ( username == NULL )
+ goto loser;
+
+ caname = CERT_GetOrgName(&cert->issuer);
+ if ( caname == NULL )
+ caname = PL_strdup("");
+
+ if ( caname == NULL )
+ goto loser;
+
+ count = 1;
+ nssComponent->GetPIPNSSBundleString(
+ NS_LITERAL_STRING("nick_template").get(),
+ tmpNickFmt);
+ nickFmt = tmpNickFmt.ToNewUTF8String();
+
+ nssComponent->GetPIPNSSBundleString(
+ NS_LITERAL_STRING("nick_template_with_num").get(),
+ tmpNickFmtWithNum);
+ nickFmtWithNum = tmpNickFmtWithNum.ToNewUTF8String();
+
+
+ nickname = PR_smprintf(nickFmt, username, caname);
+ /*
+ * We need to see if the private key exists on a token, if it does
+ * then we need to check for nicknames that already exist on the smart
+ * card.
+ */
+ slot = PK11_KeyForCertExists(cert, &keyHandle, ctx);
+ if (slot == NULL) {
+ goto loser;
+ }
+ if (!PK11_IsInternal(slot)) {
+ tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), nickname);
+ PR_Free(nickname);
+ nickname = tmp;
+ tmp = NULL;
+ }
+ tmp = nickname;
+ while ( 1 ) {
+ if ( count > 1 ) {
+ nickname = PR_smprintf("%s #%d", tmp, count);
+ }
+
+ if ( nickname == NULL )
+ goto loser;
+
+ if (PK11_IsInternal(slot)) {
+ /* look up the nickname to make sure it isn't in use already */
+ dummycert = CERT_FindCertByNickname(defaultcertdb, nickname);
+
+ } else {
+ /*
+ * Check the cert against others that already live on the smart
+ * card.
+ */
+ dummycert = PK11_FindCertFromNickname(nickname, ctx);
+ if (dummycert != NULL) {
+ /*
+ * Make sure the subject names are different.
+ */
+ if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
+ {
+ /*
+ * There is another certificate with the same nickname and
+ * the same subject name on the smart card, so let's use this
+ * nickname.
+ */
+ CERT_DestroyCertificate(dummycert);
+ dummycert = NULL;
+ }
+ }
+ }
+ if ( dummycert == NULL )
+ goto done;
+
+ /* found a cert, destroy it and loop */
+ CERT_DestroyCertificate(dummycert);
+ if (tmp != nickname) PR_Free(nickname);
+ count++;
+ } /* end of while(1) */
+
+loser:
+ if ( nickname ) {
+ PR_Free(nickname);
+ }
+ nickname = NULL;
+done:
+ if ( caname ) {
+ PR_Free(caname);
+ }
+ if ( username ) {
+ PR_Free(username);
+ }
+ if (slot != NULL) {
+ PK11_FreeSlot(slot);
+ if (nickname != NULL) {
+ tmp = nickname;
+ nickname = strchr(tmp, ':');
+ if (nickname != NULL) {
+ nickname++;
+ nickname = PL_strdup(nickname);
+ PR_Free(tmp);
+ } else {
+ nickname = tmp;
+ tmp = NULL;
+ }
+ }
+ }
+ PR_FREEIF(tmp);
+ return(nickname);
+}
+static SECStatus
+collect_certs(void *arg, SECItem **certs, int numcerts)
+{
+ CERTDERCerts *collectArgs;
+ SECItem *cert;
+ SECStatus rv;
+
+ collectArgs = (CERTDERCerts *)arg;
+
+ collectArgs->numcerts = numcerts;
+ collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
+ sizeof(SECItem) * numcerts);
+ if ( collectArgs->rawCerts == NULL )
+ return(SECFailure);
+ cert = collectArgs->rawCerts;
+
+ while ( numcerts-- ) {
+ rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
+ if ( rv == SECFailure )
+ return(SECFailure);
+ cert++;
+ certs++;
+ }
+
+ return (SECSuccess);
+}
+
+NS_IMETHODIMP
+nsNSSCertificateDB::ImportUserCertificate(char *data, PRUint32 length, nsIInterfaceRequestor *ctx)
+{
+ PK11SlotInfo *slot;
+ char * nickname = NULL;
+ SECStatus sec_rv;
+ int numCACerts;
+ SECItem *CACerts;
+ CERTDERCerts * collectArgs;
+ PRArenaPool *arena;
+ CERTCertificate * cert=NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if ( arena == NULL )
+ goto loser;
+
+ collectArgs = (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
+ if ( collectArgs == NULL )
+ goto loser;
+
+ collectArgs->arena = arena;
+ sec_rv = CERT_DecodeCertPackage(data, length, collect_certs,
+ (void *)collectArgs);
+ if (sec_rv != PR_SUCCESS)
+ goto loser;
+
+ cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
+ (char *)NULL, PR_FALSE, PR_TRUE);
+ if (!cert)
+ goto loser;
+
+ slot = PK11_KeyForCertExists(cert, NULL, ctx);
+ if ( slot == NULL ) {
+ goto loser;
+ }
+ PK11_FreeSlot(slot);
+
+ /* pick a nickname for the cert */
+ if (cert->subjectList && cert->subjectList->entry &&
+ cert->subjectList->entry->nickname) {
+ nickname = cert->subjectList->entry->nickname;
+ } else {
+ nickname = default_nickname(cert, ctx);
+ }
+
+ /* user wants to import the cert */
+ slot = PK11_ImportCertForKey(cert, nickname, ctx);
+ if (!slot)
+ goto loser;
+ PK11_FreeSlot(slot);
+ numCACerts = collectArgs->numcerts - 1;
+
+ if (numCACerts) {
+ CACerts = collectArgs->rawCerts+1;
+ sec_rv = CERT_ImportCAChain(CACerts, numCACerts, certUsageUserCertImport);
+ }
+
+loser:
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ CERT_DestroyCertificate(cert);
+ return (sec_rv) ? NS_ERROR_FAILURE : NS_OK;
+}
+
/*
* void deleteCertificate(in nsIX509Cert aCert);
*/
diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp
index baccefb9a6f..bf53ec9acb9 100644
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -585,7 +585,7 @@ PipUIContext::~PipUIContext()
/* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
NS_IMETHODIMP PipUIContext::GetInterface(const nsIID & uuid, void * *result)
{
- nsresult rv;
+ nsresult rv = NS_OK;
if (uuid.Equals(NS_GET_IID(nsIPrompt))) {
nsCOMPtr proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
@@ -795,6 +795,17 @@ CertDownloader::OnDataAvailable(nsIRequest* request,
PRUint32 amt;
nsresult err;
+ //Do a check to see if we need to allocate more memory.
+ if ((mBufferOffset + (PRInt32)aLength) > mContentLength) {
+ size_t newSize = mContentLength + kDefaultCertAllocLength;
+ char *newBuffer;
+ newBuffer = (char*)nsMemory::Realloc(mByteData, newSize);
+ if (newBuffer == nsnull) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ mByteData = newBuffer;
+ mContentLength = newSize;
+ }
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDownloader::OnDataAvailable\n"));
do {
@@ -819,24 +830,35 @@ CertDownloader::OnStopRequest(nsIRequest* request,
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDownloader::OnStopRequest\n"));
/* this will init NSS if it hasn't happened already */
nsCOMPtr certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
- nsCOMPtr cert = new nsNSSCertificate(mByteData, mBufferOffset);
- if (certdb == nsnull)
- return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr ctx = new CertDownloaderContext();
- nsCOMPtr dialogs;
- PRBool canceled;
- PRUint32 trust;
- rv = ::getNSSDialogs(getter_AddRefs(dialogs),
- NS_GET_IID(nsICertificateDialogs));
- if (NS_FAILED(rv)) goto loser;
- rv = dialogs->DownloadCACert(ctx, cert, &trust, &canceled);
- if (NS_FAILED(rv)) goto loser;
- if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
- PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trust));
- return certdb->ImportCertificate(cert, mType, trust, nsnull);
+ switch (mType) {
+ case nsIX509Cert::CA_CERT:
+ {
+ nsCOMPtr cert = new nsNSSCertificate(mByteData, mBufferOffset);
+ if (certdb == nsnull)
+ return NS_ERROR_FAILURE;
+ nsCOMPtr dialogs;
+ PRBool canceled;
+ PRUint32 trust;
+ rv = ::getNSSDialogs(getter_AddRefs(dialogs),
+ NS_GET_IID(nsICertificateDialogs));
+ if (NS_FAILED(rv)) goto loser;
+ rv = dialogs->DownloadCACert(ctx, cert, &trust, &canceled);
+ if (NS_FAILED(rv)) goto loser;
+ if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trust));
+
+ return certdb->ImportCertificate(cert, mType, trust, nsnull);
+ }
+ case nsIX509Cert::USER_CERT:
+ return certdb->ImportUserCertificate(mByteData, mBufferOffset, ctx);
+ default:
+ rv = NS_ERROR_FAILURE;
+ break;
+ }
loser:
return rv;
}
diff --git a/security/manager/ssl/src/nsNSSModule.cpp b/security/manager/ssl/src/nsNSSModule.cpp
index 0dd73d04839..4eb5a475dbf 100644
--- a/security/manager/ssl/src/nsNSSModule.cpp
+++ b/security/manager/ssl/src/nsNSSModule.cpp
@@ -30,6 +30,7 @@
#include "nsSecureBrowserUIImpl.h"
#include "nsSSLSocketProvider.h"
#include "nsTLSSocketProvider.h"
+#include "nsKeygenHandler.h"
#include "nsCURILoader.h"
@@ -149,6 +150,13 @@ static nsModuleComponentInfo components[] =
nsNSSCertificateDBConstructor
},
+ {
+ "Form Processor",
+ NS_FORMPROCESSOR_CID,
+ NS_FORMPROCESSOR_CONTRACTID,
+ nsKeygenFormProcessor::Create
+ },
+
{
"Certificate Outliner",
NS_CERTOUTLINER_CID,