summaryrefslogtreecommitdiff
path: root/security/nss/lib/fortcrypt/swfort/swfparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/fortcrypt/swfort/swfparse.c')
-rw-r--r--security/nss/lib/fortcrypt/swfort/swfparse.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/security/nss/lib/fortcrypt/swfort/swfparse.c b/security/nss/lib/fortcrypt/swfort/swfparse.c
new file mode 100644
index 000000000..4422cb18a
--- /dev/null
+++ b/security/nss/lib/fortcrypt/swfort/swfparse.c
@@ -0,0 +1,531 @@
+/*
+ * 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):
+ *
+ * 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.
+ */
+/*
+ * The following program decodes the FORTEZZA Init File, and stores the result
+ * into the fortezza directory.
+ */
+#include "secasn1.h"
+#include "swforti.h"
+#include "blapi.h"
+#include "secoid.h"
+#include "secitem.h"
+#include "secder.h"
+
+
+/*
+ * templates for parsing the FORTEZZA Init File. These were taken from DER
+ * definitions on SWF Initialization File Format Version 1.0 pp1-3.
+ */
+
+/* Key info structure... There are up to two of these per slot entry */
+static const SEC_ASN1Template fortKeyInfoTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(fortKeyInformation) },
+ { SEC_ASN1_INTEGER,
+ offsetof(fortKeyInformation,keyFlags) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortKeyInformation,privateKeyWrappedWithKs) },
+ { SEC_ASN1_ANY ,
+ offsetof(fortKeyInformation, derPublicKey) },
+ { SEC_ASN1_OCTET_STRING, offsetof(fortKeyInformation,p) },
+ { SEC_ASN1_OCTET_STRING, offsetof(fortKeyInformation,g) },
+ { SEC_ASN1_OCTET_STRING, offsetof(fortKeyInformation,q) },
+ { 0 }
+};
+
+/* This is data that has been wrapped by Ks */
+static const SEC_ASN1Template fortProtDataTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(fortProtectedData) },
+ { SEC_ASN1_INTEGER,
+ offsetof(fortProtectedData,length) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedData,dataIV) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedData,dataEncryptedWithKs) },
+ { 0 }
+};
+
+/* DER to describe each Certificate Slot ... there are an arbitrary number */
+static const SEC_ASN1Template fortSlotEntryTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(fortSlotEntry) },
+ { SEC_ASN1_BOOLEAN,
+ offsetof(fortSlotEntry,trusted) },
+ { SEC_ASN1_INTEGER,
+ offsetof(fortSlotEntry,certificateIndex) },
+ { SEC_ASN1_INLINE,
+ offsetof(fortSlotEntry,certificateLabel), fortProtDataTemplate },
+ { SEC_ASN1_INLINE,
+ offsetof(fortSlotEntry,certificateData), fortProtDataTemplate },
+ { SEC_ASN1_POINTER | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_CONSTRUCTED | 0,
+ offsetof(fortSlotEntry, exchangeKeyInformation),
+ fortKeyInfoTemplate },
+ { SEC_ASN1_POINTER | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_CONSTRUCTED | 1,
+ offsetof(fortSlotEntry, signatureKeyInformation),
+ fortKeyInfoTemplate },
+ { 0 }
+};
+
+/* This data is used to check MemPhrases, and to generate Ks
+ * each file has two mem phrases, one for SSO, one for User */
+static const SEC_ASN1Template fortProtectedMemPhrase[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(fortProtectedPhrase) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedPhrase,kValueIV) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedPhrase,wrappedKValue) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedPhrase,memPhraseIV) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedPhrase,hashedEncryptedMemPhrase) },
+ { 0 }
+};
+
+/* This data is used to check the Mem Init Phrases, and to generate Kinit
+ * each file has one mem init phrase, which is used only in transport of
+ * this file */
+static const SEC_ASN1Template fortMemInitPhrase[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(fortProtectedPhrase) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedPhrase,wrappedKValue) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedPhrase,memPhraseIV) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(fortProtectedPhrase,hashedEncryptedMemPhrase) },
+ { 0 }
+};
+
+static const SEC_ASN1Template fortSlotEntriesTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, fortSlotEntryTemplate }
+};
+
+/* This is the complete file with all it's data, but has not been signed
+ * yet. */
+static const SEC_ASN1Template fortSwFortezzaInitFileToSign[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(FORTSWFile) },
+ { SEC_ASN1_INTEGER,
+ offsetof(FORTSWFile,version) },
+ { SEC_ASN1_ANY,
+ offsetof(FORTSWFile,derIssuer) },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(FORTSWFile,serialID) },
+ { SEC_ASN1_INLINE,
+ offsetof(FORTSWFile,initMemPhrase), fortMemInitPhrase },
+ { SEC_ASN1_INLINE,
+ offsetof(FORTSWFile,ssoMemPhrase), fortProtectedMemPhrase },
+ { SEC_ASN1_INLINE,
+ offsetof(FORTSWFile,userMemPhrase), fortProtectedMemPhrase },
+ { SEC_ASN1_INLINE,
+ offsetof(FORTSWFile,ssoPinPhrase), fortProtectedMemPhrase },
+ { SEC_ASN1_INLINE,
+ offsetof(FORTSWFile,userPinPhrase), fortProtectedMemPhrase },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(FORTSWFile,wrappedRandomSeed) },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(FORTSWFile,slotEntries),
+ fortSlotEntryTemplate },
+ /* optional extentions to ignore here... */
+ { 0 }
+};
+
+/* The complete, signed init file */
+static const SEC_ASN1Template fortSwFortezzaInitFile[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(FORTSignedSWFile) },
+ { SEC_ASN1_SAVE,
+ offsetof(FORTSignedSWFile,signatureWrap.data) },
+ { SEC_ASN1_INLINE,
+ offsetof(FORTSignedSWFile,file),
+ fortSwFortezzaInitFileToSign },
+ { SEC_ASN1_INLINE,
+ offsetof(FORTSignedSWFile,signatureWrap.signatureAlgorithm),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_BIT_STRING,
+ offsetof(FORTSignedSWFile,signatureWrap.signature) },
+ { 0 }
+};
+
+FORTSkipjackKeyPtr
+fort_CalculateKMemPhrase(FORTSWFile *file,
+ fortProtectedPhrase * prot_phrase, char *phrase, FORTSkipjackKeyPtr wrapKey)
+{
+ unsigned char *data = NULL;
+ unsigned char hashout[SHA1_LENGTH];
+ int data_len = prot_phrase->wrappedKValue.len;
+ int ret;
+ unsigned int len;
+ unsigned int version;
+ unsigned char enc_version[2];
+ FORTSkipjackKeyPtr Kout = NULL;
+ FORTSkipjackKey Kfek;
+ SHA1Context *sha;
+
+ data = (unsigned char *) PORT_ZAlloc(data_len);
+ if (data == NULL) goto fail;
+
+ PORT_Memcpy(data,prot_phrase->wrappedKValue.data,data_len);
+
+ /* if it's a real protected mem phrase, it's been wrapped by kinit, which
+ * was passed to us. */
+ if (wrapKey) {
+ fort_skipjackDecrypt(wrapKey,
+ &prot_phrase->kValueIV.data[SKIPJACK_LEAF_SIZE],data_len,
+ data,data);
+ data_len = sizeof(CI_KEY);
+ }
+
+ /* now calculate the PBE key for fortezza */
+ sha = SHA1_NewContext();
+ if (sha == NULL) goto fail;
+ SHA1_Begin(sha);
+ version = DER_GetUInteger(&file->version);
+ enc_version[0] = (version >> 8) & 0xff;
+ enc_version[1] = version & 0xff;
+ SHA1_Update(sha,enc_version,sizeof(enc_version));
+ SHA1_Update(sha,file->derIssuer.data, file->derIssuer.len);
+ SHA1_Update(sha,file->serialID.data, file->serialID.len);
+ SHA1_Update(sha,(unsigned char *)phrase,strlen(phrase));
+ SHA1_End(sha,hashout,&len,SHA1_LENGTH);
+ SHA1_DestroyContext(sha, PR_TRUE);
+ PORT_Memcpy(Kfek,hashout,sizeof(FORTSkipjackKey));
+
+ /* now use that key to unwrap */
+ Kout = (FORTSkipjackKeyPtr) PORT_Alloc(sizeof(FORTSkipjackKey));
+ ret = fort_skipjackUnwrap(Kfek,data_len,data,Kout);
+ if (ret != CI_OK) {
+ PORT_Free(Kout);
+ Kout = NULL;
+ }
+
+fail:
+ PORT_Memset(&Kfek, 0, sizeof(FORTSkipjackKey));
+ if (data) PORT_ZFree(data,data_len);
+ return Kout;
+}
+
+
+PRBool
+fort_CheckMemPhrase(FORTSWFile *file,
+ fortProtectedPhrase * prot_phrase, char *phrase, FORTSkipjackKeyPtr wrapKey)
+{
+ unsigned char *data = NULL;
+ unsigned char hashout[SHA1_LENGTH];
+ int data_len = prot_phrase->hashedEncryptedMemPhrase.len;
+ unsigned int len;
+ SHA1Context *sha;
+ PRBool pinOK = PR_FALSE;
+ unsigned char cw[4];
+ int i;
+
+
+ /* first, decrypt the hashed/Encrypted Memphrase */
+ data = (unsigned char *) PORT_ZAlloc(data_len);
+ if (data == NULL) goto failed;
+
+ PORT_Memcpy(data,prot_phrase->hashedEncryptedMemPhrase.data,data_len);
+ fort_skipjackDecrypt(wrapKey,
+ &prot_phrase->memPhraseIV.data[SKIPJACK_LEAF_SIZE],data_len,
+ data,data);
+
+ /* now build the hash for comparisons */
+ sha = SHA1_NewContext();
+ if (sha == NULL) goto failed;
+ SHA1_Begin(sha);
+ SHA1_Update(sha,(unsigned char *)phrase,strlen(phrase));
+ SHA1_End(sha,hashout,&len,SHA1_LENGTH);
+ SHA1_DestroyContext(sha, PR_TRUE);
+
+ /* hashes don't match... must not be the right pass mem */
+ if (PORT_Memcmp(data,hashout,len) != 0) goto failed;
+
+ /* now calcuate the checkword and compare it */
+ cw[0] = cw[1] = cw[2] = cw[3] = 0;
+ for (i=0; i <5 ; i++) {
+ cw[0] = cw[0] ^ hashout[i*4];
+ cw[1] = cw[1] ^ hashout[i*4+1];
+ cw[2] = cw[2] ^ hashout[i*4+2];
+ cw[3] = cw[3] ^ hashout[i*4+3];
+ }
+
+ /* checkword doesn't match, must not be the right pass mem */
+ if (PORT_Memcmp(data+len,cw,4) != 0) goto failed;
+
+ /* pased all our test, its OK */
+ pinOK = PR_TRUE;
+
+failed:
+ PORT_Free(data);
+
+ return pinOK;
+}
+
+/*
+ * walk through the list of memphrases. This function allows us to use a
+ * for loop to walk down them.
+ */
+fortProtectedPhrase *
+fort_getNextPhrase( FORTSWFile *file, fortProtectedPhrase *last)
+{
+ if (last == &file->userMemPhrase) {
+ return &file->userPinPhrase;
+ }
+ /* we can add more test here if we want to support SSO mode someday. */
+
+ return NULL;
+}
+
+/*
+ * decode the DER file data into our nice data structures, including turning
+ * cert indexes into integers.
+ */
+FORTSignedSWFile *
+FORT_GetSWFile(SECItem *initBits)
+{
+ FORTSignedSWFile *sw_init_file;
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ int i, count;
+
+ /* get the local arena... be sure to free this at the end */
+
+ /* get the local arena... be sure to free this at the end */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) goto fail;
+
+ sw_init_file = (FORTSignedSWFile *)
+ PORT_ArenaZAlloc(arena,sizeof(FORTSignedSWFile));
+ if (sw_init_file == NULL) goto fail;
+
+ /* ANS1 decode the complete init file */
+ rv = SEC_ASN1DecodeItem(arena,sw_init_file,fortSwFortezzaInitFile,initBits);
+ if (rv != SECSuccess) {
+ goto fail;
+ }
+
+ /* count the certs */
+ count = 0;
+ while (sw_init_file->file.slotEntries[count]) count++;
+
+ for (i=0; i < count; i++) {
+ /* update the cert Index Pointers */
+ sw_init_file->file.slotEntries[i]->certIndex =
+ DER_GetInteger(&sw_init_file->
+ file.slotEntries[i]->certificateIndex );
+ }
+
+ /* now start checking the mem phrases and pins, as well as calculating the
+ * file's 'K' values. First we start with K(init). */
+ sw_init_file->file.arena = arena;
+
+ return sw_init_file;
+ /* OK now that we've read in the init file, and now have Kinit, Ks, and the
+ * appropriate Pin Phrase, we need to build our database file. */
+
+fail:
+ if (arena) PORT_FreeArena(arena,PR_TRUE);
+ return NULL;
+}
+
+/*
+ * Check the init memphrases and the user mem phrases. Remove all the init
+ * memphrase wrappings. Save the Kinit and Ks values for use.
+ */
+SECStatus
+FORT_CheckInitPhrase(FORTSignedSWFile *sw_init_file, char *initMemPhrase)
+{
+ SECStatus rv = SECFailure;
+
+ sw_init_file->Kinit = fort_CalculateKMemPhrase(&sw_init_file->file,
+ &sw_init_file->file.initMemPhrase, initMemPhrase, NULL);
+ if (sw_init_file->Kinit == NULL) goto fail;
+
+ /* now check the init Mem phrase */
+ if (!fort_CheckMemPhrase(&sw_init_file->file,
+ &sw_init_file->file.initMemPhrase,
+ initMemPhrase, sw_init_file->Kinit)) {
+ goto fail;
+ }
+ rv = SECSuccess;
+
+fail:
+ return rv;
+}
+
+ /* now check user user mem phrase and calculate Ks */
+SECStatus
+FORT_CheckUserPhrase(FORTSignedSWFile *sw_init_file, char *userMemPhrase)
+{
+ SECStatus rv = SECFailure;
+ char tmp_data[13];
+ char *padMemPhrase = NULL;
+ fortProtectedPhrase *phrase_store;
+
+ if (strlen(userMemPhrase) < 12) {
+ PORT_Memset(tmp_data, ' ', sizeof(tmp_data));
+ PORT_Memcpy(tmp_data,userMemPhrase,strlen(userMemPhrase));
+ tmp_data[12] = 0;
+ padMemPhrase = tmp_data;
+ }
+
+ for (phrase_store = &sw_init_file->file.userMemPhrase; phrase_store;
+ phrase_store = fort_getNextPhrase(&sw_init_file->file,phrase_store)) {
+ sw_init_file->Ks = fort_CalculateKMemPhrase(&sw_init_file->file,
+ phrase_store, userMemPhrase, sw_init_file->Kinit);
+
+ if ((sw_init_file->Ks == NULL) && (padMemPhrase != NULL)) {
+ sw_init_file->Ks = fort_CalculateKMemPhrase(&sw_init_file->file,
+ phrase_store, padMemPhrase, sw_init_file->Kinit);
+ userMemPhrase = padMemPhrase;
+ }
+ if (sw_init_file->Ks == NULL) {
+ continue;
+ }
+
+ /* now check the User Mem phrase */
+ if (fort_CheckMemPhrase(&sw_init_file->file, phrase_store,
+ userMemPhrase, sw_init_file->Ks)) {
+ break;
+ }
+ PORT_Free(sw_init_file->Ks);
+ sw_init_file->Ks = NULL;
+ }
+
+
+ if (phrase_store == NULL) goto fail;
+
+ /* strip the Kinit wrapping */
+ fort_skipjackDecrypt(sw_init_file->Kinit,
+ &phrase_store->kValueIV.data[SKIPJACK_LEAF_SIZE],
+ phrase_store->wrappedKValue.len, phrase_store->wrappedKValue.data,
+ phrase_store->wrappedKValue.data);
+ phrase_store->wrappedKValue.len = 12;
+
+ PORT_Memset(phrase_store->kValueIV.data,0,phrase_store->kValueIV.len);
+
+ sw_init_file->file.initMemPhrase = *phrase_store;
+ sw_init_file->file.ssoMemPhrase = *phrase_store;
+ sw_init_file->file.ssoPinPhrase = *phrase_store;
+ sw_init_file->file.userMemPhrase = *phrase_store;
+ sw_init_file->file.userPinPhrase = *phrase_store;
+
+
+ rv = SECSuccess;
+
+fail:
+ /* don't keep the pin around */
+ PORT_Memset(tmp_data, 0, sizeof(tmp_data));
+ return rv;
+}
+
+void
+FORT_DestroySWFile(FORTSWFile *file)
+{
+ PORT_FreeArena(file->arena,PR_FALSE);
+}
+
+void
+FORT_DestroySignedSWFile(FORTSignedSWFile *swfile)
+{
+ FORT_DestroySWFile(&swfile->file);
+}
+
+
+SECItem *
+FORT_GetDERCert(FORTSignedSWFile *swfile,int index)
+{
+ SECItem *newItem = NULL;
+ unsigned char *cert = NULL;
+ int len,ret;
+ fortSlotEntry *certEntry = NULL;
+
+
+ newItem = PORT_ZNew(SECItem);
+ if (newItem == NULL) return NULL;
+
+ certEntry = fort_GetCertEntry(&swfile->file,index);
+ if (certEntry == NULL) {
+ PORT_Free(newItem);
+ return NULL;
+ }
+
+ newItem->len = len = certEntry->certificateData.dataEncryptedWithKs.len;
+ newItem->data = cert = PORT_ZAlloc(len);
+ if (cert == NULL) {
+ PORT_Free(newItem);
+ return NULL;
+ }
+ newItem->len = DER_GetUInteger(&certEntry->certificateData.length);
+
+
+ PORT_Memcpy(cert, certEntry->certificateData.dataEncryptedWithKs.data,len);
+
+ /* Ks is always stored in keyReg[0] when we log in */
+ ret = fort_skipjackDecrypt(swfile->Ks,
+ &certEntry->certificateData.dataIV.data[SKIPJACK_LEAF_SIZE],
+ len,cert,cert);
+ if (ret != CI_OK) {
+ SECITEM_FreeItem(newItem,PR_TRUE);
+ return NULL;
+ }
+ return newItem;
+}
+
+/*
+ * decode the DER file data into our nice data structures, including turning
+ * cert indexes into integers.
+ */
+SECItem *
+FORT_PutSWFile(FORTSignedSWFile *sw_init_file)
+{
+ SECItem *outBits, *tmpBits;
+
+ outBits = PORT_ZNew(SECItem);
+ if (outBits == NULL) goto fail;
+
+ /* ANS1 encode the complete init file */
+ tmpBits = SEC_ASN1EncodeItem(NULL,outBits,sw_init_file,fortSwFortezzaInitFile);
+ if (tmpBits == NULL) {
+ goto fail;
+ }
+
+ return outBits;
+
+fail:
+ if (outBits) SECITEM_FreeItem(outBits,PR_TRUE);
+ return NULL;
+}