// // Nonthrowing passphrase-based unlock. This returns false if unlock failed. // Note that this requires an explicitly given passphrase. // Caller must hold common lock. // bool KeychainDatabase::decode(const CssmData &passphrase) { assert(mBlob); common().setup(mBlob, passphrase); bool success = decode(); if (success) { if (common().isLoginKeychain() && (unlock_keybag(common(), passphrase.data(), (int)passphrase.length()) != 0)) { service_context_t context = common().session().get_current_service_context(); // check to see if it was locked with the master key if so change the secret to the passphrase if (!common().session().keybagGetState(session_keybag_check_master_key)) { CssmAutoData key(Allocator::standard(Allocator::sensitive)); key = common().masterKey()->keyData(); if (service_client_kb_unlock(&context, key.data(), (int)key.length()) == 0) { service_client_kb_change_secret(&context, key.data(), (int)key.length(), passphrase.data(), (int)passphrase.length()); } common().session().keybagSetState(session_keybag_check_master_key); } bool no_pin = false; if (service_client_kb_is_locked(&context, NULL, &no_pin) == 0) { if ((passphrase.length() > 0) && no_pin) { syslog(LOG_ERR, "Updating passphrase for your iCloud keychain"); service_client_kb_change_secret(&context, NULL, 0, passphrase.data(), (int)passphrase.length()); } else { syslog(LOG_ERR, "The passphrase for your login.keychain and your iCloud keychain are out of sync"); } } } } return success; }
void Policy::setValue(const CssmData &value) { StLock<Mutex>_(mMutex); mValue = value; mAuxValue.reset(); // Certain policy values may contain an embedded pointer. Ask me how I feel about that. if (mOid == CSSMOID_APPLE_TP_SSL || mOid == CSSMOID_APPLE_TP_EAP || mOid == CSSMOID_APPLE_TP_IP_SEC || mOid == CSSMOID_APPLE_TP_APPLEID_SHARING) { CSSM_APPLE_TP_SSL_OPTIONS *opts = (CSSM_APPLE_TP_SSL_OPTIONS *)value.data(); if (opts->Version == CSSM_APPLE_TP_SSL_OPTS_VERSION) { if (opts->ServerNameLen > 0) { // Copy auxiliary data, then update the embedded pointer to reference our copy mAuxValue.copy(const_cast<char*>(opts->ServerName), opts->ServerNameLen); mValue.get().interpretedAs<CSSM_APPLE_TP_SSL_OPTIONS>()->ServerName = reinterpret_cast<char*>(mAuxValue.data()); } else { // Clear the embedded pointer! mValue.get().interpretedAs<CSSM_APPLE_TP_SSL_OPTIONS>()->ServerName = reinterpret_cast<char*>(NULL); } } } else if (mOid == CSSMOID_APPLE_TP_SMIME || mOid == CSSMOID_APPLE_TP_ICHAT || mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING) { CSSM_APPLE_TP_SMIME_OPTIONS *opts = (CSSM_APPLE_TP_SMIME_OPTIONS *)value.data(); if (opts->Version == CSSM_APPLE_TP_SMIME_OPTS_VERSION) { if (opts->SenderEmailLen > 0) { // Copy auxiliary data, then update the embedded pointer to reference our copy mAuxValue.copy(const_cast<char*>(opts->SenderEmail), opts->SenderEmailLen); mValue.get().interpretedAs<CSSM_APPLE_TP_SMIME_OPTIONS>()->SenderEmail = reinterpret_cast<char*>(mAuxValue.data()); } else { // Clear the embedded pointer! mValue.get().interpretedAs<CSSM_APPLE_TP_SMIME_OPTIONS>()->SenderEmail = reinterpret_cast<char*>(NULL); } } } }
void KCEventNotifier::PostKeychainEvent(SecKeychainEvent whichEvent, const DLDbIdentifier &dlDbIdentifier, const PrimaryKey &primaryKey) { NameValueDictionary nvd; Endian<pid_t> thePid = getpid(); nvd.Insert (new NameValuePair (PID_KEY, CssmData (reinterpret_cast<void*>(&thePid), sizeof (pid_t)))); if (dlDbIdentifier) { NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier (dlDbIdentifier, nvd); } CssmData* pKey = primaryKey; if (primaryKey) { nvd.Insert (new NameValuePair (ITEM_KEY, *pKey)); } // flatten the dictionary CssmData data; nvd.Export (data); SecurityServer::ClientSession cs (Allocator::standard(), Allocator::standard()); cs.postNotification (SecurityServer::kNotificationDomainDatabase, whichEvent, data); secdebug("kcnotify", "KCEventNotifier::PostKeychainEvent posted event %u", (unsigned int) whichEvent); free (data.data ()); }
void CL_certCrlDecodeComponents( const CssmData &signedItem, // DER-encoded cert or CRL CssmOwnedData &tbsBlob, // still DER-encoded CssmOwnedData &algId, // ditto CssmOwnedData &rawSig) // raw bits (not an encoded AsnBits) { /* BER-decode into temp memory */ NSS_SignedCertOrCRL nssObj; SecNssCoder coder; PRErrorCode prtn; memset(&nssObj, 0, sizeof(nssObj)); prtn = coder.decode(signedItem.data(), signedItem.length(), kSecAsn1SignedCertOrCRLTemplate, &nssObj); if(prtn) { CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } /* tbsBlob and algId are raw ASN_ANY including tags, which we pass * back to caller intact */ tbsBlob.copy(nssObj.tbsBlob.Data, nssObj.tbsBlob.Length); algId.copy(nssObj.signatureAlgorithm.Data, nssObj.signatureAlgorithm.Length); /* signature is a bit string which we do in fact decode */ rawSig.copy(nssObj.signature.Data, (nssObj.signature.Length + 7) / 8); }
/* * Generate keygen parameters, stash them in a context attr array for later use * when actually generating the keys. */ void DSAKeyPairGenContext::generate( const Context &context, uint32 bitSize, CssmData ¶ms, uint32 &attrCount, Context::Attr * &attrs) { void *seed = NULL; unsigned seedLen = 0; /* optional seed from context */ CssmData *seedData = context.get<CssmData>(CSSM_ATTRIBUTE_SEED); if(seedData) { seed = seedData->data(); seedLen = (unsigned)seedData->length(); } /* generate the params, temp alloc from SecNssCoder */ NSS_DSAAlgParams algParams; SecNssCoder coder; dsaGenParams(bitSize, seed, seedLen, algParams, coder); /* * Here comes the fun part. * We "return" the DER encoding of these generated params in two ways: * 1. Copy out to app via the params argument, mallocing if Data ptr is NULL. * The app must free this. * 2. Cook up a 1-element Context::attr array containing one ALG_PARAM attr, * a CSSM_DATA_PTR containing the DER encoding. We have to save a ptr to * this attr array and free it, the CSSM_DATA it points to, and the DER * encoding *that* points to, in our destructor. * * First, DER encode. */ CssmAutoData aDerData(session()); DSAEncodeAlgParams(algParams, aDerData); /* copy/release that into a mallocd CSSM_DATA. */ CSSM_DATA_PTR derData = (CSSM_DATA_PTR)session().malloc(sizeof(CSSM_DATA)); *derData = aDerData.release(); /* stuff that into a one-element Attr array which we keep after returning */ freeGenAttrs(); mGenAttrs = (Context::Attr *)session().malloc(sizeof(Context::Attr)); mGenAttrs->AttributeType = CSSM_ATTRIBUTE_ALG_PARAMS; mGenAttrs->AttributeLength = sizeof(CSSM_DATA); mGenAttrs->Attribute.Data = derData; /* and "return" this stuff */ copyCssmData(CssmData::overlay(*derData), params, session()); attrCount = 1; attrs = mGenAttrs; }
/* one-shot constructor, decoding from DER-encoded data */ DecodedCert::DecodedCert( AppleX509CLSession &session, const CssmData &encodedCert) : DecodedItem(session) { memset(&mCert, 0, sizeof(mCert)); PRErrorCode prtn = mCoder.decode(encodedCert.data(), encodedCert.length(), kSecAsn1SignedCertTemplate, &mCert); if(prtn) { CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } mDecodedExtensions.decodeFromNss(mCert.tbs.extensions); mState = IS_DecodedAll; }
DbKey::DbKey(char type, const CssmData &key, bool perUser, uid_t user) : CssmAutoData(Allocator::standard()) { using namespace LowLevelMemoryUtilities; char header[20]; size_t headerLength; if (perUser) headerLength = 1 + sprintf(header, "%c%d", type, user); else headerLength = 1 + sprintf(header, "%cS", type); malloc(headerLength + key.length()); memcpy(this->data(), header, headerLength); memcpy(get().at(headerLength), key.data(), key.length()); }
/* decode TBSCert and its extensions */ void DecodedCert::decodeTbs( const CssmData &encodedTbs) { assert(mState == IS_Empty); memset(&mCert, 0, sizeof(mCert)); PRErrorCode prtn = mCoder.decode(encodedTbs.data(), encodedTbs.length(), kSecAsn1TBSCertificateTemplate, &mCert.tbs); if(prtn) { CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } mDecodedExtensions.decodeFromNss(mCert.tbs.extensions); mState = IS_DecodedTBS; }
// // Send a keychain-related notification event about this database // void DbCommon::notify(NotificationEvent event, const DLDbIdentifier &ident) { // form the data (encoded DLDbIdentifier) NameValueDictionary nvd; NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(ident, nvd); CssmData data; nvd.Export(data); // inject notification into Security event system Listener::notify(kNotificationDomainDatabase, event, data); // clean up free (data.data()); }
// // Send CDSA-layer notifications for this token. // These events are usually received by CDSA plugins working with securityd. // void Token::notify(NotificationEvent event) { NameValueDictionary nvd; CssmSubserviceUid ssuid(mGuid, NULL, h2n (mSubservice), h2n(CSSM_SERVICE_DL | CSSM_SERVICE_CSP)); nvd.Insert(new NameValuePair(SSUID_KEY, CssmData::wrap(ssuid))); CssmData data; nvd.Export(data); // inject notification into Security event system Listener::notify(kNotificationDomainCDSA, event, data); // clean up free (data.data()); }
static void setField_PublicKeyStruct ( DecodedItem &item, const CssmData &fieldValue) { DecodedCert &cert = dynamic_cast<DecodedCert &>(item); CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstKeyInfo = cert.mCert.tbs.subjectPublicKeyInfo; tbsSetCheck(dstKeyInfo.subjectPublicKey.Data, fieldValue, sizeof(CSSM_KEY), "PubKeyStruct"); CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data(); if((cssmKey->KeyData.Data == NULL) || (cssmKey->KeyData.Data == 0)) { CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); } CL_CSSMKeyToSubjPubKeyInfoNSS(*cssmKey, dstKeyInfo, cert.coder()); }
/* new in 10.6 */ CFDataRef SecCertificateCopyData(SecCertificateRef certificate) { CFDataRef data = NULL; OSStatus __secapiresult = errSecSuccess; try { CssmData output = Certificate::required(certificate)->data(); CFIndex length = (CFIndex)output.length(); const UInt8 *bytes = (const UInt8 *)output.data(); if (length && bytes) { data = CFDataCreate(NULL, bytes, length); } } catch (const MacOSError &err) { __secapiresult=err.osStatus(); } catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } catch (...) { __secapiresult=errSecInternalComponent; } return data; }
/* * Set the field specified by fieldId in the specified Cert. * Note no index - individual field routines either append (for extensions) * or if field already set ::throwMe(for all others) */ void DecodedCert::setCertField( const CssmOid &fieldId, // which field const CssmData &fieldValue) { switch(mState) { case IS_Empty: // first time thru mState = IS_Building; break; case IS_Building: // subsequent passes break; case IS_DecodedAll: case IS_DecodedTBS: clErrorLog("DecodedCert::setCertField: can't build on a decoded cert!"); CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); } if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); } const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); const CssmData &value = CssmData::overlay(fieldValue); fieldFuncs->setFcn(*this, value); }
void KeychainDatabase::makeUnlocked(const CssmData &passphrase) { if (isLocked()) { if (decode(passphrase)) return; else CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); } else if (!mValidData) { // need to decode to get our ACLs, passphrase available if (!decode()) CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); } if (common().isLoginKeychain()) { bool locked = false; service_context_t context = common().session().get_current_service_context(); if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) { unlock_keybag(common(), passphrase.data(), (int)passphrase.length()); } } assert(!isLocked()); assert(mValidData); }
void CryptKit::FEEBinaryKey::generateKeyBlob( Allocator &allocator, CssmData &blob, CSSM_KEYBLOB_FORMAT &format, AppleCSPSession &session, const CssmKey *paramKey, /* optional, unused here */ CSSM_KEYATTR_FLAGS &attrFlags) /* IN/OUT */ { unsigned char *keyBlob; unsigned len; feeReturn frtn = FR_Internal; bool freeTheKey = false; feePubKey keyToEncode = mFeeKey; assert(mFeeKey != NULL); if((format == CSSM_KEYBLOB_RAW_FORMAT_DIGEST) && (mKeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)) { /* key digest calculation; special case for private keys: cook * up the associated public key and encode that */ keyToEncode = feePubKeyAlloc(); if(keyToEncode == NULL) { CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); } frtn = feePubKeyInitPubKeyFromPriv(mFeeKey, keyToEncode); if(frtn) { feePubKeyFree(keyToEncode); throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv"); } freeTheKey = true; } bool badFormat = false; int isPrivate = feePubKeyIsPrivate(keyToEncode); switch(mKeyHeader.AlgorithmId) { case CSSM_ALGID_FEE: if(isPrivate) { /* FEE private key */ switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: format = CSSM_KEYBLOB_RAW_FORMAT_NONE; /* and drop thru */ case CSSM_KEYBLOB_RAW_FORMAT_NONE: frtn = feePubKeyCreateDERPrivBlob(keyToEncode, &keyBlob, &len); break; case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: frtn = feePubKeyCreatePrivBlob(keyToEncode, &keyBlob, &len); break; default: badFormat = true; break; } } else { /* FEE Public key */ switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: format = CSSM_KEYBLOB_RAW_FORMAT_NONE; /* and drop thru */ case CSSM_KEYBLOB_RAW_FORMAT_NONE: frtn = feePubKeyCreateDERPubBlob(keyToEncode, &keyBlob, &len); break; case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: frtn = feePubKeyCreatePubBlob(keyToEncode, &keyBlob, &len); break; default: badFormat = true; break; } } /* end of base ALGID_FEE */ break; case CSSM_ALGID_ECDSA: if(isPrivate) { /* ECDSA/ECDH private key */ switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: /* ECDSA private key: PKCS8 */ frtn = feePubKeyCreatePKCS8Blob(keyToEncode, &keyBlob, &len); break; case CSSM_KEYBLOB_RAW_FORMAT_NONE: /* set to default format, drop thru */ format = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: /* ECDSA private key, SEC1/OpenSSL format */ frtn = feePubKeyCreateOpenSSLBlob(keyToEncode, &keyBlob, &len); break; case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; /* and drop thru */ case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: /* raw private key bytes */ frtn = feeCreateECDSAPrivBlob(keyToEncode, &keyBlob, &len); break; default: badFormat = true; break; } } else { /* * ECDSA public key. * Note there is no OpenSSL case here, that format is only generated for * private keys. */ switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_NONE: /* set to default format, drop thru */ format = CSSM_KEYBLOB_RAW_FORMAT_X509; case CSSM_KEYBLOB_RAW_FORMAT_X509: /* ECDSA, public key, default: X509 */ frtn = feePubKeyCreateX509Blob(keyToEncode, &keyBlob, &len); break; case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; /* and drop thru */ case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: /* raw x|y string */ frtn = feeCreateECDSAPubBlob(keyToEncode, &keyBlob, &len); break; default: badFormat = true; break; } } /* end of case CSSM_ALGID_ECDSA */ break; default: /* not reached */ break; } if(badFormat) { CssmError::throwMe(isPrivate ? CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT : CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT); } if(frtn) { throwCryptKit(frtn, "feePubKeyCreate*Blob"); } setUpCssmData(blob, len, allocator); memmove(blob.data(), keyBlob, len); blob.length(len); ffree(keyBlob); if(freeTheKey) { /* free the temp pub key we created here */ feePubKeyFree(keyToEncode); } }
// this one is specified in, and called from, AppleKeyPairGenContext void CryptKit::FEEKeyPairGenContext::generate( const Context &context, BinaryKey &pubBinKey, BinaryKey &privBinKey, uint32 &keyBits) { /* * These casts throw exceptions if the keys are of the * wrong classes, which would be a major bogon, since we created * the keys in the above generate() function. */ FEEBinaryKey &fPubBinKey = dynamic_cast<FEEBinaryKey &>(pubBinKey); FEEBinaryKey &fPrivBinKey = dynamic_cast<FEEBinaryKey &>(privBinKey); /* * Two parameters from context. Key size in bits is required; * seed is optional. If not present, we cook up random private data. */ keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH, CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH); CssmCryptoData *cseed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED); CssmData *seed; bool haveSeed; CssmAutoData aSeed(session()); // malloc on demand if(cseed) { /* caller specified seed */ haveSeed = true; seed = &cseed->param(); } else { /* generate random seed */ haveSeed = false; unsigned keyBytes = ((keyBits + 7) / 8) + 1; aSeed.malloc(keyBytes); session().getRandomBytes(keyBytes, aSeed); seed = &aSeed.get(); } CSSM_ALGORITHMS algId = context.algorithm(); /* Curve and prime types - optional */ feePrimeType primeType = FPT_Default; uint32 uPrimeType = context.getInt(CSSM_ATTRIBUTE_FEE_PRIME_TYPE); switch(uPrimeType) { case CSSM_FEE_PRIME_TYPE_DEFAULT: break; case CSSM_FEE_PRIME_TYPE_MERSENNE: primeType = FPT_Mersenne; break; case CSSM_FEE_PRIME_TYPE_FEE: primeType = FPT_FEE; break; case CSSM_FEE_PRIME_TYPE_GENERAL: primeType = FPT_General; break; default: /* FIXME - maybe we should be more specific */ CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS); } feeCurveType curveType = FCT_Default; switch(algId) { case CSSM_ALGID_ECDSA: /* no options */ curveType = FCT_ANSI; break; default: { uint32 uCurveType = context.getInt(CSSM_ATTRIBUTE_FEE_CURVE_TYPE); switch(uCurveType) { case CSSM_FEE_CURVE_TYPE_DEFAULT: break; case CSSM_FEE_CURVE_TYPE_MONTGOMERY: curveType = FCT_Montgomery; break; case CSSM_FEE_CURVE_TYPE_WEIERSTRASS: curveType = FCT_Weierstrass; break; case CSSM_FEE_CURVE_TYPE_ANSI_X9_62: curveType = FCT_ANSI; break; default: /* FIXME - maybe we should be more specific */ CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS); } break; } } feeReturn frtn = feePubKeyInitFromPrivDataKeyBits( fPrivBinKey.feeKey(), (unsigned char *)seed->data(), (unsigned int)seed->length(), keyBits, primeType, curveType, /* * our random seed: trust it * caller's seed: hash it */ haveSeed ? 1 : 0); if(frtn) { throwCryptKit(frtn, "feePubKeyInitFromPrivDataKeyBits"); } frtn = feePubKeyInitPubKeyFromPriv(fPrivBinKey.feeKey(), fPubBinKey.feeKey()); if(frtn) { throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv"); } }
void MacContext::update(const CssmData &data) { CCHmacUpdate(&hmacCtx, data.data(), data.length()); }
void Session::resetKeyStorePassphrase(const CssmData &passphrase) { service_context_t context = get_current_service_context(); service_client_kb_reset(&context, passphrase.data(), (int)passphrase.length()); }
// update for input-only block/stream algorithms void BSafe::BSafeContext::update(const CssmData &data) { opStarted = true; check(inUpdate(bsAlgorithm, POINTER(data.data()), data.length(), bsSurrender)); }