static int kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA * rsa, int padding) { struct kc_rsa *kc = RSA_get_app_data(rsa); CSSM_RETURN cret; OSStatus ret; const CSSM_ACCESS_CREDENTIALS *creds; SecKeyRef privKeyRef = kc->pkey; CSSM_CSP_HANDLE cspHandle; const CSSM_KEY *cssmKey; CSSM_CC_HANDLE handle = 0; CSSM_DATA out, in, rem; int fret = 0; CSSM_SIZE outlen = 0; char remdata[1024]; if (padding != RSA_PKCS1_PADDING) return -1; cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); if(cret) heim_abort("SecKeyGetCSSMKey failed: %d", (int)cret); cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); if(cret) heim_abort("SecKeyGetCSPHandle failed: %d", (int)cret); ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeNoUI, &creds); if(ret) heim_abort("SecKeyGetCredentials failed: %d", (int)ret); ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, CSSM_ALGID_RSA, creds, cssmKey, CSSM_PADDING_PKCS1, &handle); if(ret) heim_abort("CSSM_CSP_CreateAsymmetricContext failed: %d", (int)ret); in.Data = (uint8 *)from; in.Length = flen; out.Data = (uint8 *)to; out.Length = kc->keysize; rem.Data = (uint8 *)remdata; rem.Length = sizeof(remdata); cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); if(cret) { /* cssmErrorString(cret); */ fret = -1; } else fret = (int)out.Length; if(handle) CSSM_DeleteContext(handle); return fret; }
/* * Calculate digest of any CSSM_KEY. Unlike older implementations * of this logic, you can actually calculate the public key hash * on any class of key, any format, raw CSP or CSPDL (though if * you're using the CSPDL, the key has to be a reference key * in that CSPDL session). * * Caller must free keyDigest->Data using impExpFreeCssmMemory() since * this is allocated by the CSP's app-specified allocator. */ CSSM_RETURN impExpKeyDigest( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR key, CSSM_DATA_PTR keyDigest) // contents allocd and RETURNED { CSSM_DATA_PTR localDigest; CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn = CSSM_CSP_CreatePassThroughContext(cspHand, key, &ccHand); if(crtn) { return crtn; } crtn = CSSM_CSP_PassThrough(ccHand, CSSM_APPLECSP_KEYDIGEST, NULL, (void **)&localDigest); if(crtn) { SecImpExpDbg("CSSM_CSP_PassThrough(KEY_DIGEST) failure"); } else { /* * Give caller the Data referent and we'll free the * CSSM_DATA struct itswelf. */ *keyDigest = *localDigest; impExpFreeCssmMemory(cspHand, localDigest); } CSSM_DeleteContext(ccHand); return crtn; }
/* * Sign/verify wrappers. */ static CSSM_RETURN sigSign(CSSM_CSP_HANDLE cspHandle, uint32 algorithm, // CSSM_ALGID_SHA1WithRSA, etc. CSSM_KEY_PTR key, // private key const CSSM_DATA *text, CSSM_DATA_PTR sig) { CSSM_CC_HANDLE sigHand; CSSM_RETURN crtn; crtn = CSSM_CSP_CreateSignatureContext(cspHandle, algorithm, NULL, // passPhrase key, &sigHand); if(crtn) { return crtn; } crtn = CSSM_SignData(sigHand, text, 1, CSSM_ALGID_NONE, sig); CSSM_DeleteContext(sigHand); return crtn; }
/* * Staged init - cook up a CSSM_CC_HANDLE and call the appropriate * init. */ CSSM_RETURN cdsaStagedEncDecrInit( CSSM_CSP_HANDLE cspHandle, // from cdsaCspAttach() const CSSM_KEY *key, // from cdsaDeriveKey() StagedOpType opType, // SO_Encrypt, SO_Decrypt CSSM_CC_HANDLE *ccHandle) // RETURNED { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand; crtn = genCryptHandle(cspHandle, key, &ivCommon, &ccHand); if(crtn) { return crtn; } switch(opType) { case SO_Encrypt: crtn = CSSM_EncryptDataInit(ccHand); break; case SO_Decrypt: crtn = CSSM_DecryptDataInit(ccHand); break; default: return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED; } if(crtn) { CSSM_DeleteContext(ccHand); } else { *ccHandle = ccHand; } return CSSM_OK; }
/* * Calculate the MAC for a PFX. Caller is either going compare * the result against an existing PFX's MAC or drop the result into * a newly created PFX. */ CSSM_RETURN p12GenMac( CSSM_CSP_HANDLE cspHand, const CSSM_DATA &ptext, // e.g., NSS_P12_DecodedPFX.derAuthSaafe CSSM_ALGORITHMS alg, // better be SHA1! unsigned 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 macData CSSM_DATA &macData) // RETURNED { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand = 0; /* P12 style key derivation */ unsigned keySizeInBits; CSSM_ALGORITHMS hmacAlg; switch(alg) { case CSSM_ALGID_SHA1: keySizeInBits = 160; hmacAlg = CSSM_ALGID_SHA1HMAC; break; case CSSM_ALGID_MD5: /* not even sure if this is legal in p12 world... */ keySizeInBits = 128; hmacAlg = CSSM_ALGID_MD5HMAC; break; default: return CSSMERR_CSP_INVALID_ALGORITHM; } CSSM_KEY macKey; CSSM_DATA iv = {0, NULL}; crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg, keySizeInBits, iterCount, salt, pwd, passKey, iv); if(crtn) { return crtn; } /* subsequent errors to errOut: */ /* prealloc the mac data */ coder.allocItem(macData, keySizeInBits / 8); crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand); if(crtn) { cuPrintError("CSSM_CSP_CreateMacContext", crtn); goto errOut; } crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData); if(crtn) { cuPrintError("CSSM_GenerateMac", crtn); } errOut: if(ccHand) { CSSM_DeleteContext(ccHand); } CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE); return crtn; }
/* * SecCmsDigestContextCancel - cancel digesting operation */ void SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx) { int i; for (i = 0; i < cmsdigcx->digcnt; i++) if (cmsdigcx->digobjs[i]) CSSM_DeleteContext(cmsdigcx->digobjs[i]); }
void SecCmsCipherContextDestroy(SecCmsCipherContext *cc) { PORT_Assert(cc != NULL); if (cc == NULL) return; CSSM_DeleteContext(cc->cc); PORT_Free(cc); }
void Context::deactivate() { StLock<Mutex> _(mActivateMutex); if (mActive) { mActive = false; check(CSSM_DeleteContext(mHandle)); } }
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; }
/* verify a cert using specified key and/or signerCert */ static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand, CSSM_CSP_HANDLE cspHand, CSSM_DATA_PTR cert, CSSM_DATA_PTR signerCert, // optional CSSM_KEY_PTR key, // ditto, to work spec one, other, or both CSSM_ALGORITHMS sigAlg, // CSSM_ALGID_SHA1WithRSA, etc. CSSM_RETURN expectResult, const char *opString) { CSSM_RETURN crtn; CSSM_CC_HANDLE signContext = CSSM_INVALID_HANDLE; if(key) { crtn = CSSM_CSP_CreateSignatureContext(cspHand, sigAlg, NULL, // AccessCred key, &signContext); if(crtn) { printf("Failure during %s\n", opString); printError("CSSM_CSP_CreateSignatureContext", crtn); return crtn; } } crtn = CSSM_CL_CertVerify(clHand, signContext, cert, // CertToBeVerified signerCert, // SignerCert NULL, // VerifyScope 0); // ScopeSize if(crtn != expectResult) { printf("Failure during %s\n", opString); if(crtn == CSSM_OK) { printf("Unexpected CSSM_CL_CertVerify success\n"); } else if(expectResult == CSSM_OK) { printError("CSSM_CL_CertVerify", crtn); } else { printError("CSSM_CL_CertVerify: expected", expectResult); printError("CSSM_CL_CertVerify: got ", crtn); } return CSSMERR_CL_VERIFICATION_FAILURE; } if(signContext != CSSM_INVALID_HANDLE) { crtn = CSSM_DeleteContext(signContext); if(crtn) { printf("Failure during %s\n", opString); printError("CSSM_DeleteContext", crtn); return crtn; } } return CSSM_OK; }
static int kc_rsa_private_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { struct kc_rsa *kc = RSA_get_app_data(rsa); CSSM_RETURN cret; OSStatus ret; const CSSM_ACCESS_CREDENTIALS *creds; SecKeyRef privKeyRef = (SecKeyRef)kc->item; CSSM_CSP_HANDLE cspHandle; const CSSM_KEY *cssmKey; CSSM_CC_HANDLE sigHandle = 0; CSSM_DATA sig, in; int fret = 0; if (padding != RSA_PKCS1_PADDING) return -1; cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); if(cret) abort(); cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); if(cret) abort(); ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, &creds); if(ret) abort(); ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, creds, cssmKey, &sigHandle); if(ret) abort(); in.Data = (uint8 *)from; in.Length = flen; sig.Data = (uint8 *)to; sig.Length = kc->keysize; cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); if(cret) { /* cssmErrorString(cret); */ fret = -1; } else fret = sig.Length; if(sigHandle) CSSM_DeleteContext(sigHandle); return fret; }
/* * Common, flexible, error-tolerant symmetric key generator. */ static int genSymKey( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR symKey, uint32 alg, const char *keyAlgStr, uint32 keySizeInBits, CSSM_KEYATTR_FLAGS keyAttr, CSSM_KEYUSE keyUsage, CSSM_RETURN expectRtn, CSSM_BOOL quiet, CSSM_BOOL freeKey, // true: free the key on exit const char *testStr) { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand; CSSM_DATA dummyLabel = {4, (uint8 *)"foo"}; int irtn; memset(symKey, 0, sizeof(CSSM_KEY)); crtn = CSSM_CSP_CreateKeyGenContext(cspHand, alg, keySizeInBits, // keySizeInBits NULL, // Seed NULL, // Salt NULL, // StartDate NULL, // EndDate NULL, // Params &ccHand); if(crtn) { printError("CSSM_CSP_CreateKeyGenContext", crtn); return testError(quiet); } crtn = CSSM_GenerateKey(ccHand, keyUsage, keyAttr, &dummyLabel, NULL, // ACL symKey); if(crtn != expectRtn) { printf("***Testing %s for alg %s:\n", testStr, keyAlgStr); printf(" CSSM_GenerateKey: expect %s\n", cssmErrToStr(expectRtn)); printf(" CSSM_GenerateKey: got %s\n", cssmErrToStr(crtn)); irtn = testError(quiet); } else { irtn = 0; } CSSM_DeleteContext(ccHand); if(freeKey && (crtn == CSSM_OK)) { cspFreeKey(cspHand, symKey); } return irtn; }
/* * Derive a symmetric CSSM_KEY from the specified raw key material. */ CSSM_RETURN cdsaDeriveKey( CSSM_CSP_HANDLE cspHandle, const void *rawKey, size_t rawKeyLen, CSSM_ALGORITHMS keyAlg, // e.g., CSSM_ALGID_AES uint32 keySizeInBits, CSSM_KEY_PTR key) { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand; CSSM_DATA dummyLabel = {8, (uint8 *)"tempKey"}; CSSM_DATA saltData = {8, (uint8 *)"someSalt"}; CSSM_PKCS5_PBKDF2_PARAMS pbeParams; CSSM_DATA pbeData; CSSM_ACCESS_CREDENTIALS creds; memset(key, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateDeriveKeyContext(cspHandle, CSSM_ALGID_PKCS5_PBKDF2, keyAlg, keySizeInBits, &creds, NULL, // BaseKey 1000, // iterationCount, 1000 is the minimum &saltData, NULL, // seed &ccHand); if(crtn) { return crtn; } /* this is the caller's raw key bits, typically ASCII (though it * could be anything) */ pbeParams.Passphrase.Data = (uint8 *)rawKey; pbeParams.Passphrase.Length = rawKeyLen; /* The only PRF supported by the CSP is HMACSHA1 */ pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1; pbeData.Data = (uint8 *)&pbeParams; pbeData.Length = sizeof(pbeParams); crtn = CSSM_DeriveKey(ccHand, &pbeData, CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &dummyLabel, NULL, // cred and acl key); CSSM_DeleteContext(ccHand); // ignore error here return crtn; }
static int doVerify( CSSM_CSP_HANDLE cspHand, const char *algStr, CSSM_KEY_PTR key, // private CSSM_ALGORITHMS sigAlg, CSSM_RETURN expRtn, // expected result CSSM_BOOL quiet) { uint8 ptextData[PTEXT_SIZE]; CSSM_DATA ptext = {PTEXT_SIZE, ptextData}; uint8 sigData[PTEXT_SIZE]; CSSM_DATA sig = {PTEXT_SIZE, sigData}; simpleGenData(&ptext, PTEXT_SIZE, PTEXT_SIZE); memset(sigData, 0, PTEXT_SIZE); CSSM_CC_HANDLE cryptHand = 0; CSSM_RETURN crtn; crtn = CSSM_CSP_CreateSignatureContext(cspHand, sigAlg, NULL, // passPhrase key, &cryptHand); if(crtn) { printError("CSSM_CSP_CreateSignatureContext (2)", crtn); return testError(quiet); } int irtn = 0; crtn = CSSM_VerifyData(cryptHand, &ptext, 1, CSSM_ALGID_NONE, &sig); if(crtn != expRtn) { if(expRtn == CSSM_OK) { printError("CSSM_VerifyData", crtn); printf("Unexpected error verifying with %s\n", algStr); } else { printf("***Verify with %s: expected %s, got %s.\n", algStr, cssmErrToStr(expRtn), cssmErrToStr(crtn)); } irtn = testError(quiet); } CSSM_DeleteContext(cryptHand); return irtn; }
/* * 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; }
/* * Perform Diffie-Hellman key exchange. * Given "our" private key (in the form of a CSSM_KEY) and "their" public * key (in the form of a raw blob of bytes), cook up a symmetric key. */ CSSM_RETURN cdsaDhKeyExchange( CSSM_CSP_HANDLE cspHandle, CSSM_KEY_PTR myPrivateKey, // from cdsaDhGenerateKeyPair const void *theirPubKey, uint32 theirPubKeyLen, CSSM_KEY_PTR derivedKey, // RETURNED uint32 deriveKeySizeInBits, CSSM_ALGORITHMS derivedKeyAlg) // e.g., CSSM_ALGID_AES { CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; CSSM_CC_HANDLE ccHandle; CSSM_DATA labelData = {8, (uint8 *)"tempKey"}; memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); memset(derivedKey, 0, sizeof(CSSM_KEY)); crtn = CSSM_CSP_CreateDeriveKeyContext(cspHandle, CSSM_ALGID_DH, derivedKeyAlg, deriveKeySizeInBits, &creds, myPrivateKey, // BaseKey 0, // IterationCount 0, // Salt 0, // Seed &ccHandle); if(crtn) { return crtn; } /* public key passed in as CSSM_DATA *Param */ CSSM_DATA theirPubKeyData = { theirPubKeyLen, (uint8 *)theirPubKey }; crtn = CSSM_DeriveKey(ccHandle, &theirPubKeyData, CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &labelData, NULL, // cread/acl derivedKey); CSSM_DeleteContext(ccHandle); return crtn; }
/* * Decrypt. * plainText->Data is allocated by the CSP and must be freed (via * free()) by caller. */ CSSM_RETURN cdsaDecrypt( CSSM_CSP_HANDLE cspHandle, const CSSM_KEY *key, const CSSM_DATA *cipherText, CSSM_DATA_PTR plainText) { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHandle; CSSM_DATA remData = {0, NULL}; uint32 bytesDecrypted; crtn = genCryptHandle(cspHandle, key, &ivCommon, &ccHandle); if(crtn) { return crtn; } plainText->Length = 0; plainText->Data = NULL; crtn = CSSM_DecryptData(ccHandle, cipherText, 1, plainText, 1, &bytesDecrypted, &remData); CSSM_DeleteContext(ccHandle); if(crtn) { return crtn; } plainText->Length = bytesDecrypted; if(remData.Length != 0) { /* append remaining data to plainText */ uint32 newLen = plainText->Length + remData.Length; plainText->Data = (uint8 *)appRealloc(plainText->Data, newLen, NULL); memmove(plainText->Data + plainText->Length, remData.Data, remData.Length); plainText->Length = newLen; appFree(remData.Data, NULL); } return CSSM_OK; }
static CSSM_RETURN sigVerify(CSSM_CSP_HANDLE cspHand, uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc. CSSM_KEY_PTR key, // public key const CSSM_DATA *text, const CSSM_DATA *sig, uint32 digestAlg, // optional for raw signing CSSM_BOOL noPad) // true --> add PADDING_NONE to context { CSSM_CC_HANDLE sigHand; CSSM_RETURN crtn; crtn = CSSM_CSP_CreateSignatureContext(cspHand, algorithm, NULL, // passPhrase key, &sigHand); if(crtn) { printError("CSSM_CSP_CreateSignatureContext", crtn); return crtn; } if(noPad) { crtn = AddContextAttribute(sigHand, CSSM_ATTRIBUTE_PADDING, sizeof(uint32), CAT_Uint32, NULL, CSSM_PADDING_NONE); if(crtn) { return crtn; } } crtn = CSSM_VerifyData(sigHand, text, 1, digestAlg, sig); if(crtn) { printError("CSSM_VerifyData", crtn); } CSSM_DeleteContext(sigHand); return crtn; }
static int badDecrypt( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR key, const char *keyAlgStr, CSSM_ALGORITHMS opAlg, CSSM_RETURN expectRtn, CSSM_BOOL quiet, const char *goodUseStr, const char *badUseStr) { CSSM_CC_HANDLE cryptHand; CSSM_DATA ctext = {4, (uint8 *)"foo"}; CSSM_DATA ptext = {0, NULL}; CSSM_DATA remData = {0, NULL}; CSSM_RETURN crtn; CSSM_SIZE bytesDecrypted; int irtn; cryptHand = genCryptHandle(cspHand, opAlg, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE, key, NULL /* key2 */, NULL /* iv */, 0, 0); if(cryptHand == 0) { return testError(quiet); } crtn = CSSM_DecryptData(cryptHand, &ctext, 1, &ptext, 1, &bytesDecrypted, &remData); if(crtn != expectRtn) { printf("***Testing %s key w/%s during %s:\n", keyAlgStr, goodUseStr, badUseStr); printf(" CSSM_DecryptData: expect %s\n", cssmErrToStr(expectRtn)); printf(" CSSM_DecryptData: got %s\n", cssmErrToStr(crtn)); irtn = testError(quiet); } else { irtn = 0; } /* assume no ptext or remdata - OK? */ CSSM_DeleteContext(cryptHand); 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); }
CSSM_RETURN cuCspGenKeyPair(CSSM_CSP_HANDLE cspHand, CSSM_DL_DB_HANDLE *dlDbHand, // optional uint32 algorithm, const char *keyLabel, unsigned keyLabelLen, uint32 keySize, // in bits CSSM_KEY_PTR pubKey, // mallocd by caller CSSM_KEYUSE pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc. CSSM_KEYATTR_FLAGS pubAttrs, // CSSM_KEYATTR_EXTRACTABLE, etc. CSSM_KEY_PTR privKey, // mallocd by caller CSSM_KEYUSE privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc. CSSM_KEYATTR_FLAGS privAttrs) // CSSM_KEYATTR_EXTRACTABLE, etc. { CSSM_RETURN crtn; CSSM_RETURN ocrtn; CSSM_CC_HANDLE ccHand; CSSM_DATA keyLabelData; keyLabelData.Data = (uint8 *)keyLabel, keyLabelData.Length = keyLabelLen; memset(pubKey, 0, sizeof(CSSM_KEY)); memset(privKey, 0, sizeof(CSSM_KEY)); crtn = CSSM_CSP_CreateKeyGenContext(cspHand, algorithm, keySize, NULL, // Seed NULL, // Salt NULL, // StartDate NULL, // EndDate NULL, // Params &ccHand); if(crtn) { cuPrintError("CSSM_CSP_CreateKeyGenContext", crtn); return crtn; } /* post-context-create algorithm-specific stuff */ switch(algorithm) { #if DO_DSA_GEN_PARAMS case CSSM_ALGID_DSA: /* * extra step - generate params - this just adds some * info to the context */ { CSSM_DATA dummy = {0, NULL}; crtn = CSSM_GenerateAlgorithmParams(ccHand, keySize, &dummy); if(crtn) { cuPrintError("CSSM_GenerateAlgorithmParams", crtn); CSSM_DeleteContext(ccHand); return crtn; } cuAppFree(dummy.Data, NULL); } break; #endif /* DO_DSA_GEN_PARAMS */ default: break; } /* optionally specify DL/DB storage location */ if(dlDbHand) { crtn = cuAddContextAttribute(ccHand, CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE), dlDbHand); if(crtn) { CSSM_DeleteContext(ccHand); return crtn; } } ocrtn = CSSM_GenerateKeyPair(ccHand, pubKeyUsage, pubAttrs, &keyLabelData, pubKey, privKeyUsage, privAttrs, &keyLabelData, // same labels NULL, // CredAndAclEntry privKey); if(ocrtn) { cuPrintError("CSSM_GenerateKeyPair", ocrtn); } crtn = CSSM_DeleteContext(ccHand); if(crtn) { cuPrintError("CSSM_DeleteContext", crtn); if(ocrtn == CSSM_OK) { /* error on CSSM_GenerateKeyPair takes precedence */ ocrtn = crtn; } } return ocrtn; }
int main(int argc, char **argv) { CSSM_CL_HANDLE clHand; // CL handle CSSM_X509_NAME *subjName; CSSM_X509_NAME *rootName; CSSM_X509_TIME *notBefore; // UTC-style "not before" time CSSM_X509_TIME *notAfter; // UTC-style "not after" time CSSM_DATA_PTR rawCert; // from CSSM_CL_CertCreateTemplate CSSM_DATA signedRootCert; // from CSSM_CL_CertSign CSSM_DATA signedSubjCert; // from CSSM_CL_CertSign CSSM_CSP_HANDLE cspHand; // CSP handle CSSM_KEY subjPubKey; // subject's RSA public key blob CSSM_KEY subjPrivKey; // subject's RSA private key - ref format CSSM_KEY rootPubKey; // root's RSA public key blob CSSM_KEY rootPrivKey; // root's RSA private key - ref format CSSM_RETURN crtn; CSSM_KEY_PTR extractRootKey; // from CSSM_CL_CertGetKeyInfo() CSSM_KEY_PTR extractSubjKey; // ditto CSSM_CC_HANDLE signContext; // for signing/verifying the cert unsigned badByte; int arg; unsigned errorCount = 0; /* user-spec'd variables */ CSSM_BOOL writeBlobs = CSSM_FALSE; CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT; CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT; uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT; /* * Two extensions. Subject has one (KeyUsage); root has KeyUsage and * BasicConstraints. */ CSSM_X509_EXTENSION exts[2]; CE_KeyUsage keyUsage; CE_BasicConstraints bc; for(arg=1; arg<argc; arg++) { switch(argv[arg][0]) { case 'w': writeBlobs = CSSM_TRUE; break; case 'a': if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) { usage(argv); } switch(argv[arg][2]) { case 's': keyAlg = CSSM_ALGID_RSA; sigAlg = CSSM_ALGID_SHA1WithRSA; break; case 'm': keyAlg = CSSM_ALGID_RSA; sigAlg = CSSM_ALGID_MD5WithRSA; break; case 'f': keyAlg = CSSM_ALGID_FEE; sigAlg = CSSM_ALGID_FEE_MD5; break; case 'F': keyAlg = CSSM_ALGID_FEE; sigAlg = CSSM_ALGID_FEE_SHA1; break; case 'e': keyAlg = CSSM_ALGID_FEE; sigAlg = CSSM_ALGID_SHA1WithECDSA; break; case 'E': keyAlg = CSSM_ALGID_ECDSA; sigAlg = CSSM_ALGID_SHA1WithECDSA; break; case '7': keyAlg = CSSM_ALGID_ECDSA; sigAlg = CSSM_ALGID_SHA256WithECDSA; break; case '8': keyAlg = CSSM_ALGID_ECDSA; sigAlg = CSSM_ALGID_SHA384WithECDSA; break; case '9': keyAlg = CSSM_ALGID_ECDSA; sigAlg = CSSM_ALGID_SHA512WithECDSA; break; case '2': keyAlg = CSSM_ALGID_RSA; sigAlg = CSSM_ALGID_SHA224WithRSA; break; case '6': keyAlg = CSSM_ALGID_RSA; sigAlg = CSSM_ALGID_SHA256WithRSA; break; case '3': keyAlg = CSSM_ALGID_RSA; sigAlg = CSSM_ALGID_SHA384WithRSA; break; case '5': keyAlg = CSSM_ALGID_RSA; sigAlg = CSSM_ALGID_SHA512WithRSA; break; default: usage(argv); } break; case 'k': keySizeInBits = atoi(&argv[arg][2]); break; default: usage(argv); } } /* connect to CL and CSP */ clHand = clStartup(); if(clHand == 0) { return 0; } cspHand = cspStartup(); if(cspHand == 0) { return 0; } /* subsequent errors to abort: to detach */ /* cook up an RSA key pair for the subject */ crtn = cspGenKeyPair(cspHand, keyAlg, SUBJ_KEY_LABEL, strlen(SUBJ_KEY_LABEL), keySizeInBits, &subjPubKey, CSSM_FALSE, // pubIsRef - should work both ways, but not yet CSSM_KEYUSE_VERIFY, CSSM_KEYBLOB_RAW_FORMAT_NONE, &subjPrivKey, CSSM_FALSE, // privIsRef CSSM_KEYUSE_SIGN, CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_FALSE); if(crtn) { errorCount++; goto abort; } if(writeBlobs) { writeFile(SUBJ_PRIV_KEY_FILE, subjPrivKey.KeyData.Data, subjPrivKey.KeyData.Length); printf("...wrote %lu bytes to %s\n", subjPrivKey.KeyData.Length, SUBJ_PRIV_KEY_FILE); } /* and the root */ crtn = cspGenKeyPair(cspHand, keyAlg, ROOT_KEY_LABEL, strlen(ROOT_KEY_LABEL), keySizeInBits, &rootPubKey, CSSM_FALSE, // pubIsRef - should work both ways, but not yet CSSM_KEYUSE_VERIFY, CSSM_KEYBLOB_RAW_FORMAT_NONE, &rootPrivKey, CSSM_FALSE, // privIsRef CSSM_KEYUSE_SIGN, CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_FALSE); if(crtn) { errorCount++; goto abort; } if(writeBlobs) { writeFile(ROOT_PRIV_KEY_FILE, rootPrivKey.KeyData.Data, rootPrivKey.KeyData.Length); printf("...wrote %lu bytes to %s\n", rootPrivKey.KeyData.Length, ROOT_PRIV_KEY_FILE); } if(compareKeyData(&rootPubKey, &subjPubKey)) { printf("**WARNING: Identical root and subj keys!\n"); } /* * Cook up various cert fields. * First, the RDNs for subject and issuer. */ rootName = CB_BuildX509Name(rootRdn, NUM_ROOT_NAMES); subjName = CB_BuildX509Name(subjRdn, NUM_SUBJ_NAMES); if((rootName == NULL) || (subjName == NULL)) { printf("CB_BuildX509Name failure"); errorCount++; goto abort; } /* not before/after in generalized time format */ notBefore = CB_BuildX509Time(0); notAfter = CB_BuildX509Time(10000); /* A KeyUsage extension for both certs */ exts[0].extnId = CSSMOID_KeyUsage; exts[0].critical = CSSM_FALSE; exts[0].format = CSSM_X509_DATAFORMAT_PARSED; keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign | CE_KU_KeyEncipherment | CE_KU_DataEncipherment; exts[0].value.parsedValue = &keyUsage; exts[0].BERvalue.Data = NULL; exts[0].BERvalue.Length = 0; /* BasicConstraints for root only */ exts[1].extnId = CSSMOID_BasicConstraints; exts[1].critical = CSSM_TRUE; exts[1].format = CSSM_X509_DATAFORMAT_PARSED; bc.cA = CSSM_TRUE; bc.pathLenConstraintPresent = CSSM_TRUE; bc.pathLenConstraint = 2; exts[1].value.parsedValue = &bc; exts[1].BERvalue.Data = NULL; exts[1].BERvalue.Length = 0; /* cook up root cert */ printf("Creating root cert...\n"); rawCert = CB_MakeCertTemplate(clHand, 0x12345678, // serial number rootName, rootName, notBefore, notAfter, &rootPubKey, sigAlg, NULL, // subjUniqueId NULL, // issuerUniqueId exts, // extensions 2); // numExtensions if(rawCert == NULL) { errorCount++; goto abort; } if(writeBlobs) { writeFile(ROOT_TBS_FILE_NAME, rawCert->Data, rawCert->Length); printf("...wrote %lu bytes to %s\n", rawCert->Length, ROOT_TBS_FILE_NAME); } /* Self-sign; this is a root cert */ crtn = CSSM_CSP_CreateSignatureContext(cspHand, sigAlg, NULL, // AccessCred &rootPrivKey, &signContext); if(crtn) { printError("CSSM_CSP_CreateSignatureContext", crtn); errorCount++; goto abort; } signedRootCert.Data = NULL; signedRootCert.Length = 0; crtn = CSSM_CL_CertSign(clHand, signContext, rawCert, // CertToBeSigned NULL, // SignScope 0, // ScopeSize, &signedRootCert); if(crtn) { printError("CSSM_CL_CertSign", crtn); errorCount++; goto abort; } crtn = CSSM_DeleteContext(signContext); if(crtn) { printError("CSSM_DeleteContext", crtn); errorCount++; goto abort; } appFreeCssmData(rawCert, CSSM_TRUE); if(writeBlobs) { writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, signedRootCert.Length); printf("...wrote %lu bytes to %s\n", signedRootCert.Length, ROOT_CERT_FILE_NAME); } /* now a subject cert signed by the root cert */ printf("Creating subject cert...\n"); rawCert = CB_MakeCertTemplate(clHand, 0x8765, // serial number rootName, subjName, notBefore, notAfter, &subjPubKey, sigAlg, NULL, // subjUniqueId NULL, // issuerUniqueId exts, // extensions 1); // numExtensions if(rawCert == NULL) { errorCount++; goto abort; } if(writeBlobs) { writeFile(SUBJ_TBS_FILE_NAME, rawCert->Data, rawCert->Length); printf("...wrote %lu bytes to %s\n", rawCert->Length, SUBJ_TBS_FILE_NAME); } /* sign by root */ crtn = CSSM_CSP_CreateSignatureContext(cspHand, sigAlg, NULL, // AccessCred &rootPrivKey, &signContext); if(crtn) { printError("CSSM_CSP_CreateSignatureContext", crtn); errorCount++; goto abort; } signedSubjCert.Data = NULL; signedSubjCert.Length = 0; crtn = CSSM_CL_CertSign(clHand, signContext, rawCert, // CertToBeSigned NULL, // SignScope 0, // ScopeSize, &signedSubjCert); if(crtn) { printError("CSSM_CL_CertSign", crtn); errorCount++; goto abort; } crtn = CSSM_DeleteContext(signContext); if(crtn) { printError("CSSM_DeleteContext", crtn); errorCount++; goto abort; } appFreeCssmData(rawCert, CSSM_TRUE); if(writeBlobs) { writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, signedSubjCert.Length); printf("...wrote %lu bytes to %s\n", signedSubjCert.Length, SUBJ_CERT_FILE_NAME); } /* Free the stuff we allocd to get here */ CB_FreeX509Name(rootName); CB_FreeX509Name(subjName); CB_FreeX509Time(notBefore); CB_FreeX509Time(notAfter); /* * Extract public keys from the two certs, verify. */ crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedSubjCert, &extractSubjKey); if(crtn) { printError("CSSM_CL_CertGetKeyInfo", crtn); } else { /* compare key data - header is different. * Known header differences: * -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for * this field * -- Format. rootPubKey : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE) * extractRootKey : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1) * -- KeyAttr. rootPubKey : 0x20 (CSSM_KEYATTR_EXTRACTABLE) * extractRootKey : 0x0 */ if(!compareKeyData(extractSubjKey, &subjPubKey)) { printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n"); } if(extractSubjKey->KeyHeader.LogicalKeySizeInBits != subjPubKey.KeyHeader.LogicalKeySizeInBits) { printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n", (unsigned)extractSubjKey->KeyHeader.LogicalKeySizeInBits, (unsigned)subjPubKey.KeyHeader.LogicalKeySizeInBits); } } crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedRootCert, &extractRootKey); if(crtn) { printError("CSSM_CL_CertGetKeyInfo", crtn); } else { if(!compareKeyData(extractRootKey, &rootPubKey)) { printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n"); } } /* * Verify: */ printf("Verifying certificates...\n"); /* * Verify root cert by root pub key, should succeed. */ if(verifyCert(clHand, cspHand, &signedRootCert, NULL, &rootPubKey, sigAlg, CSSM_OK, "Verify(root by root key)")) { errorCount++; /* continue */ } /* * Verify root cert by root cert, should succeed. */ if(verifyCert(clHand, cspHand, &signedRootCert, &signedRootCert, NULL, CSSM_ALGID_NONE, // sigAlg not used here CSSM_OK, "Verify(root by root cert)")) { errorCount++; /* continue */ } /* * Verify subject cert by root pub key, should succeed. */ if(verifyCert(clHand, cspHand, &signedSubjCert, NULL, &rootPubKey, sigAlg, CSSM_OK, "Verify(subj by root key)")) { errorCount++; /* continue */ } /* * Verify subject cert by root cert, should succeed. */ if(verifyCert(clHand, cspHand, &signedSubjCert, &signedRootCert, NULL, CSSM_ALGID_NONE, // sigAlg not used here CSSM_OK, "Verify(subj by root cert)")) { errorCount++; /* continue */ } /* * Verify subject cert by root cert AND key, should succeed. */ if(verifyCert(clHand, cspHand, &signedSubjCert, &signedRootCert, &rootPubKey, sigAlg, CSSM_OK, "Verify(subj by root cert and key)")) { errorCount++; /* continue */ } /* * Verify subject cert by extracted root pub key, should succeed. */ if(verifyCert(clHand, cspHand, &signedSubjCert, NULL, extractRootKey, sigAlg, CSSM_OK, "Verify(subj by extracted root key)")) { errorCount++; /* continue */ } /* * Verify subject cert by subject pub key, should fail. */ if(verifyCert(clHand, cspHand, &signedSubjCert, NULL, &subjPubKey, sigAlg, CSSMERR_CL_VERIFICATION_FAILURE, "Verify(subj by subj key)")) { errorCount++; /* continue */ } /* * Verify subject cert by subject cert, should fail. */ if(verifyCert(clHand, cspHand, &signedSubjCert, &signedSubjCert, NULL, CSSM_ALGID_NONE, // sigAlg not used here CSSMERR_CL_VERIFICATION_FAILURE, "Verify(subj by subj cert)")) { errorCount++; /* continue */ } /* * Verify erroneous subject cert by root pub key, should fail. */ badByte = genRand(1, signedSubjCert.Length - 1); signedSubjCert.Data[badByte] ^= 0x55; if(verifyCert(clHand, cspHand, &signedSubjCert, NULL, &rootPubKey, sigAlg, CSSMERR_CL_VERIFICATION_FAILURE, "Verify(bad subj by root key)")) { errorCount++; /* continue */ } /* free/delete certs and keys */ appFreeCssmData(&signedSubjCert, CSSM_FALSE); appFreeCssmData(&signedRootCert, CSSM_FALSE); cspFreeKey(cspHand, &rootPubKey); cspFreeKey(cspHand, &subjPubKey); /* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with * a bogus GUID. This may be a problem with the Apple CSP... * cspFreeKey(cspHand, extractRootKey); cspFreeKey(cspHand, extractSubjKey); * * do it this way instead...*/ CSSM_FREE(extractRootKey->KeyData.Data); CSSM_FREE(extractSubjKey->KeyData.Data); /* need to do this regardless...*/ CSSM_FREE(extractRootKey); CSSM_FREE(extractSubjKey); abort: if(cspHand != 0) { CSSM_ModuleDetach(cspHand); } if(errorCount) { printf("Signer/Subject test failed with %d errors\n", errorCount); } else { printf("Signer/Subject test succeeded\n"); } return 0; }
/* * SecCmsDigestContextFinishMultiple - finish the digests and put them * into an array of CSSM_DATAs (allocated on poolp) */ OSStatus SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef poolp, CSSM_DATA_PTR **digestsp) { CSSM_CC_HANDLE digobj; CSSM_DATA_PTR *digests, digest; int i; void *mark; OSStatus rv = SECFailure; /* no contents? do not update digests */ if (digestsp == NULL || !cmsdigcx->saw_contents) { for (i = 0; i < cmsdigcx->digcnt; i++) if (cmsdigcx->digobjs[i]) CSSM_DeleteContext(cmsdigcx->digobjs[i]); rv = SECSuccess; if (digestsp) *digestsp = NULL; goto cleanup; } mark = PORT_ArenaMark ((PLArenaPool *)poolp); /* allocate digest array & CSSM_DATAs on arena */ digests = (CSSM_DATA_PTR *)PORT_ArenaAlloc((PLArenaPool *)poolp, (cmsdigcx->digcnt+1) * sizeof(CSSM_DATA_PTR)); digest = (CSSM_DATA_PTR)PORT_ArenaZAlloc((PLArenaPool *)poolp, cmsdigcx->digcnt * sizeof(CSSM_DATA)); if (digests == NULL || digest == NULL) { goto loser; } for (i = 0; i < cmsdigcx->digcnt; i++, digest++) { digobj = cmsdigcx->digobjs[i]; CSSM_QUERY_SIZE_DATA dataSize; rv = CSSM_QuerySize(digobj, CSSM_FALSE, 1, &dataSize); if (rv != CSSM_OK) { goto loser; } int diglength = dataSize.SizeOutputBlock; if (digobj) { digest->Data = (unsigned char*)PORT_ArenaAlloc((PLArenaPool *)poolp, diglength); if (digest->Data == NULL) goto loser; digest->Length = diglength; rv = CSSM_DigestDataFinal(digobj, digest); if (rv != CSSM_OK) { goto loser; } CSSM_DeleteContext(digobj); } else { digest->Data = NULL; digest->Length = 0; } digests[i] = digest; } digests[i] = NULL; *digestsp = digests; rv = SECSuccess; loser: if (rv == SECSuccess) PORT_ArenaUnmark((PLArenaPool *)poolp, mark); else PORT_ArenaRelease((PLArenaPool *)poolp, mark); cleanup: if (cmsdigcx->digcnt > 0) { PORT_Free(cmsdigcx->digobjs); } PORT_Free(cmsdigcx); return rv; }
/* * Derive symmetric key. * Note in the X CSP, we never return an IV. */ CSSM_RETURN cuCspDeriveKey(CSSM_CSP_HANDLE cspHand, uint32 keyAlg, // CSSM_ALGID_RC5, etc. const char *keyLabel, unsigned keyLabelLen, uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc. uint32 keySizeInBits, CSSM_DATA_PTR password, // in PKCS-5 lingo CSSM_DATA_PTR salt, // ditto uint32 iterationCnt, // ditto CSSM_KEY_PTR key) { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand; uint32 keyAttr; CSSM_DATA dummyLabel; CSSM_PKCS5_PBKDF2_PARAMS pbeParams; CSSM_DATA pbeData; CSSM_ACCESS_CREDENTIALS creds; memset(key, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand, CSSM_ALGID_PKCS5_PBKDF2, keyAlg, keySizeInBits, &creds, NULL, // BaseKey iterationCnt, salt, NULL, // seed &ccHand); if(crtn) { cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn); return crtn; } keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE; dummyLabel.Length = keyLabelLen; dummyLabel.Data = (uint8 *)keyLabel; /* passing in password is pretty strange....*/ pbeParams.Passphrase = *password; pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1; pbeData.Data = (uint8 *)&pbeParams; pbeData.Length = sizeof(pbeParams); crtn = CSSM_DeriveKey(ccHand, &pbeData, keyUsage, keyAttr, &dummyLabel, NULL, // cred and acl key); if(crtn) { cuPrintError("CSSM_DeriveKey", crtn); return crtn; } crtn = CSSM_DeleteContext(ccHand); if(crtn) { cuPrintError("CSSM_DeleteContext", crtn); } return crtn; }
/* * 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; }
/* * Find private key by label, modify its Label attr to be the * hash of the associated public key. * Also optionally re-sets the key's PrintName attribute; used to reset * this attr from the random label we create when first unwrap it * to the friendly name we find later after parsing attributes. * Detection of a duplicate key when updating the key's attributes * results in a lookup of the original key and returning it in * foundKey. */ CSSM_RETURN p12SetPubKeyHash( CSSM_CSP_HANDLE cspHand, // where the key lives CSSM_DL_DB_HANDLE dlDbHand, // ditto CSSM_DATA &keyLabel, // for DB lookup CSSM_DATA_PTR newPrintName, // optional SecNssCoder &coder, // for mallocing newLabel CSSM_DATA &newLabel, // RETURNED with label as hash CSSM_KEY_PTR &foundKey) // RETURNED { CSSM_QUERY query; CSSM_SELECTION_PREDICATE predicate; CSSM_DB_UNIQUE_RECORD_PTR record = NULL; CSSM_RETURN crtn; CSSM_HANDLE resultHand = 0; CSSM_DATA keyData = {0, NULL}; CSSM_CC_HANDLE ccHand = 0; CSSM_KEY_PTR privKey = NULL; CSSM_DATA_PTR keyDigest = NULL; assert(cspHand != 0); query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; query.Conjunctive = CSSM_DB_NONE; query.NumSelectionPredicates = 1; predicate.DbOperator = CSSM_DB_EQUAL; predicate.Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; predicate.Attribute.Info.Label.AttributeName = (char*) P12_KEY_ATTR_LABEL_AND_HASH; predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; /* hope this cast is OK */ predicate.Attribute.Value = &keyLabel; query.SelectionPredicate = &predicate; query.QueryLimits.TimeLimit = 0; // FIXME - meaningful? query.QueryLimits.SizeLimit = 1; // FIXME - meaningful? query.QueryFlags = CSSM_QUERY_RETURN_DATA; /* build Record attribute with one or two attrs */ CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; CSSM_DB_ATTRIBUTE_DATA attr[2]; attr[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; attr[0].Info.Label.AttributeName = (char*) P12_KEY_ATTR_LABEL_AND_HASH; attr[0].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; if(newPrintName) { attr[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; attr[1].Info.Label.AttributeName = (char*) P12_KEY_ATTR_PRINT_NAME; attr[1].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; } recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; recordAttrs.NumberOfAttributes = newPrintName ? 2 : 1; recordAttrs.AttributeData = attr; crtn = CSSM_DL_DataGetFirst(dlDbHand, &query, &resultHand, &recordAttrs, &keyData, // theData &record); /* abort only on success */ if(crtn != CSSM_OK) { p12LogCssmError("CSSM_DL_DataGetFirst", crtn); p12ErrorLog("***p12SetPubKeyHash: can't find private key\n"); return crtn; } /* subsequent errors to errOut: */ if(keyData.Data == NULL) { p12ErrorLog("***p12SetPubKeyHash: private key lookup failure\n"); crtn = CSSMERR_CSSM_INTERNAL_ERROR; goto errOut; } privKey = (CSSM_KEY_PTR)keyData.Data; /* public key hash via passthrough - works on any key, any CSP/CSPDL.... */ /* * Warning! This relies on the current default ACL meaning "allow this * current app to access this private key" since we created the key. */ crtn = CSSM_CSP_CreatePassThroughContext(cspHand, privKey, &ccHand); if(crtn) { p12LogCssmError("CSSM_CSP_CreatePassThroughContext", crtn); goto errOut; } crtn = CSSM_CSP_PassThrough(ccHand, CSSM_APPLECSP_KEYDIGEST, NULL, (void **)&keyDigest); if(crtn) { p12LogCssmError("CSSM_CSP_PassThrough", crtn); goto errOut; } /* * Replace Label attr data with hash. * NOTE: the module which allocated this attribute data - a DL - * was loaded and attached by out client layer, not by us. Thus * we can't use the memory allocator functions *we* used when * attaching to the CSP - we have to use the ones * which the client registered with the DL. */ freeCssmMemory(dlDbHand.DLHandle, attr[0].Value->Data); freeCssmMemory(dlDbHand.DLHandle, attr[0].Value); if(newPrintName) { freeCssmMemory(dlDbHand.DLHandle, attr[1].Value->Data); freeCssmMemory(dlDbHand.DLHandle, attr[1].Value); } /* modify key attributes */ attr[0].Value = keyDigest; if(newPrintName) { attr[1].Value = newPrintName; } crtn = CSSM_DL_DataModify(dlDbHand, CSSM_DL_DB_RECORD_PRIVATE_KEY, record, &recordAttrs, NULL, // DataToBeModified CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); switch(crtn) { case CSSM_OK: /* give caller the key's new label */ coder.allocCopyItem(*keyDigest, newLabel); break; default: p12LogCssmError("CSSM_DL_DataModify", crtn); break; case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA: { /* * Special case: dup private key. The label we just tried to modify is * the public key hash so we can be confident that this really is a dup. * Delete it, look up the original, and return the original to caller. */ CSSM_RETURN drtn = CSSM_DL_DataDelete(dlDbHand, record); if(drtn) { p12LogCssmError("CSSM_DL_DataDelete on dup key", drtn); crtn = drtn; break; } /* Free items created in last search */ CSSM_DL_DataAbortQuery(dlDbHand, resultHand); resultHand = 0; CSSM_DL_FreeUniqueRecord(dlDbHand, record); record = NULL; /* lookup by label as public key hash this time */ predicate.Attribute.Value = keyDigest; drtn = CSSM_DL_DataGetFirst(dlDbHand, &query, &resultHand, NULL, // no attrs this time &keyData, &record); if(drtn) { p12LogCssmError("CSSM_DL_DataGetFirst on original key", crtn); crtn = drtn; break; } foundKey = (CSSM_KEY_PTR)keyData.Data; /* give caller the key's actual label */ coder.allocCopyItem(*keyDigest, newLabel); break; } } errOut: /* free resources */ if(resultHand) { CSSM_DL_DataAbortQuery(dlDbHand, resultHand); } if(record) { CSSM_DL_FreeUniqueRecord(dlDbHand, record); } if(ccHand) { CSSM_DeleteContext(ccHand); } if(privKey) { /* key created by the CSPDL */ CSSM_FreeKey(cspHand, NULL, privKey, CSSM_FALSE); freeCssmMemory(dlDbHand.DLHandle, privKey); } if(keyDigest) { /* mallocd by someone else's CSP */ freeCssmMemory(cspHand, keyDigest->Data); freeCssmMemory(cspHand, keyDigest); } return crtn; }
CFDataRef decodePrivateKeyHeader(SecKeychainRef keychain, const FVPrivateKeyHeader &inHeader) { // kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h SecKeychainAttribute attrs[] = { { 6 /* kSecKeyLabel */, inHeader.publicKeyHashSize, const_cast<uint8 *>(inHeader.publicKeyHash) } }; SecKeychainAttributeList attrList = { sizeof(attrs) / sizeof(SecKeychainAttribute), attrs }; CSSM_CSP_HANDLE cspHandle = 0; const CSSM_KEY *cssmKey = NULL; const CSSM_ACCESS_CREDENTIALS *accessCred = NULL; CSSM_CC_HANDLE cc = 0; SecKeychainSearchRef _searchRef; throwIfError(SecKeychainSearchCreateFromAttributes(keychain, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &_searchRef)); CFRef<SecKeychainSearchRef> searchRef(_searchRef); SecKeychainItemRef _item; if (SecKeychainSearchCopyNext(searchRef, &_item) != 0) { return NULL; // XXX possibly should throw here? } CFRef<SecKeyRef> keyItem(reinterpret_cast<SecKeyRef>(_item)); throwIfError(SecKeyGetCSPHandle(keyItem, &cspHandle)); throwIfError(SecKeyGetCSSMKey(keyItem, &cssmKey)); throwIfError(SecKeyGetCredentials(keyItem, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault, &accessCred)); throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle, cssmKey->KeyHeader.AlgorithmId, accessCred, cssmKey, CSSM_PADDING_PKCS1, &cc)); CFDataRef result; try { CssmMemoryFunctions memFuncs; throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle, &memFuncs)); CssmMemoryFunctionsAllocator allocator(memFuncs); const CssmData cipherBuf(const_cast<uint8 *>(inHeader.encryptedBlob), inHeader.encryptedBlobSize); CssmAutoData clearBuf(allocator); CssmAutoData remData(allocator); size_t bytesDecrypted; CSSM_RETURN crx = CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get()); secinfo("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx); throwIfError(crx); // throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get())); clearBuf.length(bytesDecrypted); // rawKey.copy(clearBuf.get()); result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)clearBuf.get().data(), clearBuf.get().length()); // result = parseKeyBlob(clearBuf.get()); } catch(...) { CSSM_DeleteContext(cc); throw; } throwIfError(CSSM_DeleteContext(cc)); return result; }
/* * Generate asymmetric key pair. Currently supported algorithms * are RSA, DSA, and FEE. */ CSSM_RETURN cdsaGenerateKeyPair( CSSM_CSP_HANDLE cspHandle, CSSM_ALGORITHMS keyAlg, // e.g., CSSM_ALGID_RSA uint32 keySizeInBits, CSSM_KEY_PTR publicKey, CSSM_KEY_PTR privateKey) { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHandle; CSSM_DATA dummyLabel = {8, (uint8 *)"tempKey"}; memset(publicKey, 0, sizeof(CSSM_KEY)); memset(privateKey, 0, sizeof(CSSM_KEY)); crtn = CSSM_CSP_CreateKeyGenContext(cspHandle, keyAlg, keySizeInBits, NULL, // Seed NULL, // Salt NULL, // StartDate NULL, // EndDate NULL, // Params &ccHandle); if(crtn) { return crtn; } /* post-context-create algorithm-specific stuff */ switch(keyAlg) { case CSSM_ALGID_DSA: /* * extra step - generate params - this just adds some * info to the context */ { CSSM_DATA dummy = {0, NULL}; crtn = CSSM_GenerateAlgorithmParams(ccHandle, keySizeInBits, &dummy); if(crtn) { return crtn; } free(dummy.Data); } break; default: /* RSA, FEE - nothing to do */ break; } /* * Public keys can encrypt and verify signature. * Private keys can decrypt and sign. */ crtn = CSSM_GenerateKeyPair(ccHandle, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &dummyLabel, publicKey, CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &dummyLabel, // same labels NULL, // CredAndAclEntry privateKey); CSSM_DeleteContext(ccHandle); return crtn; }
/* * Generate a Diffie-Hellman key pair. Algorithm parameters are * either specified by caller via inParams, or are generated here * and returned to caller in outParams. Exactly one of (inParams, * outParams) must be non-NULL. */ CSSM_RETURN cdsaDhGenerateKeyPair( CSSM_CSP_HANDLE cspHandle, CSSM_KEY_PTR publicKey, CSSM_KEY_PTR privateKey, uint32 keySizeInBits, const CSSM_DATA *inParams, // optional CSSM_DATA_PTR outParams) // optional, we malloc { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHandle; CSSM_DATA labelData = {8, (uint8 *)"tempKey"}; /* Caller must specify either inParams or outParams, not both */ if(inParams && outParams) { return CSSMERR_CSSM_INVALID_POINTER; } if(!inParams && !outParams) { return CSSMERR_CSSM_INVALID_POINTER; } memset(publicKey, 0, sizeof(CSSM_KEY)); memset(privateKey, 0, sizeof(CSSM_KEY)); crtn = CSSM_CSP_CreateKeyGenContext(cspHandle, CSSM_ALGID_DH, keySizeInBits, NULL, // Seed NULL, // Salt NULL, // StartDate NULL, // EndDate inParams, // Params, may be NULL &ccHandle); if(crtn) { return crtn; } if(outParams) { /* explicitly generate params and return them to caller */ outParams->Data = NULL; outParams->Length = 0; crtn = CSSM_GenerateAlgorithmParams(ccHandle, keySizeInBits, outParams); if(crtn) { CSSM_DeleteContext(ccHandle); return crtn; } } crtn = CSSM_GenerateKeyPair(ccHandle, CSSM_KEYUSE_DERIVE, // only legal use of a Diffie-Hellman key CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &labelData, publicKey, /* private key specification */ CSSM_KEYUSE_DERIVE, CSSM_KEYATTR_RETURN_REF, &labelData, // same labels NULL, // CredAndAclEntry privateKey); CSSM_DeleteContext(ccHandle); return crtn; }