/* Generate a mechaism param from a type, and iv. */ SECItem * PK11_ParamFromAlgid(SECAlgorithmID *algid) { CK_RC2_CBC_PARAMS * rc2_cbc_params = NULL; CK_RC2_PARAMS * rc2_ecb_params = NULL; CK_RC5_CBC_PARAMS * rc5_cbc_params = NULL; CK_RC5_PARAMS * rc5_ecb_params = NULL; PRArenaPool * arena = NULL; SECItem * mech = NULL; SECOidTag algtag; SECStatus rv; CK_MECHANISM_TYPE type; /* initialize these to prevent UMRs in the ASN1 decoder. */ SECItem iv = {siBuffer, NULL, 0}; sec_rc2cbcParameter rc2 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; sec_rc5cbcParameter rc5 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}, {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; algtag = SECOID_GetAlgorithmTag(algid); type = PK11_AlgtagToMechanism(algtag); mech = PORT_New(SECItem); if (mech == NULL) { return NULL; } mech->type = siBuffer; mech->data = NULL; mech->len = 0; arena = PORT_NewArena(1024); if (!arena) { goto loser; } /* handle the complicated cases */ switch (type) { case CKM_RC2_ECB: rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2ecb_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc2_ecb_params = PORT_New(CK_RC2_PARAMS); if (rc2_ecb_params == NULL) { goto loser; } *rc2_ecb_params = rc2_map(&rc2.rc2ParameterVersion); mech->data = (unsigned char *) rc2_ecb_params; mech->len = sizeof *rc2_ecb_params; break; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2cbc_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc2_cbc_params = PORT_New(CK_RC2_CBC_PARAMS); if (rc2_cbc_params == NULL) { goto loser; } mech->data = (unsigned char *) rc2_cbc_params; mech->len = sizeof *rc2_cbc_params; rc2_cbc_params->ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion); if (rc2.iv.len != sizeof rc2_cbc_params->iv) { PORT_SetError(SEC_ERROR_INPUT_LEN); goto loser; } PORT_Memcpy(rc2_cbc_params->iv, rc2.iv.data, rc2.iv.len); break; case CKM_RC5_ECB: rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5ecb_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc5_ecb_params = PORT_New(CK_RC5_PARAMS); if (rc5_ecb_params == NULL) { goto loser; } rc5_ecb_params->ulRounds = DER_GetInteger(&rc5.rounds); rc5_ecb_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; mech->data = (unsigned char *) rc5_ecb_params; mech->len = sizeof *rc5_ecb_params; break; case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5cbc_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc5_cbc_params = (CK_RC5_CBC_PARAMS *) PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + rc5.iv.len); if (rc5_cbc_params == NULL) { goto loser; } mech->data = (unsigned char *) rc5_cbc_params; mech->len = sizeof *rc5_cbc_params; rc5_cbc_params->ulRounds = DER_GetInteger(&rc5.rounds); rc5_cbc_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; rc5_cbc_params->pIv = ((CK_BYTE_PTR)rc5_cbc_params) + sizeof(CK_RC5_CBC_PARAMS); rc5_cbc_params->ulIvLen = rc5.iv.len; PORT_Memcpy(rc5_cbc_params->pIv, rc5.iv.data, rc5.iv.len); break; case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_DES2_EDE_CBC: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_RC2_40_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: case CKM_PKCS5_PBKD2: rv = pbe_PK11AlgidToParam(algid,mech); if (rv != SECSuccess) { goto loser; } break; case CKM_RC4: case CKM_SEED_ECB: case CKM_CAMELLIA_ECB: case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: break; default: if (pk11_lookup(type)->iv == 0) { break; } /* FALL THROUGH */ case CKM_SEED_CBC: case CKM_CAMELLIA_CBC: case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_SEED_CBC_PAD: case CKM_CAMELLIA_CBC_PAD: case CKM_AES_CBC_PAD: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: /* simple cases are simply octet string encoded IVs */ rv = SEC_ASN1DecodeItem(arena, &iv, SEC_ASN1_GET(SEC_OctetStringTemplate), &(algid->parameters)); if (rv != SECSuccess || iv.data == NULL) { goto loser; } /* XXX Should be some IV length sanity check here. */ mech->data = (unsigned char*)PORT_Alloc(iv.len); if (mech->data == NULL) { goto loser; } PORT_Memcpy(mech->data, iv.data, iv.len); mech->len = iv.len; break; } PORT_FreeArena(arena, PR_FALSE); return mech; loser: if (arena) PORT_FreeArena(arena, PR_FALSE); SECITEM_FreeItem(mech,PR_TRUE); return NULL; }
static SecCmsCipherContext * SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid, PRBool encrypt) { SecCmsCipherContext *cc; CSSM_CC_HANDLE ciphercc = 0; SECOidData *oidData; SECOidTag algtag; CSSM_ALGORITHMS algorithm; CSSM_PADDING padding = CSSM_PADDING_PKCS7; CSSM_ENCRYPT_MODE mode; CSSM_CSP_HANDLE cspHandle; const CSSM_KEY *cssmKey; OSStatus rv; uint8 ivbuf[8]; CSSM_DATA initVector = { sizeof(ivbuf), ivbuf }; //CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_ALG_PARAMS, sizeof(CSSM_DATA_PTR) }; rv = SecKeyGetCSPHandle(key, &cspHandle); if (rv) goto loser; rv = SecKeyGetCSSMKey(key, &cssmKey); if (rv) goto loser; // @@@ Add support for PBE based stuff oidData = SECOID_FindOID(&algid->algorithm); if (!oidData) goto loser; algtag = oidData->offset; algorithm = oidData->cssmAlgorithm; if (!algorithm) goto loser; switch (algtag) { case SEC_OID_RC2_CBC: case SEC_OID_RC4: case SEC_OID_DES_EDE3_CBC: case SEC_OID_DES_EDE: case SEC_OID_DES_CBC: case SEC_OID_RC5_CBC_PAD: case SEC_OID_AES_128_CBC: case SEC_OID_AES_192_CBC: case SEC_OID_AES_256_CBC: case SEC_OID_FORTEZZA_SKIPJACK: mode = CSSM_ALGMODE_CBCPadIV8; break; case SEC_OID_DES_ECB: case SEC_OID_AES_128_ECB: case SEC_OID_AES_192_ECB: case SEC_OID_AES_256_ECB: mode = CSSM_ALGMODE_ECBPad; break; case SEC_OID_DES_OFB: mode = CSSM_ALGMODE_OFBPadIV8; break; case SEC_OID_DES_CFB: mode = CSSM_ALGMODE_CFBPadIV8; break; default: goto loser; } if (encrypt) { CSSM_CC_HANDLE randomcc; //SECItem *parameters; // Generate random initVector if (CSSM_CSP_CreateRandomGenContext(cspHandle, CSSM_ALGID_APPLE_YARROW, NULL, /* seed*/ initVector.Length, &randomcc)) goto loser; if (CSSM_GenerateRandom(randomcc, &initVector)) goto loser; CSSM_DeleteContext(randomcc); // Put IV into algid.parameters switch (algtag) { case SEC_OID_RC4: case SEC_OID_DES_EDE3_CBC: case SEC_OID_DES_EDE: case SEC_OID_DES_CBC: case SEC_OID_AES_128_CBC: case SEC_OID_AES_192_CBC: case SEC_OID_AES_256_CBC: case SEC_OID_FORTEZZA_SKIPJACK: case SEC_OID_DES_ECB: case SEC_OID_AES_128_ECB: case SEC_OID_AES_192_ECB: case SEC_OID_AES_256_ECB: case SEC_OID_DES_OFB: case SEC_OID_DES_CFB: /* Just encode the initVector as an octet string. */ if (!SEC_ASN1EncodeItem(poolp, &algid->parameters, &initVector, SEC_OctetStringTemplate)) goto loser; break; case SEC_OID_RC2_CBC: { sec_rc2cbcParameter rc2 = {}; unsigned long rc2version; SECItem *newParams; rc2.iv = initVector; rc2version = rc2_unmap(cssmKey->KeyHeader.LogicalKeySizeInBits); if (!SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion), rc2version)) goto loser; newParams = SEC_ASN1EncodeItem (poolp, &algid->parameters, &rc2, sec_rc2cbc_parameter_template); PORT_Free(rc2.rc2ParameterVersion.Data); if (newParams == NULL) goto loser; break; } case SEC_OID_RC5_CBC_PAD: default: // @@@ Implement rc5 params stuff. goto loser; break; } } else { // Extract IV from algid.parameters // Put IV into algid.parameters switch (algtag) { case SEC_OID_RC4: case SEC_OID_DES_EDE3_CBC: case SEC_OID_DES_EDE: case SEC_OID_DES_CBC: case SEC_OID_AES_128_CBC: case SEC_OID_AES_192_CBC: case SEC_OID_AES_256_CBC: case SEC_OID_FORTEZZA_SKIPJACK: case SEC_OID_DES_ECB: case SEC_OID_AES_128_ECB: case SEC_OID_AES_192_ECB: case SEC_OID_AES_256_ECB: case SEC_OID_DES_OFB: case SEC_OID_DES_CFB: { CSSM_DATA iv = {}; /* Just decode the initVector from an octet string. */ rv = SEC_ASN1DecodeItem(NULL, &iv, SEC_OctetStringTemplate, &(algid->parameters)); if (rv) goto loser; if (initVector.Length != iv.Length) { PORT_Free(iv.Data); goto loser; } memcpy(initVector.Data, iv.Data, initVector.Length); PORT_Free(iv.Data); break; } case SEC_OID_RC2_CBC: { sec_rc2cbcParameter rc2 = {}; unsigned long ulEffectiveBits; rv = SEC_ASN1DecodeItem(NULL, &rc2 ,sec_rc2cbc_parameter_template, &(algid->parameters)); if (rv) goto loser; if (initVector.Length != rc2.iv.Length) { PORT_Free(rc2.iv.Data); PORT_Free(rc2.rc2ParameterVersion.Data); goto loser; } memcpy(initVector.Data, rc2.iv.Data, initVector.Length); PORT_Free(rc2.iv.Data); ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion); PORT_Free(rc2.rc2ParameterVersion.Data); if (ulEffectiveBits != cssmKey->KeyHeader.LogicalKeySizeInBits) goto loser; break; } case SEC_OID_RC5_CBC_PAD: default: // @@@ Implement rc5 params stuff. goto loser; break; } } if (CSSM_CSP_CreateSymmetricContext(cspHandle, algorithm, mode, NULL, /* accessCred */ cssmKey, &initVector, padding, NULL, /* reserved */ &ciphercc)) goto loser; if (encrypt) rv = CSSM_EncryptDataInit(ciphercc); else rv = CSSM_DecryptDataInit(ciphercc); if (rv) goto loser; cc = (SecCmsCipherContext *)PORT_ZAlloc(sizeof(SecCmsCipherContext)); if (cc == NULL) goto loser; cc->cc = ciphercc; cc->encrypt = encrypt; return cc; loser: if (ciphercc) CSSM_DeleteContext(ciphercc); return NULL; }