/* * NOTE: This is not thread safe. Called at init time, and when loading * a new Entry. It is reasonably safe as long as it is not re-entered * (readers will always see a consistant table) * * This routine is called to add entries to the mechanism table, once there, * they can not be removed. */ void PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key, CK_MECHANISM_TYPE keyGen, CK_MECHANISM_TYPE padType, int ivLen, int blockSize) { int tableSize = pk11_MechTableSize; int size = pk11_MechEntrySize; int entry = size++; pk11MechanismData *old = pk11_MechanismTable; pk11MechanismData *newt = pk11_MechanismTable; if (size > tableSize) { int oldTableSize = tableSize; tableSize += 10; newt = PORT_NewArray(pk11MechanismData, tableSize); if (newt == NULL) return; if (old) PORT_Memcpy(newt, old, oldTableSize*sizeof(*newt)); } else old = NULL; newt[entry].type = type; newt[entry].keyType = key; newt[entry].keyGen = keyGen; newt[entry].padType = padType; newt[entry].iv = ivLen; newt[entry].blockSize = blockSize; pk11_MechanismTable = newt; pk11_MechTableSize = tableSize; pk11_MechEntrySize = size; if (old) PORT_Free(old); }
/* * copy a template of attributes from a source object to a target object. * if target object is not given, create it. */ static SECStatus pk11_copyAttributes(PLArenaPool *arena, PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID, PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID, CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount) { SECStatus rv; CK_ATTRIBUTE *newTemplate = NULL; CK_RV crv; crv = PK11_GetAttributes(arena, sourceSlot, sourceID, copyTemplate, copyTemplateCount); /* if we have missing attributes, just skip them and create the object */ if (crv == CKR_ATTRIBUTE_TYPE_INVALID) { CK_ULONG i, j; newTemplate = PORT_NewArray(CK_ATTRIBUTE, copyTemplateCount); if (!newTemplate) { return SECFailure; } /* remove the unknown attributes. If we don't have enough attributes * PK11_CreateNewObject() will fail */ for (i = 0, j = 0; i < copyTemplateCount; i++) { if (copyTemplate[i].ulValueLen != -1) { newTemplate[j] = copyTemplate[i]; j++; } } copyTemplate = newTemplate; copyTemplateCount = j; crv = PK11_GetAttributes(arena, sourceSlot, sourceID, copyTemplate, copyTemplateCount); } if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); return SECFailure; } if (targetID == CK_INVALID_HANDLE) { /* we need to create the object */ rv = PK11_CreateNewObject(targetSlot, CK_INVALID_SESSION, copyTemplate, copyTemplateCount, PR_TRUE, &targetID); } else { /* update the existing object with the new attributes */ rv = pk11_setAttributes(targetSlot, targetID, copyTemplate, copyTemplateCount); } if (newTemplate) { free(newTemplate); } return rv; }
Error LoadMechanismList(void) { int i; if (pk11_DefaultArray == NULL) { pk11_DefaultArray = PK11_GetDefaultArray(&pk11_DefaultArraySize); if (pk11_DefaultArray == NULL) { /* should assert. This shouldn't happen */ return UNSPECIFIED_ERR; } } if (mechanismStrings != NULL) { return SUCCESS; } /* build the mechanismStrings array */ mechanismStrings = PORT_NewArray(MaskString, pk11_DefaultArraySize); if (mechanismStrings == NULL) { return OUT_OF_MEM_ERR; } numMechanismStrings = pk11_DefaultArraySize; for (i = 0; i < numMechanismStrings; i++) { const char *name = pk11_DefaultArray[i].name; unsigned long flag = pk11_DefaultArray[i].flag; /* map new name to old */ switch (flag) { case SECMOD_FORTEZZA_FLAG: name = "FORTEZZA"; break; case SECMOD_SHA1_FLAG: name = "SHA1"; break; case SECMOD_CAMELLIA_FLAG: name = "CAMELLIA"; break; case SECMOD_RANDOM_FLAG: name = "RANDOM"; break; case SECMOD_FRIENDLY_FLAG: name = "FRIENDLY"; break; default: break; } mechanismStrings[i].name = name; mechanismStrings[i].mask = SECMOD_InternaltoPubMechFlags(flag); } return SUCCESS; }
SECStatus SECU_ParseCommandLine(int argc, char **argv, char *progName, const secuCommand *cmd) { PRBool found; PLOptState *optstate; PLOptStatus status; char *optstring; PLLongOpt *longopts = NULL; int i, j; int lcmd = 0, lopt = 0; PR_ASSERT(HasNoDuplicates(cmd->commands, cmd->numCommands)); PR_ASSERT(HasNoDuplicates(cmd->options, cmd->numOptions)); optstring = (char *)PORT_Alloc(cmd->numCommands + 2 * cmd->numOptions + 1); if (optstring == NULL) return SECFailure; j = 0; for (i = 0; i < cmd->numCommands; i++) { if (cmd->commands[i].flag) /* single character option ? */ optstring[j++] = cmd->commands[i].flag; if (cmd->commands[i].longform) lcmd++; } for (i = 0; i < cmd->numOptions; i++) { if (cmd->options[i].flag) { optstring[j++] = cmd->options[i].flag; if (cmd->options[i].needsArg) optstring[j++] = ':'; } if (cmd->options[i].longform) lopt++; } optstring[j] = '\0'; if (lcmd + lopt > 0) { longopts = PORT_NewArray(PLLongOpt, lcmd + lopt + 1); if (!longopts) { PORT_Free(optstring); return SECFailure; } j = 0; for (i = 0; j < lcmd && i < cmd->numCommands; i++) { if (cmd->commands[i].longform) { longopts[j].longOptName = cmd->commands[i].longform; longopts[j].longOption = 0; longopts[j++].valueRequired = cmd->commands[i].needsArg; } } lopt += lcmd; for (i = 0; j < lopt && i < cmd->numOptions; i++) { if (cmd->options[i].longform) { longopts[j].longOptName = cmd->options[i].longform; longopts[j].longOption = 0; longopts[j++].valueRequired = cmd->options[i].needsArg; } } longopts[j].longOptName = NULL; } optstate = PL_CreateLongOptState(argc, argv, optstring, longopts); if (!optstate) { PORT_Free(optstring); PORT_Free(longopts); return SECFailure; } /* Parse command line arguments */ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { const char *optstatelong; char option = optstate->option; /* positional parameter, single-char option or long opt? */ if (optstate->longOptIndex == -1) { /* not a long opt */ if (option == '\0') continue; /* it's a positional parameter */ optstatelong = ""; } else { /* long opt */ if (option == '\0') option = '\377'; /* force unequal with all flags */ optstatelong = longopts[optstate->longOptIndex].longOptName; } found = PR_FALSE; for (i = 0; i < cmd->numCommands; i++) { if (cmd->commands[i].flag == option || cmd->commands[i].longform == optstatelong) { cmd->commands[i].activated = PR_TRUE; if (optstate->value) { cmd->commands[i].arg = (char *)optstate->value; } found = PR_TRUE; break; } } if (found) continue; for (i = 0; i < cmd->numOptions; i++) { if (cmd->options[i].flag == option || cmd->options[i].longform == optstatelong) { cmd->options[i].activated = PR_TRUE; if (optstate->value) { cmd->options[i].arg = (char *)optstate->value; } else if (cmd->options[i].needsArg) { status = PL_OPT_BAD; goto loser; } found = PR_TRUE; break; } } if (!found) { status = PL_OPT_BAD; break; } } loser: PL_DestroyOptState(optstate); PORT_Free(optstring); if (longopts) PORT_Free(longopts); if (status == PL_OPT_BAD) return SECFailure; return SECSuccess; }
/* ** Perform AES key unwrap. ** "cx" the context ** "output" the output buffer to store the decrypted data. ** "outputLen" how much data is stored in "output". Set by the routine ** after some data is stored in output. ** "maxOutputLen" the maximum amount of data that can ever be ** stored in "output" ** "input" the input data ** "inputLen" the amount of input data */ extern SECStatus AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output, unsigned int *pOutputLen, unsigned int maxOutputLen, const unsigned char *input, unsigned int inputLen) { PRUint64 * R = NULL; unsigned int nBlocks; unsigned int i, j; unsigned int aesLen = AES_BLOCK_SIZE; unsigned int outLen; SECStatus s = SECFailure; /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ PRUint64 t; PRUint64 B[2]; /* Check args */ if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { PORT_SetError(SEC_ERROR_INPUT_LEN); return s; } outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE; #ifdef maybe if (!output && pOutputLen) { /* caller is asking for output size */ *pOutputLen = outLen; return SECSuccess; } #endif if (maxOutputLen < outLen) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); return s; } if (cx == NULL || output == NULL || input == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return s; } nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; R = PORT_NewArray(PRUint64, nBlocks); if (!R) return s; /* error is already set. */ nBlocks--; /* ** 1) Initialize variables. */ memcpy(&R[0], input, inputLen); B[0] = R[0]; #if BIG_ENDIAN_WITH_64_BIT_REGISTERS t = 6UL * nBlocks; #else set_t((unsigned char *)&t, 6UL * nBlocks); #endif /* ** 2) Calculate intermediate values. */ for (j = 0; j < 6; ++j) { for (i = nBlocks; i; --i) { /* here, XOR A with t (in big endian order) and decrement t; */ #if BIG_ENDIAN_WITH_64_BIT_REGISTERS B[0] ^= t--; #else xor_and_decrement(&B[0], &t); #endif B[1] = R[i]; s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen, sizeof B, (unsigned char *)B, sizeof B); if (s != SECSuccess) break; R[i] = B[1]; } } /* ** 3) Output the results. */ if (s == SECSuccess) { int bad = memcmp(&B[0], cx->iv, AES_KEY_WRAP_IV_BYTES); if (!bad) { memcpy(output, &R[1], outLen); if (pOutputLen) *pOutputLen = outLen; } else { s = SECFailure; PORT_SetError(SEC_ERROR_BAD_DATA); if (pOutputLen) *pOutputLen = 0; } } else if (pOutputLen) { *pOutputLen = 0; } PORT_ZFree(R, inputLen); return s; }
/* ** Perform AES key wrap. ** "cx" the context ** "output" the output buffer to store the encrypted data. ** "outputLen" how much data is stored in "output". Set by the routine ** after some data is stored in output. ** "maxOutputLen" the maximum amount of data that can ever be ** stored in "output" ** "input" the input data ** "inputLen" the amount of input data */ extern SECStatus AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output, unsigned int *pOutputLen, unsigned int maxOutputLen, const unsigned char *input, unsigned int inputLen) { PRUint64 * R = NULL; unsigned int nBlocks; unsigned int i, j; unsigned int aesLen = AES_BLOCK_SIZE; unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE; SECStatus s = SECFailure; /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */ PRUint64 t; PRUint64 B[2]; #define A B[0] /* Check args */ if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) { PORT_SetError(SEC_ERROR_INPUT_LEN); return s; } #ifdef maybe if (!output && pOutputLen) { /* caller is asking for output size */ *pOutputLen = outLen; return SECSuccess; } #endif if (maxOutputLen < outLen) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); return s; } if (cx == NULL || output == NULL || input == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return s; } nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE; R = PORT_NewArray(PRUint64, nBlocks + 1); if (!R) return s; /* error is already set. */ /* ** 1) Initialize variables. */ memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES); memcpy(&R[1], input, inputLen); #if BIG_ENDIAN_WITH_64_BIT_REGISTERS t = 0; #else memset(&t, 0, sizeof t); #endif /* ** 2) Calculate intermediate values. */ for (j = 0; j < 6; ++j) { for (i = 1; i <= nBlocks; ++i) { B[1] = R[i]; s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen, sizeof B, (unsigned char *)B, sizeof B); if (s != SECSuccess) break; R[i] = B[1]; /* here, increment t and XOR A with t (in big endian order); */ #if BIG_ENDIAN_WITH_64_BIT_REGISTERS A ^= ++t; #else increment_and_xor((unsigned char *)&A, (unsigned char *)&t); #endif } } /* ** 3) Output the results. */ if (s == SECSuccess) { R[0] = A; memcpy(output, &R[0], outLen); if (pOutputLen) *pOutputLen = outLen; } else if (pOutputLen) { *pOutputLen = 0; } PORT_ZFree(R, outLen); return s; }
/* * check to see if the module has added new slots. PKCS 11 v2.20 allows for * modules to add new slots, but never remove them. Slots cannot be added * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently * grow on the caller. It is permissible for the slots to increase between * successive calls with NULL to get the size. */ SECStatus SECMOD_UpdateSlotList(SECMODModule *mod) { CK_RV crv; CK_ULONG count; CK_ULONG i, oldCount; PRBool freeRef = PR_FALSE; void *mark = NULL; CK_ULONG *slotIDs = NULL; PK11SlotInfo **newSlots = NULL; PK11SlotInfo **oldSlots = NULL; if (!moduleLock) { PORT_SetError(SEC_ERROR_NOT_INITIALIZED); return SECFailure; } /* C_GetSlotList is not a session function, make sure * calls are serialized */ PZ_Lock(mod->refLock); freeRef = PR_TRUE; /* see if the number of slots have changed */ crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } /* nothing new, blow out early, we want this function to be quick * and cheap in the normal case */ if (count == mod->slotCount) { PZ_Unlock(mod->refLock); return SECSuccess; } if (count < (CK_ULONG)mod->slotCount) { /* shouldn't happen with a properly functioning PKCS #11 module */ PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); goto loser; } /* get the new slot list */ slotIDs = PORT_NewArray(CK_SLOT_ID, count); if (slotIDs == NULL) { goto loser; } crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } freeRef = PR_FALSE; PZ_Unlock(mod->refLock); mark = PORT_ArenaMark(mod->arena); if (mark == NULL) { goto loser; } newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); /* walk down the new slot ID list returned from the module. We keep * the old slots which match a returned ID, and we initialize the new * slots. */ for (i=0; i < count; i++) { PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); if (!slot) { /* we have a new slot create a new slot data structure */ slot = PK11_NewSlotInfo(mod); if (!slot) { goto loser; } PK11_InitSlot(mod, slotIDs[i], slot); STAN_InitTokenForSlotInfo(NULL, slot); } newSlots[i] = slot; } STAN_ResetTokenInterator(NULL); PORT_Free(slotIDs); slotIDs = NULL; PORT_ArenaUnmark(mod->arena, mark); /* until this point we're still using the old slot list. Now we update * module slot list. We update the slots (array) first then the count, * since we've already guarrenteed that count has increased (just in case * someone is looking at the slots field of module without holding the * moduleLock */ SECMOD_GetWriteLock(moduleLock); oldCount =mod->slotCount; oldSlots = mod->slots; mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is * allocated out of the module arena and won't * be freed until the module is freed */ mod->slotCount = count; SECMOD_ReleaseWriteLock(moduleLock); /* free our old references before forgetting about oldSlot*/ for (i=0; i < oldCount; i++) { PK11_FreeSlot(oldSlots[i]); } return SECSuccess; loser: if (freeRef) { PZ_Unlock(mod->refLock); } if (slotIDs) { PORT_Free(slotIDs); } /* free all the slots we allocated. newSlots are part of the * mod arena. NOTE: the newSlots array contain both new and old * slots, but we kept a reference to the old slots when we built the new * array, so we need to free all the slots in newSlots array. */ if (newSlots) { for (i=0; i < count; i++) { if (newSlots[i] == NULL) { break; /* hit the last one */ } PK11_FreeSlot(newSlots[i]); } } /* must come after freeing newSlots */ if (mark) { PORT_ArenaRelease(mod->arena, mark); } return SECFailure; }