/* * 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. */ /* * implement the MACI calls as Software Fortezza Calls. * only do the ones Nescape Needs. This provides a single software slot, * with 100 key registers, and 50 backup Ra private registers. Since we only * create one session per slot, this implementation only uses one session. * One future enhancement may be to try to improve on this for better threading * support. */ #include "prtypes.h" #include "prio.h" #include "swforti.h" /*#include "keytlow.h"*/ /* #include "dh.h" */ #include "blapi.h" #include "maci.h" /* #include "dsa.h" */ /* #include "hasht.h" */ #include "secitem.h" #include "secrng.h" /*#include "keylow.h" */ #include "secder.h" #if defined(XP_UNIX) || defined(XP_BEOS) #include #endif #ifndef O_BINARY #define O_BINARY 0 #endif /* currently we only support one software token. In the future we can use the * session to determin which of many possible tokens we are talking about. * all the calls which need tokens take a pointer to the software token as a * target. */ static FORTSWToken *swtoken = NULL; #define SOCKET_ID 1 /* can't change the pin on SW fortezza for now */ int MACI_ChangePIN(HSESSION session, int PINType, CI_PIN CI_FAR pOldPIN, CI_PIN CI_FAR pNewPin) { return CI_INV_STATE; } /* * Check pin checks the pin, then logs the user in or out depending on if * the pin succedes. The General implementation would support both SSO and * User mode our's only needs User mode. Pins are checked by whether or not * they can produce our valid Ks for this 'card'. */ int MACI_CheckPIN(HSESSION session, int PINType, CI_PIN CI_FAR pin) { FORTSkipjackKeyPtr Ks; FORTSWFile *config_file = NULL; FORTSkipjackKey seed; unsigned char pinArea[13]; unsigned char *padPin = NULL; /* This SW module can only log in as USER */ if (PINType != CI_USER_PIN) return CI_INV_TYPE; if (swtoken == NULL) return CI_NO_CARD; /* we can't check a pin if we haven't been initialized yet */ if (swtoken->config_file == NULL) return CI_NO_CARD; config_file = swtoken->config_file; /* Make sure the pin value meets minimum lengths */ if (PORT_Strlen((char *)pin) < 12) { PORT_Memset(pinArea, ' ', sizeof(pinArea)); PORT_Memcpy(pinArea,pin,PORT_Strlen((char *)pin)); pinArea[12] = 0; padPin = pinArea; } /* get the Ks by unwrapping it from the memphrase with the pbe generated * from the pin */ Ks = fort_CalculateKMemPhrase(config_file, &config_file->fortezzaPhrase, (char *)pin, NULL); if (Ks == 0) { Ks = fort_CalculateKMemPhrase(config_file, &config_file->fortezzaPhrase, (char *)padPin, NULL); if (Ks == 0) { PORT_Memset(pinArea, 0, sizeof(pinArea)); fort_Logout(swtoken); return CI_FAIL; } } /* use Ks and hash to verify that pin is correct */ if (! fort_CheckMemPhrase(config_file, &config_file->fortezzaPhrase, (char *)pin, Ks) ) { if ((padPin == NULL) || ! fort_CheckMemPhrase(config_file, &config_file->fortezzaPhrase, (char *)padPin, Ks) ) { PORT_Memset(pinArea, 0, sizeof(pinArea)); fort_Logout(swtoken); return CI_FAIL; } } PORT_Memset(pinArea, 0, sizeof(pinArea)); /* OK, add the random Seed value into the random number generator */ fort_skipjackUnwrap(Ks,config_file->wrappedRandomSeed.len, config_file->wrappedRandomSeed.data,seed); RNG_RandomUpdate(seed,sizeof(seed)); /* it is, go ahead and log in */ swtoken->login = PR_TRUE; /* Ks is always stored in keyReg[0] when we log in */ PORT_Memcpy(swtoken->keyReg[0].data, Ks, sizeof (FORTSkipjackKey)); swtoken->keyReg[0].present = PR_TRUE; PORT_Memset(Ks, 0, sizeof(FORTSkipjackKey)); PORT_Free(Ks); return CI_OK; } /* * close an open socket. Power_Down flag is set when we want to reset the * cards complete state. */ int MACI_Close(HSESSION session, unsigned int flags, int socket) { if (socket != SOCKET_ID) return CI_BAD_CARD; if (swtoken == NULL) return CI_BAD_CARD; if (flags == CI_POWER_DOWN_FLAG) { fort_Logout(swtoken); } return CI_OK; } /* * Decrypt keeps track of it's own IV. */ int MACI_Decrypt(HSESSION session, unsigned int size, CI_DATA cipherIn, CI_DATA plainOut) { int ret; unsigned char IV[SKIPJACK_BLOCK_SIZE]; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,swtoken->key,PR_TRUE)) != CI_OK) return ret; /*fort_AddNoise();*/ /* save the IV, before we potentially trash the new one when we decrypt. * (it's permissible to decrypt into the cipher text buffer by passing the * same buffers for both cipherIn and plainOut. */ PORT_Memcpy(IV,swtoken->IV, sizeof(IV)); fort_UpdateIV(cipherIn,size,swtoken->IV); return fort_skipjackDecrypt(swtoken->keyReg[swtoken->key].data, IV,size,cipherIn,plainOut); } /* * Clear a key from one of the key registers (indicated by index). * return an error if no key exists. */ int MACI_DeleteKey(HSESSION session, int index) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; /* can't delete Ks */ if (index == 0) return CI_INV_KEY_INDEX; if ((ret = fort_KeyOK(swtoken,index,PR_TRUE)) != CI_OK) return ret; fort_ClearKey(&swtoken->keyReg[index]); return CI_OK; } /* * encrypt some blocks of data and update the IV. */ int MACI_Encrypt(HSESSION session, unsigned int size, CI_DATA plainIn, CI_DATA cipherOut) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,swtoken->key,PR_TRUE)) != CI_OK) return ret; /*fort_AddNoise();*/ ret = fort_skipjackEncrypt(swtoken->keyReg[swtoken->key].data, swtoken->IV,size,plainIn,cipherOut); fort_UpdateIV(cipherOut,size,swtoken->IV); return ret; } /* * create a new IV and encode it. */ static char *leafbits="THIS IS NOT LEAF"; int MACI_GenerateIV(HSESSION Session, CI_IV CI_FAR pIV) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,swtoken->key,PR_TRUE)) != CI_OK) return ret; ret = fort_GenerateRandom(swtoken->IV,SKIPJACK_BLOCK_SIZE); if (ret != CI_OK) return ret; PORT_Memcpy(pIV,leafbits,SKIPJACK_LEAF_SIZE); PORT_Memcpy(&pIV[SKIPJACK_LEAF_SIZE],swtoken->IV,SKIPJACK_BLOCK_SIZE); return CI_OK; } /* * create a new Key */ int MACI_GenerateMEK(HSESSION session, int index, int reserved) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,index,PR_FALSE)) != CI_OK) return ret; ret = fort_GenerateRandom(swtoken->keyReg[index].data, sizeof (swtoken->keyReg[index].data)); if (ret == CI_OK) swtoken->keyReg[index].present = PR_TRUE; return ret; } /* * build a new Ra/ra pair for a KEA exchange. */ int MACI_GenerateRa(HSESSION session, CI_RA CI_FAR pRa) { int ret; int counter; int RaLen,raLen; DSAPrivateKey *privKey = NULL; PQGParams params; SECStatus rv; int crv = CI_EXEC_FAIL; fortSlotEntry *certEntry = NULL; unsigned char *unsignedRa = NULL; unsigned char *unsignedra = NULL; fortKeyInformation *key_info = NULL; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; /* make sure the personality is set */ if (swtoken->certIndex == 0) return CI_INV_STATE; /* pick next Ra circular buffer */ counter = swtoken->nextRa; swtoken->nextRa++; if (swtoken->nextRa >= MAX_RA_SLOTS) swtoken->nextRa = 0; /* now get the params for diffie -helman key gen */ certEntry = fort_GetCertEntry(swtoken->config_file,swtoken->certIndex); if (certEntry == NULL) return CI_INV_CERT_INDEX; if (certEntry->exchangeKeyInformation) { key_info = certEntry->exchangeKeyInformation; } else { key_info = certEntry->signatureKeyInformation; } if (key_info == NULL) return CI_NO_X; /* Generate Diffie Helman key Pair -- but we use DSA key gen to do it */ rv = SECITEM_CopyItem(NULL,¶ms.prime,&key_info->p); if (rv != SECSuccess) return CI_EXEC_FAIL; rv = SECITEM_CopyItem(NULL,¶ms.subPrime,&key_info->q); if (rv != SECSuccess) return CI_EXEC_FAIL; rv = SECITEM_CopyItem(NULL,¶ms.base,&key_info->g); if (rv != SECSuccess) return CI_EXEC_FAIL; /* KEA uses DSA like key generation with short DSA keys that have to * maintain a relationship to q */ rv = DSA_NewKey(¶ms, &privKey); SECITEM_FreeItem(¶ms.prime,PR_FALSE); SECITEM_FreeItem(¶ms.subPrime,PR_FALSE); SECITEM_FreeItem(¶ms.base,PR_FALSE); if (rv != SECSuccess) return CI_EXEC_FAIL; /* save private key, public key, and param in Ra Circular buffer */ unsignedRa = privKey->publicValue.data; RaLen = privKey->publicValue.len; while ((unsignedRa[0] == 0) && (RaLen > CI_RA_SIZE)) { unsignedRa++; RaLen--; } if (RaLen > CI_RA_SIZE) goto loser; unsignedra = privKey->privateValue.data; raLen = privKey->privateValue.len; while ((unsignedra[0] == 0) && (raLen > sizeof(fortRaPrivate))) { unsignedra++; raLen--; } if (raLen > sizeof(fortRaPrivate)) goto loser; PORT_Memset(swtoken->RaValues[counter].private, 0, sizeof(fortRaPrivate)); PORT_Memcpy( &swtoken->RaValues[counter].private[sizeof(fortRaPrivate) - raLen], unsignedra, raLen); PORT_Memset(pRa, 0, CI_RA_SIZE); PORT_Memcpy(&pRa[CI_RA_SIZE-RaLen], unsignedRa, RaLen); PORT_Memcpy(swtoken->RaValues[counter].public, pRa, CI_RA_SIZE); crv = CI_OK; loser: PORT_FreeArena(privKey->params.arena, PR_TRUE); return crv; } /* * return some random data. */ int MACI_GenerateRandom(HSESSION session, CI_RANDOM CI_FAR random) { int ret; if ((ret = fort_CardExists(swtoken,PR_FALSE)) != CI_OK) return ret; return fort_GenerateRandom(random,sizeof (CI_RANDOM)); } static CI_RA Remail = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; /* * build a new Token exchange key using KEA. */ int MACI_GenerateTEK(HSESSION hSession, int flags, int target, CI_RA CI_FAR Ra, CI_RA CI_FAR Rb, unsigned int YSize, CI_Y CI_FAR pY ) { FORTEZZAPrivateKey *key = NULL; fortSlotEntry * certEntry; unsigned char * w = NULL; SECItem *q; SECStatus rv; int ret,i; PRBool email = PR_TRUE; SECItem R; /* public */ SECItem Y; /* public */ SECItem r; /* private */ SECItem x; /* private */ SECItem wItem; /* derived secret */ fortRaPrivatePtr ra; FORTSkipjackKey cover_key; unsigned char pad[10] = { 0x72, 0xf1, 0xa8, 0x7e, 0x92, 0x82, 0x41, 0x98, 0xab, 0x0b }; /* verify that everything is ok with the token, keys and certs */ if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; /* make sure the personality is set */ if (swtoken->certIndex == 0) return CI_INV_STATE; if ((ret = fort_KeyOK(swtoken,target,PR_FALSE)) != CI_OK) return ret; /* get the cert from the entry, then look up the key from that cert */ certEntry = fort_GetCertEntry(swtoken->config_file,swtoken->certIndex); if (certEntry == NULL) return CI_INV_CERT_INDEX; key = fort_GetPrivKey(swtoken,fortezzaDHKey,certEntry); if (key == NULL) return CI_NO_X; if (certEntry->exchangeKeyInformation) { q = &certEntry->exchangeKeyInformation->q; } else { q = &certEntry->signatureKeyInformation->q; } email = (PORT_Memcmp(Rb,Remail,sizeof(Rb)) == 0) ? PR_TRUE: PR_FALSE; /* load the common elements */ Y.data = pY; Y.len = YSize; x.data = key->u.dh.privateValue.data; x.len = key->u.dh.privateValue.len; /* now initialize the rest of the values */ if (flags == CI_INITIATOR_FLAG) { if (email) { R.data = Y.data; R.len = Y.len; } else { R.data = Rb; R.len = sizeof(CI_RA); } ra = fort_LookupPrivR(swtoken,Ra); if (ra == NULL) { ret = CI_EXEC_FAIL; goto loser; } r.data = ra; r.len = sizeof(fortRaPrivate); } else { R.data = Ra; R.len = sizeof(CI_RA); if (email) { r.data = x.data; r.len = x.len; } else { ra = fort_LookupPrivR(swtoken,Rb); if (ra == NULL) { ret = CI_EXEC_FAIL; goto loser; } r.data = ra; r.len = sizeof(fortRaPrivate); } } if (!KEA_Verify(&Y,&key->u.dh.prime,q)) { ret = CI_EXEC_FAIL; goto loser; } if (!KEA_Verify(&R,&key->u.dh.prime,q)) { ret = CI_EXEC_FAIL; goto loser; } /* calculate the base key */ rv = KEA_Derive(&key->u.dh.prime, &Y, &R, &r, &x, &wItem); if (rv != SECSuccess) { ret = CI_EXEC_FAIL; goto loser; } w = wItem.data; /* use the skipjack wrapping function to 'mix' the key up */ for (i=0; i < sizeof(FORTSkipjackKey); i++) cover_key[i] = pad[i] ^ w[i]; ret = fort_skipjackWrap(cover_key,sizeof(FORTSkipjackKey), &w[sizeof(FORTSkipjackKey)],swtoken->keyReg[target].data); if (ret != CI_OK) goto loser; swtoken->keyReg[target].present = PR_TRUE; ret = CI_OK; loser: if (w) PORT_Free(w); if (key) fort_DestroyPrivateKey(key); return ret; } /* * return the bytes of a certificate. */ int MACI_GetCertificate(HSESSION hSession, int certIndex, CI_CERTIFICATE CI_FAR cert) { int len; int ret; fortSlotEntry *certEntry = NULL; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; certEntry = fort_GetCertEntry(swtoken->config_file,certIndex); if (certEntry == NULL) return CI_INV_CERT_INDEX; len = certEntry->certificateData.dataEncryptedWithKs.len; PORT_Memset(cert,0,sizeof(CI_CERTIFICATE)); PORT_Memcpy(cert, certEntry->certificateData.dataEncryptedWithKs.data,len); /* Ks is always stored in keyReg[0] when we log in */ return fort_skipjackDecrypt(swtoken->keyReg[0].data, &certEntry->certificateData.dataIV.data[SKIPJACK_LEAF_SIZE], len,cert,cert); } /* * return out sofware configuration bytes. Those field not used by the PKCS #11 * module may not be filled in exactly. */ #define NETSCAPE "Netscape Communications Corp " #define PRODUCT "Netscape Software FORTEZZA Lib " #define SOFTWARE "Software FORTEZZA Implementation" int MACI_GetConfiguration(HSESSION hSession, CI_CONFIG_PTR config) { config->LibraryVersion = 0x0100; config->ManufacturerVersion = 0x0100; PORT_Memcpy(config->ManufacturerName,NETSCAPE,sizeof(NETSCAPE)); PORT_Memcpy(config->ProductName,PRODUCT,sizeof(PRODUCT)); PORT_Memcpy(config->ProcessorType,SOFTWARE,sizeof(SOFTWARE)); config->UserRAMSize = 0; config->LargestBlockSize = 0x10000; config->KeyRegisterCount = KEY_REGISTERS; config->CertificateCount = swtoken ? fort_GetCertCount(swtoken->config_file): 0; config->CryptoCardFlag = 0; config->ICDVersion = 0; config->ManufacturerSWVer = 0x0100; config->DriverVersion = 0x0100; return CI_OK; } /* * return a list of all the personalities (up to the value 'EntryCount') */ int MACI_GetPersonalityList(HSESSION hSession, int EntryCount, CI_PERSON CI_FAR personList[]) { int count; int i,ret; FORTSWFile *config_file = NULL; unsigned char tmp[32]; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; config_file = swtoken->config_file; /* search for the index */ count= fort_GetCertCount(config_file); /* don't return more than the user asked for */ if (count > EntryCount) count = EntryCount; for (i=0; i < count ;i ++) { int len, dataLen; personList[i].CertificateIndex = config_file->slotEntries[i]->certIndex; len = config_file->slotEntries[i]->certificateLabel. dataEncryptedWithKs.len; if (len > sizeof(tmp)) len = sizeof(tmp); PORT_Memset(personList[i].CertLabel, ' ', sizeof(personList[i].CertLabel)); PORT_Memcpy(tmp, config_file->slotEntries[i]-> certificateLabel.dataEncryptedWithKs.data, len); /* Ks is always stored in keyReg[0] when we log in */ ret = fort_skipjackDecrypt(swtoken->keyReg[0].data, &config_file->slotEntries[i]-> certificateLabel.dataIV.data[SKIPJACK_LEAF_SIZE],len, tmp,tmp); if (ret != CI_OK) return ret; dataLen = DER_GetInteger(&config_file->slotEntries[i]-> certificateLabel.length); if (dataLen > sizeof(tmp)) dataLen = sizeof(tmp); PORT_Memcpy(personList[i].CertLabel, tmp, dataLen); personList[i].CertLabel[32] = 0; personList[i].CertLabel[33] = 0; personList[i].CertLabel[34] = 0; personList[i].CertLabel[35] = 0; } return CI_OK; } /* * get a new session ID. This function is only to make the interface happy, * the PKCS #11 module only uses one session per token. */ int MACI_GetSessionID(HSESSION *session) { *session = 1; return CI_OK; } /* * return the current card state. */ int MACI_GetState(HSESSION hSession, CI_STATE_PTR state) { int ret; if ((ret = fort_CardExists(swtoken,PR_FALSE)) != CI_OK) return ret; *state = fort_GetState(swtoken); return CI_OK; } /* * return the status. NOTE that KeyRegisterFlags and CertificateFlags are never * really used by the PKCS #11 module, so they are not implemented. */ int MACI_GetStatus(HSESSION hSession, CI_STATUS_PTR status) { int ret; FORTSWFile *config_file = NULL; if ((ret = fort_CardExists(swtoken,PR_FALSE)) != CI_OK) return ret; config_file = swtoken->config_file; status->CurrentSocket = 1; status->LockState = swtoken->lock; PORT_Memcpy(status->SerialNumber, config_file->serialID.data, config_file->serialID.len); status->CurrentState = fort_GetState(swtoken); status->DecryptionMode = CI_CBC64_MODE; status->EncryptionMode = CI_CBC64_MODE; status->CurrentPersonality = swtoken->certIndex; status->KeyRegisterCount = KEY_REGISTERS; /* our code doesn't use KeyRegisters, which is good, because there's not * enough of them .... */ PORT_Memset(status->KeyRegisterFlags,0,sizeof(status->KeyRegisterFlags)); status->CertificateCount = fort_GetCertCount(config_file); PORT_Memset(status->CertificateFlags,0,sizeof(status->CertificateFlags)); PORT_Memset(status->Flags,0,sizeof(status->Flags)); return CI_OK; } /* * add the time call because the PKCS #11 module calls it, but always pretend * the clock is bad, so it never uses the returned time. */ int MACI_GetTime(HSESSION hSession, CI_TIME CI_FAR time) { return CI_BAD_CLOCK; } /* This function is copied from NSPR so that the PKCS #11 module can be * independent of NSPR */ PRInt32 local_getFileInfo(const char *fn, PRFileInfo *info); /* * initialize the SW module, and return the number of slots we support (1). */ int MACI_Initialize(int CI_FAR *count) { char *filename = NULL; SECItem file; FORTSignedSWFile *decode_file = NULL; PRFileInfo info; /*PRFileDesc *fd = NULL;*/ int fd = -1; PRStatus err; int ret = CI_OK; int fcount; file.data = NULL; file.len = 0; *count = 1; /* allocate swtoken structure */ swtoken = PORT_ZNew(FORTSWToken); if (swtoken == NULL) return CI_OUT_OF_MEMORY; filename = (char *)fort_LookupFORTEZZAInitFile(); if (filename == NULL) { ret = CI_BAD_READ; goto failed; } fd = open(filename,O_RDONLY|O_BINARY,0); if (fd < 0) { ret = CI_BAD_READ; goto failed; } err = local_getFileInfo(filename,&info); if ((err != 0) || (info.size == 0)) { ret = CI_BAD_READ; goto failed; } file.data = PORT_ZAlloc(info.size); if (file.data == NULL) { ret = CI_OUT_OF_MEMORY; goto failed; } fcount = read(fd,file.data,info.size); close(fd); fd = -1; if (fcount != (int)info.size) { ret = CI_BAD_READ; goto failed; } file.len = fcount; decode_file = FORT_GetSWFile(&file); if (decode_file == NULL) { ret = CI_BAD_READ; goto failed; } swtoken->config_file = &decode_file->file; RNG_SystemInfoForRNG(); RNG_FileForRNG(filename); failed: if (filename) PORT_Free(filename); if (fd != -1) close(fd); if (file.data) PORT_Free(file.data); if (ret != CI_OK) { if (decode_file) FORT_DestroySignedSWFile(decode_file); if (swtoken) PORT_Free(swtoken); swtoken = NULL; } return CI_OK; } /* * load an IV from an external source. We technically should check it with the * key we received. */ int MACI_LoadIV(HSESSION session, CI_IV CI_FAR iv) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; PORT_Memcpy(swtoken->IV,&iv[SKIPJACK_LEAF_SIZE],SKIPJACK_BLOCK_SIZE); return CI_OK; } /* implement token lock (should call PR_Monitor here) */ int MACI_Lock(HSESSION session, int flags) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; swtoken->lock = 1; return CI_OK; } /* open a token. For software there isn't much to do that hasn't already been * done by initialize. */ int MACI_Open(HSESSION session, unsigned int flags, int socket) { if (socket != SOCKET_ID) return CI_NO_CARD; if (swtoken == NULL) return CI_NO_CARD; return CI_OK; } /* * Reset logs out the token... */ int MACI_Reset(HSESSION session) { if (swtoken) fort_Logout(swtoken); return CI_OK; } /* * restore and encrypt/decrypt state. NOTE: there is no error checking in this * or the save function. */ int MACI_Restore(HSESSION session, int type, CI_SAVE_DATA CI_FAR data) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; PORT_Memcpy(swtoken->IV,data, sizeof (swtoken->IV)); return CI_OK; } /* * save and encrypt/decrypt state. NOTE: there is no error checking in this * or the restore function. */ int MACI_Save(HSESSION session, int type,CI_SAVE_DATA CI_FAR data) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; PORT_Memcpy(data,swtoken->IV, sizeof (swtoken->IV)); return CI_OK; } /* * picks a token to operate against. In our case there can be only one. */ int MACI_Select(HSESSION session, int socket) { if (socket == SOCKET_ID) return CKR_OK; return CI_NO_CARD; } /* * set a register as the key to use for encrypt/decrypt operations. */ int MACI_SetKey(HSESSION session, int index) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,index,PR_TRUE)) != CI_OK) return ret; swtoken->key = index; return CI_OK; } /* * only CBC64 is supported. Keep setmode for compatibility */ int MACI_SetMode(HSESSION session, int type, int mode) { if (mode != CI_CBC64_MODE) return CI_INV_MODE; return CI_OK; } /* set the personality to use for sign/verify */ int MACI_SetPersonality(HSESSION session, int cert) { int ret; fortSlotEntry *certEntry = NULL; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; certEntry = fort_GetCertEntry(swtoken->config_file,cert); if ((certEntry == NULL) || ((certEntry->exchangeKeyInformation == NULL) && (certEntry->signatureKeyInformation == NULL)) ) return CI_INV_CERT_INDEX; swtoken->certIndex = cert; return CI_OK; } /* DSA sign some data */ int MACI_Sign(HSESSION session, CI_HASHVALUE CI_FAR hash, CI_SIGNATURE CI_FAR sig) { FORTEZZAPrivateKey *key = NULL; fortSlotEntry * certEntry = NULL; int ret = CI_OK; SECStatus rv; SECItem signItem; SECItem hashItem; unsigned char random[DSA_SUBPRIME_LEN]; /* standard checks */ if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; /* make sure the personality is set */ if (swtoken->certIndex == 0) return CI_INV_STATE; /* get the current personality */ certEntry = fort_GetCertEntry(swtoken->config_file,swtoken->certIndex); if (certEntry == NULL) return CI_INV_CERT_INDEX; /* extract the private key from the personality */ ret = CI_OK; key = fort_GetPrivKey(swtoken,fortezzaDSAKey,certEntry); if (key == NULL) { ret = CI_NO_X; goto loser; } /* create a random value for the signature */ ret = fort_GenerateRandom(random, sizeof(random)); if (ret != CI_OK) goto loser; /* Sign with that private key */ signItem.data = sig; signItem.len = DSA_SIGNATURE_LEN; hashItem.data = hash; hashItem.len = SHA1_LENGTH; rv = DSA_SignDigestWithSeed(&key->u.dsa, &signItem, &hashItem, random); if (rv != SECSuccess) { ret = CI_EXEC_FAIL; } /* clean up */ loser: if (key != NULL) fort_DestroyPrivateKey(key); return ret; } /* * clean up after ourselves. */ int MACI_Terminate(HSESSION session) { if (swtoken == NULL) return CI_OUT_OF_MEMORY; /* clear all the keys */ fort_Logout(swtoken); FORT_DestroySWFile(swtoken->config_file); PORT_Free(swtoken); swtoken = NULL; return CI_OK; } /* implement token unlock (should call PR_Monitor here) */ int MACI_Unlock(HSESSION session) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; swtoken->lock = 0; return CI_OK; } /* * unwrap a key into our software token. NOTE: this function does not * verify that the wrapping key is Ks or a TEK. This is because our higher * level software doesn't try to wrap MEKs with MEKs. If this API was exposed * generically, then we would have to worry about things like this. */ int MACI_UnwrapKey(HSESSION session, int wrapKey, int target, CI_KEY CI_FAR keyData) { int ret = CI_OK; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,target,PR_FALSE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,wrapKey,PR_TRUE)) != CI_OK) return ret; ret = fort_skipjackUnwrap(swtoken->keyReg[wrapKey].data, sizeof(CI_KEY), keyData, swtoken->keyReg[target].data); if (ret != CI_OK) goto loser; swtoken->keyReg[target].present = PR_TRUE; loser: return ret; } /* * Wrap a key out of our software token. NOTE: this function does not * verify that the wrapping key is Ks or a TEK, or that the source key is * a MEK. This is because our higher level software doesn't try to wrap MEKs * with MEKs, or wrap out TEKS and Ks. If this API was exposed * generically, then we would have to worry about things like this. */ int MACI_WrapKey(HSESSION session, int wrapKey, int source, CI_KEY CI_FAR keyData) { int ret; if ((ret = fort_CardExists(swtoken,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,source,PR_TRUE)) != CI_OK) return ret; if ((ret = fort_KeyOK(swtoken,wrapKey,PR_TRUE)) != CI_OK) return ret; ret = fort_skipjackWrap(swtoken->keyReg[wrapKey].data, sizeof(CI_KEY), swtoken->keyReg[source].data,keyData); return ret; }