Back to index

lightning-sunbird  0.9+nobinonly
nsKeygenHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 extern "C" {
00040 #include "secdert.h"
00041 }
00042 #include "nspr.h"
00043 #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
00044 #include "keyhi.h"
00045 #include "secder.h"
00046 #include "cryptohi.h"
00047 #include "base64.h"
00048 #include "secasn1.h"
00049 extern "C" {
00050 #include "pk11pqg.h"
00051 }
00052 #include "nsProxiedService.h"
00053 #include "nsKeygenHandler.h"
00054 #include "nsVoidArray.h"
00055 #include "nsIServiceManager.h"
00056 #include "nsIDOMHTMLSelectElement.h"
00057 #include "nsIContent.h"
00058 #include "nsKeygenThread.h"
00059 #include "nsReadableUtils.h"
00060 #include "nsUnicharUtils.h"
00061 #include "nsCRT.h"
00062 #include "nsITokenDialogs.h"
00063 #include "nsIGenKeypairInfoDlg.h"
00064 #include "nsNSSShutDown.h"
00065 
00066 //These defines are taken from the PKCS#11 spec
00067 #define CKM_RSA_PKCS_KEY_PAIR_GEN     0x00000000
00068 #define CKM_DH_PKCS_KEY_PAIR_GEN      0x00000020
00069 #define CKM_DSA_KEY_PAIR_GEN          0x00000010
00070 
00071 //All possible key size choices.
00072 static SECKeySizeChoiceInfo SECKeySizeChoiceList[] = {
00073     { nsnull, 2048 },
00074     { nsnull, 1024 },
00075     { nsnull, 0 }, 
00076 };
00077 
00078 DERTemplate SECAlgorithmIDTemplate[] = {
00079     { DER_SEQUENCE,
00080          0, NULL, sizeof(SECAlgorithmID) },
00081     { DER_OBJECT_ID,
00082          offsetof(SECAlgorithmID,algorithm), },
00083     { DER_OPTIONAL | DER_ANY,
00084          offsetof(SECAlgorithmID,parameters), },
00085     { 0, }
00086 };
00087 
00088 DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
00089     { DER_SEQUENCE,
00090           0, nsnull, sizeof(CERTSubjectPublicKeyInfo) },
00091     { DER_INLINE,
00092           offsetof(CERTSubjectPublicKeyInfo,algorithm),
00093           SECAlgorithmIDTemplate, },
00094     { DER_BIT_STRING,
00095           offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
00096     { 0, }
00097 };
00098 
00099 DERTemplate CERTPublicKeyAndChallengeTemplate[] =
00100 {
00101     { DER_SEQUENCE, 0, nsnull, sizeof(CERTPublicKeyAndChallenge) },
00102     { DER_ANY, offsetof(CERTPublicKeyAndChallenge,spki), },
00103     { DER_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge), },
00104     { 0, }
00105 };
00106 
00107 const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = {
00108     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) },
00109     { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) },
00110     { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) },
00111     { SEC_ASN1_INTEGER, offsetof(PQGParams,base) },
00112     { 0, }
00113 };
00114 
00115 
00116 static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
00117 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
00118 
00119 static PQGParams *
00120 decode_pqg_params(char *aStr)
00121 {
00122     unsigned char *buf = nsnull;
00123     unsigned int len;
00124     PRArenaPool *arena = nsnull;
00125     PQGParams *params = nsnull;
00126     SECStatus status;
00127 
00128     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00129     if (!arena)
00130         return nsnull;
00131 
00132     params = NS_STATIC_CAST(PQGParams*, PORT_ArenaZAlloc(arena, sizeof(PQGParams)));
00133     if (!params)
00134         goto loser;
00135     params->arena = arena;
00136 
00137     buf = ATOB_AsciiToData(aStr, &len);
00138     if ((!buf) || (len == 0))
00139         goto loser;
00140 
00141     status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, (const char*)buf, len);
00142     if (status != SECSuccess)
00143         goto loser;
00144 
00145     return params;
00146 
00147 loser:
00148     if (arena) {
00149       PORT_FreeArena(arena, PR_FALSE);
00150     }
00151     if (buf) {
00152       PR_Free(buf);
00153     }
00154     return nsnull;
00155 }
00156 
00157 static int
00158 pqg_prime_bits(char *str)
00159 {
00160     PQGParams *params = nsnull;
00161     int primeBits = 0, i;
00162 
00163     params = decode_pqg_params(str);
00164     if (!params)
00165         goto done; /* lose */
00166 
00167     for (i = 0; params->prime.data[i] == 0; i++)
00168         /* empty */;
00169     primeBits = (params->prime.len - i) * 8;
00170 
00171 done:
00172     if (params)
00173         PK11_PQG_DestroyParams(params);
00174     return primeBits;
00175 }
00176 
00177 NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenFormProcessor, nsIFormProcessor)
00178 MOZ_DECL_CTOR_COUNTER(nsKeygenFormProcessor)
00179 
00180 nsKeygenFormProcessor::nsKeygenFormProcessor()
00181 { 
00182    MOZ_COUNT_CTOR(nsKeygenFormProcessor);
00183    m_ctx = new PipUIContext();
00184 
00185 } 
00186 
00187 nsKeygenFormProcessor::~nsKeygenFormProcessor()
00188 {
00189   MOZ_COUNT_DTOR(nsKeygenFormProcessor);
00190 }
00191 
00192 NS_METHOD
00193 nsKeygenFormProcessor::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
00194 {
00195   nsresult rv;
00196   NS_ENSURE_NO_AGGREGATION(aOuter);
00197   nsKeygenFormProcessor* formProc = new nsKeygenFormProcessor();
00198   if (!formProc)
00199     return NS_ERROR_OUT_OF_MEMORY;
00200 
00201   nsCOMPtr<nsISupports> stabilize = formProc;
00202   rv = formProc->Init();
00203   if (NS_SUCCEEDED(rv)) {
00204     rv = formProc->QueryInterface(aIID, aResult);
00205   }
00206   return rv;
00207 }
00208 
00209 nsresult
00210 nsKeygenFormProcessor::Init()
00211 {
00212   nsresult rv;
00213   nsAutoString str;
00214 
00215   if (SECKeySizeChoiceList[0].name != NULL)
00216     return NS_OK;
00217 
00218   // Get the key strings //
00219   nsCOMPtr<nsINSSComponent> nssComponent;
00220   nssComponent = do_GetService(kNSSComponentCID, &rv);
00221   if (NS_FAILED(rv))
00222     return rv;
00223 
00224   nssComponent->GetPIPNSSBundleString("HighGrade", str);
00225   SECKeySizeChoiceList[0].name = ToNewUnicode(str);
00226 
00227   nssComponent->GetPIPNSSBundleString("MediumGrade", str);
00228   SECKeySizeChoiceList[1].name = ToNewUnicode(str);
00229 
00230   return NS_OK;
00231 }
00232 
00233 nsresult
00234 nsKeygenFormProcessor::GetSlot(PRUint32 aMechanism, PK11SlotInfo** aSlot)
00235 {
00236   return GetSlotWithMechanism(aMechanism,m_ctx,aSlot);
00237 }
00238 
00239 
00240 PRUint32 MapGenMechToAlgoMech(PRUint32 mechanism)
00241 {
00242     PRUint32 searchMech;
00243 
00244     /* We are interested in slots based on the ability to perform
00245        a given algorithm, not on their ability to generate keys usable
00246        by that algorithm. Therefore, map keygen-specific mechanism tags
00247        to tags for the corresponding crypto algorthm. */
00248     switch(mechanism)
00249     {
00250     case CKM_RSA_PKCS_KEY_PAIR_GEN:
00251         searchMech = CKM_RSA_PKCS;
00252         break;
00253     case CKM_DSA_KEY_PAIR_GEN:
00254         searchMech = CKM_DSA;
00255         break;
00256     case CKM_RC4_KEY_GEN:
00257         searchMech = CKM_RC4;
00258         break;
00259     case CKM_DH_PKCS_KEY_PAIR_GEN:
00260         searchMech = CKM_DH_PKCS_DERIVE; /* ### mwelch  is this right? */
00261         break;
00262     case CKM_DES_KEY_GEN:
00263         /* What do we do about DES keygen? Right now, we're just using
00264            DES_KEY_GEN to look for tokens, because otherwise we'll have
00265            to search the token list three times. */
00266     default:
00267         searchMech = mechanism;
00268         break;
00269     }
00270     return searchMech;
00271 }
00272 
00273 
00274 nsresult
00275 GetSlotWithMechanism(PRUint32 aMechanism, 
00276                      nsIInterfaceRequestor *m_ctx,
00277                      PK11SlotInfo** aSlot)
00278 {
00279     nsNSSShutDownPreventionLock locker;
00280     PK11SlotList * slotList = nsnull;
00281     PRUnichar** tokenNameList = nsnull;
00282     nsITokenDialogs * dialogs;
00283     PRUnichar *unicodeTokenChosen;
00284     PK11SlotListElement *slotElement, *tmpSlot;
00285     PRUint32 numSlots = 0, i = 0;
00286     PRBool canceled;
00287     nsresult rv = NS_OK;
00288 
00289     *aSlot = nsnull;
00290 
00291     // Get the slot
00292     slotList = PK11_GetAllTokens(MapGenMechToAlgoMech(aMechanism), 
00293                                 PR_TRUE, PR_TRUE, m_ctx);
00294     if (!slotList || !slotList->head) {
00295         rv = NS_ERROR_FAILURE;
00296         goto loser;
00297     }
00298 
00299     if (!slotList->head->next) {
00300         /* only one slot available, just return it */
00301         *aSlot = slotList->head->slot;
00302       } else {
00303         // Gerenate a list of slots and ask the user to choose //
00304         tmpSlot = slotList->head;
00305         while (tmpSlot) {
00306             numSlots++;
00307             tmpSlot = tmpSlot->next;
00308         }
00309 
00310         // Allocate the slot name buffer //
00311         tokenNameList = NS_STATIC_CAST(PRUnichar**, nsMemory::Alloc(sizeof(PRUnichar *) * numSlots));
00312         if (!tokenNameList) {
00313             rv = NS_ERROR_OUT_OF_MEMORY;
00314             goto loser;
00315         }
00316 
00317         i = 0;
00318         slotElement = PK11_GetFirstSafe(slotList);
00319         while (slotElement) {
00320             tokenNameList[i] = UTF8ToNewUnicode(nsDependentCString(PK11_GetTokenName(slotElement->slot)));
00321             slotElement = PK11_GetNextSafe(slotList, slotElement, PR_FALSE);
00322             if (tokenNameList[i])
00323                 i++;
00324             else {
00325                 // OOM. adjust numSlots so we don't free unallocated memory. 
00326                 numSlots = i;
00327                 rv = NS_ERROR_OUT_OF_MEMORY;
00328                 goto loser;
00329             }
00330         }
00331 
00332               /* Throw up the token list dialog and get back the token */
00333               rv = getNSSDialogs((void**)&dialogs,
00334                                     NS_GET_IID(nsITokenDialogs),
00335                      NS_TOKENDIALOGS_CONTRACTID);
00336 
00337               if (NS_FAILED(rv)) goto loser;
00338 
00339     {
00340       nsPSMUITracker tracker;
00341       if (!tokenNameList || !*tokenNameList) {
00342           rv = NS_ERROR_OUT_OF_MEMORY;
00343       }
00344       else if (tracker.isUIForbidden()) {
00345         rv = NS_ERROR_NOT_AVAILABLE;
00346       }
00347       else {
00348               rv = dialogs->ChooseToken(nsnull, (const PRUnichar**)tokenNameList, numSlots, &unicodeTokenChosen, &canceled);
00349       }
00350     }
00351               NS_RELEASE(dialogs);
00352               if (NS_FAILED(rv)) goto loser;
00353 
00354               if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
00355 
00356         // Get the slot //
00357         slotElement = PK11_GetFirstSafe(slotList);
00358         nsAutoString tokenStr(unicodeTokenChosen);
00359         while (slotElement) {
00360             if (tokenStr.Equals(NS_ConvertUTF8toUCS2(PK11_GetTokenName(slotElement->slot)))) {
00361                 *aSlot = slotElement->slot;
00362                 break;
00363             }
00364             slotElement = PK11_GetNextSafe(slotList, slotElement, PR_FALSE);
00365         }
00366         if(!(*aSlot)) {
00367             rv = NS_ERROR_FAILURE;
00368             goto loser;
00369         }
00370       }
00371 
00372       // Get a reference to the slot //
00373       PK11_ReferenceSlot(*aSlot);
00374 loser:
00375       if (slotList) {
00376           PK11_FreeSlotList(slotList);
00377       }
00378       if (tokenNameList) {
00379           NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numSlots, tokenNameList);
00380       }
00381       return rv;
00382 }
00383 
00384 nsresult
00385 nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge, 
00386                                 nsAFlatString& aKeyType,
00387                                 nsAString& aOutPublicKey, nsAString& aPqg)
00388 {
00389     nsNSSShutDownPreventionLock locker;
00390     nsresult rv = NS_ERROR_FAILURE;
00391     char *keystring = nsnull;
00392     char *pqgString = nsnull, *str = nsnull;
00393     KeyType type;
00394     PRUint32 keyGenMechanism;
00395     PRInt32 primeBits;
00396     PQGParams *pqgParams;
00397     PK11SlotInfo *slot = nsnull;
00398     PK11RSAGenParams rsaParams;
00399     SECOidTag algTag;
00400     int keysize = 0;
00401     void *params;
00402     SECKEYPrivateKey *privateKey = nsnull;
00403     SECKEYPublicKey *publicKey = nsnull;
00404     CERTSubjectPublicKeyInfo *spkInfo = nsnull;
00405     PRArenaPool *arena = nsnull;
00406     SECStatus sec_rv = SECFailure;
00407     SECItem spkiItem;
00408     SECItem pkacItem;
00409     SECItem signedItem;
00410     CERTPublicKeyAndChallenge pkac;
00411     pkac.challenge.data = nsnull;
00412     SECKeySizeChoiceInfo *choice = SECKeySizeChoiceList;
00413     nsIGeneratingKeypairInfoDialogs * dialogs;
00414     nsKeygenThread *KeygenRunnable = 0;
00415     nsCOMPtr<nsIKeygenThread> runnable;
00416 
00417     // Get the key size //
00418     while (choice->name) {
00419         if (aValue.Equals(choice->name)) {
00420             keysize = choice->size;
00421             break;
00422         }
00423         choice++;
00424     }
00425     if (!keysize) {
00426         goto loser;
00427     }
00428 
00429     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00430     if (!arena) {
00431         goto loser;
00432     }
00433 
00434     // Set the keygen mechanism
00435     if (aKeyType.IsEmpty() || aKeyType.LowerCaseEqualsLiteral("rsa")) {
00436         type = rsaKey;
00437         keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
00438     } else if (aKeyType.LowerCaseEqualsLiteral("dsa")) {
00439         char * end;
00440         pqgString = ToNewCString(aPqg);
00441         if (!pqgString) {
00442             rv = NS_ERROR_OUT_OF_MEMORY;
00443             goto loser;
00444         }
00445 
00446         type = dsaKey;
00447         keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
00448         if (strcmp(pqgString, "null") == 0)
00449             goto loser;
00450         str = pqgString;
00451         do {
00452             end = strchr(str, ',');
00453             if (end != nsnull)
00454                 *end = '\0';
00455             primeBits = pqg_prime_bits(str);
00456             if (choice->size == primeBits)
00457                 goto found_match;
00458             str = end + 1;
00459         } while (end != nsnull);
00460         goto loser;
00461 found_match:
00462         pqgParams = decode_pqg_params(str);
00463     } else {
00464         goto loser;
00465     }
00466 
00467     // Get the slot
00468     rv = GetSlot(keyGenMechanism, &slot);
00469     if (NS_FAILED(rv)) {
00470         goto loser;
00471     }
00472       switch (keyGenMechanism) {
00473         case CKM_RSA_PKCS_KEY_PAIR_GEN:
00474             rsaParams.keySizeInBits = keysize;
00475             rsaParams.pe = DEFAULT_RSA_KEYGEN_PE;
00476             algTag = DEFAULT_RSA_KEYGEN_ALG;
00477             params = &rsaParams;
00478             break;
00479         case CKM_DSA_KEY_PAIR_GEN:
00480             // XXX Fix this! XXX //
00481             goto loser;
00482       default:
00483           goto loser;
00484       }
00485 
00486     /* Make sure token is initialized. */
00487     rv = setPassword(slot, m_ctx);
00488     if (NS_FAILED(rv))
00489     goto loser;
00490 
00491     sec_rv = PK11_Authenticate(slot, PR_TRUE, m_ctx);
00492     if (sec_rv != SECSuccess) {
00493         goto loser;
00494     }
00495 
00496     rv = getNSSDialogs((void**)&dialogs,
00497                        NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
00498                        NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
00499 
00500     if (NS_SUCCEEDED(rv)) {
00501         KeygenRunnable = new nsKeygenThread();
00502         if (KeygenRunnable) {
00503             NS_ADDREF(KeygenRunnable);
00504         }
00505     }
00506 
00507     if (NS_FAILED(rv) || !KeygenRunnable) {
00508         rv = NS_OK;
00509         privateKey = PK11_GenerateKeyPair(slot, keyGenMechanism, params,
00510                                           &publicKey, PR_TRUE, PR_TRUE, m_ctx);
00511     } else {
00512         KeygenRunnable->SetParams( slot, keyGenMechanism, params, PR_TRUE, PR_TRUE, m_ctx );
00513 
00514         runnable = do_QueryInterface(KeygenRunnable);
00515         
00516         if (runnable) {
00517             {
00518               nsPSMUITracker tracker;
00519               if (tracker.isUIForbidden()) {
00520                 rv = NS_ERROR_NOT_AVAILABLE;
00521               }
00522               else {
00523                 rv = dialogs->DisplayGeneratingKeypairInfo(m_ctx, runnable);
00524                 // We call join on the thread, 
00525                 // so we can be sure that no simultaneous access to the passed parameters will happen.
00526                 KeygenRunnable->Join();
00527               }
00528             }
00529 
00530             NS_RELEASE(dialogs);
00531             if (NS_SUCCEEDED(rv)) {
00532                 rv = KeygenRunnable->GetParams(&privateKey, &publicKey);
00533             }
00534         }
00535     }
00536     
00537     if (NS_FAILED(rv) || !privateKey) {
00538         goto loser;
00539     }
00540     // just in case we'll need to authenticate to the db -jp //
00541     privateKey->wincx = m_ctx;
00542 
00543     /*
00544      * Create a subject public key info from the public key.
00545      */
00546     spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
00547     if ( !spkInfo ) {
00548         goto loser;
00549     }
00550     
00551     /*
00552      * Now DER encode the whole subjectPublicKeyInfo.
00553      */
00554     sec_rv=DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, spkInfo);
00555     if (sec_rv != SECSuccess) {
00556         goto loser;
00557     }
00558 
00559     /*
00560      * set up the PublicKeyAndChallenge data structure, then DER encode it
00561      */
00562     pkac.spki = spkiItem;
00563     pkac.challenge.len = aChallenge.Length();
00564     pkac.challenge.data = (unsigned char *)ToNewCString(aChallenge);
00565     if (!pkac.challenge.data) {
00566         rv = NS_ERROR_OUT_OF_MEMORY;
00567         goto loser;
00568     }
00569     
00570     sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac);
00571     if ( sec_rv != SECSuccess ) {
00572         goto loser;
00573     }
00574 
00575     /*
00576      * now sign the DER encoded PublicKeyAndChallenge
00577      */
00578     sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
00579                       privateKey, algTag);
00580     if ( sec_rv != SECSuccess ) {
00581         goto loser;
00582     }
00583     
00584     /*
00585      * Convert the signed public key and challenge into base64/ascii.
00586      */
00587     keystring = BTOA_DataToAscii(signedItem.data, signedItem.len);
00588     if (!keystring) {
00589         rv = NS_ERROR_OUT_OF_MEMORY;
00590         goto loser;
00591     }
00592 
00593     CopyASCIItoUTF16(keystring, aOutPublicKey);
00594     nsCRT::free(keystring);
00595 
00596     rv = NS_OK;
00597 loser:
00598     if ( sec_rv != SECSuccess ) {
00599         if ( privateKey ) {
00600             PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
00601         }
00602         if ( publicKey ) {
00603             PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID);
00604         }
00605     }
00606     if ( spkInfo ) {
00607       SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
00608     }
00609     if ( publicKey ) {
00610         SECKEY_DestroyPublicKey(publicKey);
00611     }
00612     if ( privateKey ) {
00613         SECKEY_DestroyPrivateKey(privateKey);
00614     }
00615     if ( arena ) {
00616       PORT_FreeArena(arena, PR_TRUE);
00617     }
00618     if (slot != nsnull) {
00619         PK11_FreeSlot(slot);
00620     }
00621     if (KeygenRunnable) {
00622       NS_RELEASE(KeygenRunnable);
00623     }
00624     if (pqgString) {
00625         nsMemory::Free(pqgString);
00626     }
00627     if (pkac.challenge.data) {
00628         nsMemory::Free(pkac.challenge.data);
00629     }
00630     return rv;
00631 }
00632 
00633 NS_METHOD 
00634 nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement *aElement, 
00635                                 const nsAString& aName, 
00636                                 nsAString& aValue) 
00637 { 
00638   nsresult rv = NS_OK;
00639   nsCOMPtr<nsIDOMHTMLSelectElement>selectElement;
00640   nsresult res = aElement->QueryInterface(kIDOMHTMLSelectElementIID, 
00641                                      getter_AddRefs(selectElement));
00642   if (NS_SUCCEEDED(res)) {
00643     nsAutoString keygenvalue;
00644     nsAutoString challengeValue;
00645     nsAutoString keyTypeValue;
00646     nsAutoString pqgValue;
00647 
00648     res = selectElement->GetAttribute(NS_LITERAL_STRING("_moz-type"), keygenvalue);
00649     if (NS_CONTENT_ATTR_HAS_VALUE == res && keygenvalue.EqualsLiteral("-mozilla-keygen")) {
00650 
00651       res = selectElement->GetAttribute(NS_LITERAL_STRING("pqg"), pqgValue);
00652       res = selectElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
00653       if (NS_FAILED(res) || keyTypeValue.IsEmpty()) {
00654         // If this field is not present, we default to rsa.
00655            keyTypeValue.AssignLiteral("rsa");
00656       }
00657       res = selectElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
00658       rv = GetPublicKey(aValue, challengeValue, keyTypeValue, 
00659                      aValue, pqgValue);
00660     }
00661   }
00662 
00663   return rv; 
00664 } 
00665 
00666 NS_METHOD nsKeygenFormProcessor::ProvideContent(const nsAString& aFormType, 
00667                                           nsVoidArray& aContent, 
00668                                           nsAString& aAttribute) 
00669 { 
00670   if (Compare(aFormType, NS_LITERAL_STRING("SELECT"), 
00671     nsCaseInsensitiveStringComparator()) == 0) {
00672     for (SECKeySizeChoiceInfo* choice = SECKeySizeChoiceList; choice && choice->name; ++choice) {
00673       nsString *str = new nsString(choice->name);
00674       aContent.AppendElement(str);
00675     }
00676     aAttribute.AssignLiteral("-mozilla-keygen");
00677   }
00678   return NS_OK;
00679 } 
00680