OSStatus cmsNullWrapKey(SecKeyRef refKey, CSSM_KEY_PTR rawKey) { CSSM_DATA descData = {0, 0}; CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand; CSSM_ACCESS_CREDENTIALS creds; CSSM_CSP_HANDLE refCspHand = CSSM_INVALID_HANDLE; const CSSM_KEY *cssmKey = NULL; uint32 keyAttr; memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); memset(rawKey, 0, sizeof(CSSM_KEY)); crtn = SecKeyGetCSSMKey(refKey, &cssmKey); if(crtn) { CSSM_PERROR("SecKeyGetCSSMKey", crtn); goto loser; } crtn = SecKeyGetCSPHandle(refKey, &refCspHand); if(crtn) { CSSM_PERROR("SecKeyGetCSPHandle", crtn); goto loser; } crtn = CSSM_CSP_CreateSymmetricContext(refCspHand, CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, NULL, // unwrappingKey NULL, // initVector CSSM_PADDING_NONE, 0, // Params &ccHand); if(crtn) { CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", crtn); return crtn; } keyAttr = rawKey->KeyHeader.KeyAttr; keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE | CSSM_KEYATTR_MODIFIABLE); keyAttr |= CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE; crtn = CSSM_WrapKey(ccHand, &creds, cssmKey, &descData, rawKey); if(crtn != CSSM_OK) { CSSM_PERROR("CSSM_WrapKey", crtn); } CSSM_DeleteContext(ccHand); loser: return crtn; }
/* * Perform NULL wrap, generally expecting an error (either * CSSMERR_CSP_INVALID_KEYATTR_MASK, if the raw key bits should be inaccessible, * or CSSMERR_CSP_INVALID_KEY_REFERENCE, if the key's header has been munged.) */ int nullWrapTest( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR key, CSSM_BOOL quiet, CSSM_RETURN expectRtn, const char *keyAlgStr, const char *testStr) { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; CSSM_KEY wrappedKey; // should not get created int irtn; memset(&wrappedKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateSymmetricContext(cspHand, CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, // passPhrase, NULL, // wrappingKey, NULL, // IV CSSM_PADDING_NONE, 0, // Params &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return testError(quiet); } crtn = CSSM_WrapKey(ccHand, &creds, key, NULL, // DescriptiveData &wrappedKey); if(crtn != expectRtn) { printf("***Testing %s for alg %s:\n", testStr, keyAlgStr); printf(" CSSM_WrapKey: expect %s\n", cssmErrToStr(expectRtn)); printf(" CSSM_WrapKey: got %s\n", cssmErrToStr(crtn)); irtn = testError(quiet); } else { irtn = 0; } CSSM_DeleteContext(ccHand); return irtn; }
/* Convert a reference key to a raw key. */ static CSSM_RETURN refKeyToRaw( CSSM_CSP_HANDLE cspHand, const CSSM_KEY *refKey, CSSM_KEY_PTR rawKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; memset(rawKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateSymmetricContext(cspHand, CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, // passPhrase NULL, // wrapping key NULL, // init vector CSSM_PADDING_NONE, // Padding 0, // Params &ccHand); if(crtn) { sec_error("CSSM_CSP_CreateSymmetricContext: refKeyToRaw context err: %s", sec_errstr(crtn)); return crtn; } crtn = CSSM_WrapKey(ccHand, &creds, refKey, NULL, // DescriptiveData rawKey); if(crtn != CSSM_OK) { sec_error("CSSM_WrapKey: refKeyToRaw wrap err: %s", sec_errstr(crtn)); return crtn; } CSSM_DeleteContext(ccHand); return CSSM_OK; }
/* Convert a reference key to a raw key. */ void AppleTPSession::refKeyToRaw( CSSM_CSP_HANDLE cspHand, const CSSM_KEY *refKey, CSSM_KEY_PTR rawKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; memset(rawKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateSymmetricContext(cspHand, CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, // passPhrase NULL, // wrapping key NULL, // init vector CSSM_PADDING_NONE, // Padding 0, // Params &ccHand); if(crtn) { tpCredDebug("AppleTPSession::refKeyToRaw: context err"); CssmError::throwMe(crtn); } crtn = CSSM_WrapKey(ccHand, &creds, refKey, NULL, // DescriptiveData rawKey); if(crtn != CSSM_OK) { tpCredDebug("AppleTPSession::refKeyToRaw: wrapKey err"); CssmError::throwMe(crtn); } CSSM_DeleteContext(ccHand); }
/* * Cook up a symmetric encryption context for the specified key, * inferring all needed attributes solely from the key algorithm. * This is obviously not a one-size-fits all function, but rather * the "most common case". If you need to encrypt/decrypt with other * padding, mode, etc., do it yourself. */ static CSSM_RETURN genCryptHandle( CSSM_CSP_HANDLE cspHandle, const CSSM_KEY *key, const CSSM_DATA *ivPtr, CSSM_CC_HANDLE *ccHandle) { CSSM_ALGORITHMS keyAlg = key->KeyHeader.AlgorithmId; CSSM_ALGORITHMS encrAlg; CSSM_ENCRYPT_MODE encrMode = CSSM_ALGMODE_NONE; CSSM_PADDING encrPad = CSSM_PADDING_NONE; CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand = 0; CSSM_ACCESS_CREDENTIALS creds; CSSM_BOOL isSymmetric = CSSM_TRUE; /* * Infer algorithm - ususally it's the same as in the key itself */ switch(keyAlg) { case CSSM_ALGID_3DES_3KEY: encrAlg = CSSM_ALGID_3DES_3KEY_EDE; break; default: encrAlg = keyAlg; break; } /* infer mode and padding */ switch(encrAlg) { /* 8-byte block ciphers */ case CSSM_ALGID_DES: case CSSM_ALGID_3DES_3KEY_EDE: case CSSM_ALGID_RC5: case CSSM_ALGID_RC2: encrMode = CSSM_ALGMODE_CBCPadIV8; encrPad = CSSM_PADDING_PKCS5; break; /* 16-byte block ciphers */ case CSSM_ALGID_AES: encrMode = CSSM_ALGMODE_CBCPadIV8; encrPad = CSSM_PADDING_PKCS7; break; /* stream ciphers */ case CSSM_ALGID_ASC: case CSSM_ALGID_RC4: encrMode = CSSM_ALGMODE_NONE; encrPad = CSSM_PADDING_NONE; break; /* RSA asymmetric */ case CSSM_ALGID_RSA: /* encrMode not used */ encrPad = CSSM_PADDING_PKCS1; isSymmetric = CSSM_FALSE; break; default: /* don't wing it - abort */ return CSSMERR_CSP_INTERNAL_ERROR; } memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); if(isSymmetric) { crtn = CSSM_CSP_CreateSymmetricContext(cspHandle, encrAlg, encrMode, NULL, // access cred key, ivPtr, // InitVector encrPad, NULL, // Params &ccHand); } else { crtn = CSSM_CSP_CreateAsymmetricContext(cspHandle, encrAlg, &creds, // access key, encrPad, &ccHand); } if(crtn) { return crtn; } *ccHandle = ccHand; return CSSM_OK; }
/* * Wrap a private key, yielding shrouded key bits. */ CSSM_RETURN p12WrapKey( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR privKey, const CSSM_ACCESS_CREDENTIALS *privKeyCreds, CSSM_ALGORITHMS keyAlg, // of the unwrapping key CSSM_ALGORITHMS encrAlg, CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only uint32 keySizeInBits, uint32 blockSizeInBytes, // for IV CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. uint32 iterCount, const CSSM_DATA &salt, const CSSM_DATA *pwd, // unicode external representation const CSSM_KEY *passKey, SecNssCoder &coder, // for mallocing keyBits CSSM_DATA &shroudedKeyBits) // RETURNED { CSSM_RETURN crtn; CSSM_KEY ckey; CSSM_CC_HANDLE ccHand = 0; CSSM_KEY wrappedKey; CSSM_CONTEXT_ATTRIBUTE attr; CSSM_DATA descrData = {0, NULL}; CSSM_ACCESS_CREDENTIALS creds; /* key must be extractable */ if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) { return errSecDataNotAvailable; } if(privKeyCreds == NULL) { /* i.e., key is from the bare CSP with no ACL support */ memset(&creds, 0, sizeof(creds)); privKeyCreds = &creds; } /* P12 style IV derivation, optional */ CSSM_DATA iv = {0, NULL}; CSSM_DATA_PTR ivPtr = NULL; if(blockSizeInBytes) { coder.allocItem(iv, blockSizeInBytes); ivPtr = &iv; } /* P12 style key derivation */ crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, keySizeInBits, iterCount, salt, pwd, passKey, iv); if(crtn) { return crtn; } /* subsequent errors to errOut: */ /* CSSM context */ crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, mode, NULL, // access cred &ckey, ivPtr, // InitVector, optional padding, NULL, // Params &ccHand); if(crtn) { p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn); goto errOut; } memset(&wrappedKey, 0, sizeof(CSSM_KEY)); /* specify PKCS8 wrap format */ attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT; attr.AttributeLength = sizeof(uint32); attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; crtn = CSSM_UpdateContextAttributes( ccHand, 1, &attr); if(crtn) { p12LogCssmError("CSSM_UpdateContextAttributes", crtn); goto errOut; } crtn = CSSM_WrapKey(ccHand, privKeyCreds, privKey, &descrData, // DescriptiveData &wrappedKey); if(crtn) { p12LogCssmError("CSSM_WrapKey", crtn); } else { coder.allocCopyItem(wrappedKey.KeyData, shroudedKeyBits); /* this was mallocd by CSP */ freeCssmMemory(cspHand, wrappedKey.KeyData.Data); } errOut: if(ccHand) { CSSM_DeleteContext(ccHand); } CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); return crtn; }
/* * Unwrap a shrouded key. */ CSSM_RETURN p12UnwrapKey( CSSM_CSP_HANDLE cspHand, CSSM_DL_DB_HANDLE_PTR dlDbHand, // optional int keyIsPermanent, // nonzero - store in DB const CSSM_DATA &shroudedKeyBits, CSSM_ALGORITHMS keyAlg, // of the unwrapping key CSSM_ALGORITHMS encrAlg, CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only uint32 keySizeInBits, uint32 blockSizeInBytes, // for IV CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. uint32 iterCount, const CSSM_DATA &salt, const CSSM_DATA *pwd, // unicode external representation const CSSM_KEY *passKey, SecNssCoder &coder, // for mallocing privKey const CSSM_DATA &labelData, SecAccessRef access, // optional bool noAcl, CSSM_KEYUSE keyUsage, CSSM_KEYATTR_FLAGS keyAttrs, /* * Result: a private key, reference format, optionaly stored * in dlDbHand */ CSSM_KEY_PTR &privKey) { CSSM_RETURN crtn; CSSM_KEY ckey; CSSM_CC_HANDLE ccHand = 0; CSSM_KEY wrappedKey; CSSM_KEY unwrappedKey; CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader; CSSM_DATA descrData = {0, NULL}; // not used for PKCS8 wrap CSSM_KEYATTR_FLAGS reqAttr = keyAttrs; ResourceControlContext rcc; ResourceControlContext *rccPtr = NULL; Security::KeychainCore::Access::Maker maker; /* P12 style IV derivation, optional */ CSSM_DATA iv = {0, NULL}; CSSM_DATA_PTR ivPtr = NULL; if(blockSizeInBytes) { coder.allocItem(iv, blockSizeInBytes); ivPtr = &iv; } /* P12 style key derivation */ crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, keySizeInBits, iterCount, salt, pwd, passKey, iv); if(crtn) { return crtn; } /* subsequent errors to errOut: */ /* CSSM context */ crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, mode, NULL, // access cred &ckey, ivPtr, // InitVector, optional padding, NULL, // Params &ccHand); if(crtn) { p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn); goto errOut; } if(dlDbHand) { crtn = p12AddContextAttribute(ccHand, CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE), dlDbHand); if(crtn) { p12LogCssmError("AddContextAttribute", crtn); goto errOut; } } /* * Cook up minimal WrappedKey header fields */ memset(&wrappedKey, 0, sizeof(CSSM_KEY)); memset(&unwrappedKey, 0, sizeof(CSSM_KEY)); hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; hdr.BlobType = CSSM_KEYBLOB_WRAPPED; hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; /* * This one we do not know. The CSP will figure out the format * of the unwrapped key after it decrypts the raw key material. */ hdr.AlgorithmId = CSSM_ALGID_NONE; hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; /* also inferred by CSP */ hdr.LogicalKeySizeInBits = 0; hdr.KeyAttr = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE; hdr.KeyUsage = CSSM_KEYUSE_ANY; hdr.WrapAlgorithmId = encrAlg; hdr.WrapMode = mode; if(dlDbHand && keyIsPermanent) { reqAttr |= CSSM_KEYATTR_PERMANENT; } wrappedKey.KeyData = shroudedKeyBits; if(!noAcl) { // Create a Access::Maker for the initial owner of the private key. memset(&rcc, 0, sizeof(rcc)); maker.initialOwner(rcc); rccPtr = &rcc; } crtn = CSSM_UnwrapKey(ccHand, NULL, // PublicKey &wrappedKey, keyUsage, reqAttr, &labelData, rccPtr, // CredAndAclEntry privKey, &descrData); // required if(crtn) { p12LogCssmError("CSSM_UnwrapKey", crtn); if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) { /* report in a keychain-friendly way */ crtn = errSecDuplicateItem; } } // Finally fix the acl and owner of the private key to the // specified access control settings. if((crtn == CSSM_OK) && !noAcl) { try { CssmClient::KeyAclBearer bearer( cspHand, *privKey, Allocator::standard()); SecPointer<KeychainCore::Access> initialAccess(access ? KeychainCore::Access::required(access) : /* caller-supplied */ new KeychainCore::Access("privateKey")); /* default */ initialAccess->setAccess(bearer, maker); } catch (const CssmError &e) { /* not implemented means we're talking to the CSP which does * not implement ACLs */ if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) { crtn = e.error; } } catch(...) { p12ErrorLog("p12 exception on setAccess\n"); crtn = errSecAuthFailed; /* ??? */ } } errOut: if(ccHand) { CSSM_DeleteContext(ccHand); } CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); return crtn; }
/* * Decrypt (typically, an encrypted P7 ContentInfo contents) */ CSSM_RETURN p12Encrypt( CSSM_CSP_HANDLE cspHand, const CSSM_DATA &plainText, CSSM_ALGORITHMS keyAlg, CSSM_ALGORITHMS encrAlg, CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only uint32 keySizeInBits, uint32 blockSizeInBytes, // for IV CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. uint32 iterCount, const CSSM_DATA &salt, /* exactly one of the following two must be valid */ const CSSM_DATA *pwd, // unicode external representation const CSSM_KEY *passKey, SecNssCoder &coder, // for mallocing cipherText CSSM_DATA &cipherText) { CSSM_RETURN crtn; CSSM_KEY ckey; CSSM_CC_HANDLE ccHand = 0; CSSM_DATA ourCtext = {0, NULL}; CSSM_DATA remData = {0, NULL}; /* P12 style IV derivation, optional */ CSSM_DATA iv = {0, NULL}; CSSM_DATA_PTR ivPtr = NULL; if(blockSizeInBytes) { coder.allocItem(iv, blockSizeInBytes); ivPtr = &iv; } /* P12 style key derivation */ crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, keySizeInBits, iterCount, salt, pwd, passKey, iv); if(crtn) { return crtn; } /* subsequent errors to errOut: */ /* CSSM context */ crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, mode, NULL, // access cred &ckey, ivPtr, // InitVector, optional padding, NULL, // Params &ccHand); if(crtn) { cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn); goto errOut; } /* go - CSP mallocs ctext and rem data */ CSSM_SIZE bytesEncrypted; crtn = CSSM_EncryptData(ccHand, &plainText, 1, &ourCtext, 1, &bytesEncrypted, &remData); if(crtn) { cuPrintError("CSSM_DecryptData", crtn); } else { coder.allocCopyItem(ourCtext, cipherText); cipherText.Length = bytesEncrypted; /* plaintext copied into coder space; free the memory allocated * by the CSP */ freeCssmMemory(cspHand, ourCtext.Data); } /* an artifact of CSPFUllPLuginSession - this never contains * valid data but sometimes gets mallocds */ if(remData.Data) { freeCssmMemory(cspHand, remData.Data); } errOut: if(ccHand) { CSSM_DeleteContext(ccHand); } CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); return crtn; }
/* NULL wrap a key to specified format. */ static CSSM_RETURN nullWrapKey(CSSM_CSP_HANDLE cspHand, const CSSM_KEY *refKey, CSSM_KEYBLOB_FORMAT blobFormat, CSSM_KEY_PTR rawKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; CSSM_DATA descData = {0, 0}; memset(rawKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateSymmetricContext(cspHand, CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, // passPhrase NULL, // unwrappingKey NULL, // initVector CSSM_PADDING_NONE, 0, // Params &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return crtn; } if(blobFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) { /* only add this attribute if it's not the default */ CSSM_ATTRIBUTE_TYPE attrType; switch(refKey->KeyHeader.KeyClass) { case CSSM_KEYCLASS_SESSION_KEY: attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT; break; case CSSM_KEYCLASS_PUBLIC_KEY: attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT; break; case CSSM_KEYCLASS_PRIVATE_KEY: attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT; break; default: printf("***Bogus KeyClass in nullWrapKey\n"); return -1; } CSSM_CONTEXT_ATTRIBUTE attr; attr.AttributeType = attrType; attr.AttributeLength = sizeof(uint32); attr.Attribute.Uint32 = blobFormat; crtn = CSSM_UpdateContextAttributes( ccHand, 1, &attr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_WrapKey(ccHand, &creds, refKey, &descData, rawKey); if(crtn != CSSM_OK) { printError("CSSM_WrapKey", crtn); } if(CSSM_DeleteContext(ccHand)) { printf("CSSM_DeleteContext failure\n"); } return crtn; }
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; }
/* wrap key function. */ static CSSM_RETURN wrapKey(CSSM_CSP_HANDLE cspHand, const CSSM_KEY_PTR unwrappedKey, // must be ref const CSSM_KEY_PTR wrappingKey, CSSM_ALGORITHMS wrapAlg, CSSM_ENCRYPT_MODE wrapMode, CSSM_KEYBLOB_FORMAT wrapFormat, // NONE, PKCS7, PKCS8 CSSM_PADDING wrapPad, CSSM_KEY_PTR wrappedKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_RETURN crtn2; #if WRAP_KEY_REQUIRES_CREDS CSSM_ACCESS_CREDENTIALS creds; #endif #if 0 if(unwrappedKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) { printf("Hey! you can only wrap a reference key!\n"); return CSSM_ERRCODE_INTERNAL_ERROR; } #endif memset(wrappedKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); /* special case for NULL wrap - no wrapping key */ if((wrappingKey == NULL) || (wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, wrapAlg, wrapMode, &creds, // accessCred wrappingKey, &initVector, wrapPad, // Padding NULL, // Reserved &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } } else { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, wrapAlg, &creds, // passPhrase wrappingKey, wrapPad, // Padding &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } /* CMS requires 8-byte IV */ crtn = AddContextAttribute(ccHand, CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA), CAT_Ptr, &initVector, 0); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) { /* only add this attribute if it's not the default */ CSSM_CONTEXT_ATTRIBUTE attr; attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT; attr.AttributeLength = sizeof(uint32); attr.Attribute.Uint32 = wrapFormat; crtn = CSSM_UpdateContextAttributes( ccHand, 1, &attr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_WrapKey(ccHand, #if WRAP_KEY_REQUIRES_CREDS &creds, #else NULL, // AccessCred #endif unwrappedKey, NULL, // DescriptiveData wrappedKey); if(crtn != CSSM_OK) { printError("CSSM_WrapKey", crtn); } if((crtn2 = CSSM_DeleteContext(ccHand))) { printError("CSSM_DeleteContext", crtn2); } return crtn; }
/* unwrap key function. */ static CSSM_RETURN unwrapKey(CSSM_CSP_HANDLE cspHand, const CSSM_KEY_PTR wrappedKey, const CSSM_KEY_PTR unwrappingKey, CSSM_ALGORITHMS unwrapAlg, CSSM_ENCRYPT_MODE unwrapMode, CSSM_PADDING unwrapPad, CSSM_KEY_PTR unwrappedKey, // RETURNED const unsigned char *keyLabel, unsigned keyLabelLen) { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_RETURN crtn2; CSSM_DATA labelData; uint32 keyAttr; CSSM_DATA descData = { 0, NULL }; CSSM_ACCESS_CREDENTIALS creds; memset(unwrappedKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); if((unwrappingKey == NULL) || (unwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, unwrapAlg, unwrapMode, &creds, // accessCreds unwrappingKey, &initVector, unwrapPad, // Padding 0, // Reserved &ccHand); if(crtn) { printError("cspUnwrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } } else { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, unwrapAlg, &creds, // passPhrase, unwrappingKey, unwrapPad, // Padding &ccHand); if(crtn) { printError("cspUnwrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } /* CMS requires 8-byte IV */ crtn = AddContextAttribute(ccHand, CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA), CAT_Ptr, &initVector, 0); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } labelData.Data = (uint8 *)keyLabel; labelData.Length = keyLabelLen; /* * New keyAttr - clear some old bits, make sure we ask for ref key */ keyAttr = wrappedKey->KeyHeader.KeyAttr; keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE); keyAttr |= CSSM_KEYATTR_RETURN_REF; crtn = CSSM_UnwrapKey(ccHand, NULL, // PublicKey wrappedKey, CSSM_KEYUSE_ANY, // FIXME keyAttr, &labelData, NULL, // CredAndAclEntry unwrappedKey, &descData); // required if(crtn != CSSM_OK) { printError("CSSM_UnwrapKey", crtn); } if((crtn2 = CSSM_DeleteContext(ccHand))) { printError("CSSM_DeleteContext", crtn2); } return crtn; }
static int doDecrypt( CSSM_CSP_HANDLE cspHand, const char *algStr, CSSM_KEY_PTR key, // session, private CSSM_ALGORITHMS encrAlg, CSSM_ENCRYPT_MODE encrMode, CSSM_PADDING encrPad, DecrResult expResult, CSSM_BOOL quiet) { uint8 ctextData[CTEXT_SIZE]; CSSM_DATA ctext = {CTEXT_SIZE, ctextData}; uint8 someIvData[IV_SIZE]; CSSM_DATA someIv = {IV_SIZE, someIvData}; /* * I have not found a way to guarantee decrypt failure here, no matter * what ctext and IV I specify. We can't just do an encrypt and * munge because we might be testing a bad (expired) key. * We might have to redesign, first generating a good key, then an * expired key from it...? Until then this test is loose about * handling "key is good" detection. */ memset(ctextData, 0, CTEXT_SIZE); // guaranteed bad padding memset(someIvData, 0, IV_SIZE); CSSM_CC_HANDLE cryptHand = 0; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); if(key->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, encrMode, NULL, // access cred key, &someIv, encrPad, NULL, // Params &cryptHand); if(crtn) { printError("CSSM_CSP_CreateSymmetricContext", crtn); return testError(quiet); } } else if(key->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, encrAlg, &creds, // access key, encrPad, &cryptHand); if(crtn) { printError("CSSM_CSP_CreateAsymmetricContext", crtn); return testError(quiet); } } else { printf("***BRRZAP! Only decrypt with session and private" " keys\n"); exit(1); } CSSM_DATA ptext = {0, NULL}; CSSM_DATA remData = {0, NULL}; CSSM_SIZE bDecr; int irtn = 0; crtn = CSSM_DecryptData(cryptHand, &ctext, 1, &ptext, 1, &bDecr, &remData); switch(expResult) { case DR_BadStartDate: if(crtn != CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE) { printf("***Decrypt with %s: expected INVALID_KEY_START_DATE, " "got %s.\n", algStr, cssmErrToStr(crtn)); irtn = testError(quiet); } break; case DR_BadEndDate: if(crtn != CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE) { printf("***Decrypt with %s: expected INVALID_KEY_END_DATE, " "got %s.\n", algStr, cssmErrToStr(crtn)); irtn = testError(quiet); } break; case DR_BadData: switch(crtn) { case CSSM_OK: // good data, seen sometimes case CSSMERR_CSP_INVALID_DATA: // common case case CSSMERR_CSP_INTERNAL_ERROR: // default case in CSP's // throwRsaDsa() :-( break; default: printf("***Decrypt with %s: expected INVALID_DATA or OK, " "got %s.\n", algStr, cssmErrToStr(crtn)); irtn = testError(quiet); break; } break; } appFreeCssmData(&ptext, CSSM_FALSE); appFreeCssmData(&remData, CSSM_FALSE); CSSM_DeleteContext(cryptHand); return irtn; }
static int doEncrypt( CSSM_CSP_HANDLE cspHand, const char *algStr, CSSM_KEY_PTR key, // session, public CSSM_ALGORITHMS encrAlg, CSSM_ENCRYPT_MODE encrMode, CSSM_PADDING encrPad, CSSM_RETURN expRtn, // expected result CSSM_BOOL quiet) { uint8 ptextData[PTEXT_SIZE]; CSSM_DATA ptext = {PTEXT_SIZE, ptextData}; uint8 someIvData[IV_SIZE]; CSSM_DATA someIv = {IV_SIZE, someIvData}; simpleGenData(&ptext, PTEXT_SIZE, PTEXT_SIZE); simpleGenData(&someIv, IV_SIZE, IV_SIZE); CSSM_CC_HANDLE cryptHand = 0; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); if(key->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, encrMode, NULL, // access cred key, &someIv, encrPad, NULL, // Params &cryptHand); if(crtn) { printError("CSSM_CSP_CreateSymmetricContext", crtn); return testError(quiet); } } else if(key->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, encrAlg, &creds, // access key, encrPad, &cryptHand); if(crtn) { printError("CSSM_CSP_CreateAsymmetricContext", crtn); return testError(quiet); } } else { printf("***BRRZAP! Only encrypt with session and public keys\n"); exit(1); } CSSM_DATA ctext = {0, NULL}; CSSM_DATA remData = {0, NULL}; CSSM_SIZE bEncr; int irtn = 0; crtn = CSSM_EncryptData(cryptHand, &ptext, 1, &ctext, 1, &bEncr, &remData); if(crtn != expRtn) { if(expRtn == CSSM_OK) { printError("CSSM_EncryptData", crtn); printf("Unexpected error encrypting with %s\n", algStr); } else { printf("***Encrypt with %s: expected %s, got %s.\n", algStr, cssmErrToStr(expRtn), cssmErrToStr(crtn)); } irtn = testError(quiet); } appFreeCssmData(&ctext, CSSM_FALSE); appFreeCssmData(&remData, CSSM_FALSE); CSSM_DeleteContext(cryptHand); return irtn; }
static int badWrapTest( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR unwrappedKey, CSSM_KEYBLOB_FORMAT wrapForm, CSSM_BOOL quiet, const char *keyAlgStr, const char *testStr) { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; CSSM_KEY wrappedKey; // should not get created CSSM_KEY wrappingKey; int irtn; /* first generate a DES wrapping key */ if(genSymKey(cspHand, &wrappingKey, CSSM_ALGID_DES, "DES", CSP_DES_KEY_SIZE_DEFAULT, CSSM_KEYATTR_RETURN_REF, CSSM_KEYUSE_ANY, CSSM_OK, quiet, CSSM_FALSE, "not a test case")) { return 1; } memset(&wrappedKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); /* symmetric wrapping context */ crtn = CSSM_CSP_CreateSymmetricContext(cspHand, CSSM_ALGID_DES, CSSM_ALGMODE_CBCPadIV8, &creds, // passPhrase, &wrappingKey, NULL, // IV CSSM_PADDING_PKCS5, 0, // Params &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return testError(quiet); } /* do it, demand error */ crtn = CSSM_WrapKey(ccHand, &creds, unwrappedKey, NULL, // DescriptiveData &wrappedKey); if(crtn != CSSMERR_CSP_INVALID_KEYATTR_MASK) { printf("***Testing %s for alg %s:\n", testStr, keyAlgStr); printf(" CSSM_WrapKey: expect CSSMERR_CSP_INVALID_KEYATTR_MASK, got %s\n", cssmErrToStr(crtn)); irtn = testError(quiet); } else { irtn = 0; } CSSM_DeleteContext(ccHand); cspFreeKey(cspHand, &wrappingKey); return irtn; }