/*
 * 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);
}
Exemple #2
0
/*
 * 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;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
/*
** 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;
}
Exemple #6
0
/*
** 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;
}
Exemple #7
0
/*
 * 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;
}