bool SOSAccountPublishCloudParameters(SOSAccountRef account, CFErrorRef* error){ bool success = false; CFIndex cloud_der_len = der_sizeof_cloud_parameters( account->user_public, account->user_key_parameters, error); CFMutableDataRef cloudParameters = CFDataCreateMutableWithScratch(kCFAllocatorDefault, cloud_der_len); if (der_encode_cloud_parameters(account->user_public, account->user_key_parameters, error, CFDataGetMutableBytePtr(cloudParameters), CFDataGetMutablePastEndPtr(cloudParameters)) != NULL) { CFErrorRef changeError = NULL; if (SOSTrasnportKeyParameterPublishCloudParameters(account->key_transport, cloudParameters, error)) { success = true; } else { SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL, CFSTR("update parameters key failed [%@]"), cloudParameters); } CFReleaseSafe(changeError); } else { SOSCreateError(kSOSErrorEncodeFailure, CFSTR("Encoding parameters failed"), NULL, error); } CFReleaseNull(cloudParameters); return success; }
static bool SOSOTRSAppendStartPacket(SecOTRSessionRef session, CFMutableDataRef appendPacket, CFErrorRef *error) { OSStatus otrStatus = SecOTRSAppendStartPacket(session, appendPacket); if (otrStatus != errSecSuccess) { SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("append start packet returned: %" PRIdOSStatus), otrStatus); } return otrStatus == errSecSuccess; }
static CFMutableDataRef sessSerialized(SOSCoderRef coder, CFErrorRef *error) { CFMutableDataRef otr_state = NULL; if(!coder || !coder->sessRef) { SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, 0, CFSTR("No session reference.")); return NULL; } if ((otr_state = CFDataCreateMutable(NULL, 0)) == NULL) { SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, NULL, error, 0, CFSTR("Mutable Data allocation failed.")); return NULL; } if (errSecSuccess != SecOTRSAppendSerialization(coder->sessRef, otr_state)) { SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, NULL, error, 0, CFSTR("Append Serialization failed.")); CFReleaseSafe(otr_state); return NULL; } return otr_state; }
SOSCoderStatus SOSCoderWrap(SOSCoderRef coder, CFDataRef message, CFMutableDataRef *codedMessage, CFStringRef clientId, CFErrorRef *error) { CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0); SOSCoderStatus result = kSOSCoderDataReturned; CFStringRef beginState = NULL; CFMutableDataRef encoded = NULL; OSStatus otrStatus = 0; require_action_quiet(coder->sessRef, errOut, CFStringAppend(action, CFSTR("*** using null coder ***")); result = nullCoder(message, codedMessage)); beginState = CFCopyDescription(coder->sessRef); require_action_quiet(SecOTRSGetIsReadyForMessages(coder->sessRef), errOut, CFStringAppend(action, CFSTR("not ready")); result = kSOSCoderNegotiating); require_action_quiet(!coder->waitingForDataPacket, errOut, CFStringAppend(action, CFSTR("waiting for peer to send data packet first")); result = kSOSCoderNegotiating); require_action_quiet(encoded = CFDataCreateMutable(kCFAllocatorDefault, 0), errOut, SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, NULL, error, NULL, CFSTR("%@ alloc failed"), clientId); result = kSOSCoderFailure); require_noerr_action_quiet(otrStatus = SecOTRSSignAndProtectMessage(coder->sessRef, message, encoded), errOut, SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ cannot protect message: %" PRIdOSStatus), clientId, otrStatus); CFReleaseNull(encoded); result = kSOSCoderFailure); *codedMessage = encoded; errOut: // Uber state log if (result == kSOSCoderFailure && error && *error) CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error); secnotice("coder", "%@ %@ %s %@ %@ returned %s", clientId, beginState, SecOTRPacketTypeString(encoded), action, coder->sessRef, SOSCoderString(result)); CFReleaseSafe(beginState); CFRelease(action); return result; }
bool SOSAccountDestroyCirclePeerInfoNamed(SOSAccountRef account, CFStringRef name, CFErrorRef* error) { if (CFDictionaryGetValue(account->circles, name) == NULL) { SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No circle named '%@'"), name); return false; } SOSFullPeerInfoRef circle_full_peer_info = (SOSFullPeerInfoRef) CFDictionaryGetValue(account->circle_identities, name); if (circle_full_peer_info) { SOSFullPeerInfoPurgePersistentKey(circle_full_peer_info, NULL); } CFDictionaryRemoveValue(account->circle_identities, name); return true; }
CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error) { CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true); CFDataRef result = NULL; OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result); CFReleaseNull(query); if (copyResult != noErr) { SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service); CFReleaseNull(result); return NULL; } if (!isData(result)) { SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service); CFReleaseNull(result); return NULL; } return result; }
SecKeyRef SOSUserKeygen(CFDataRef password, CFDataRef parameters, CFErrorRef *error) { size_t saltlen; const uint8_t *salt = NULL; size_t iterations = 0; size_t keysize = 0; const uint8_t *der = CFDataGetBytePtr(parameters); const uint8_t *der_end = der + CFDataGetLength(parameters); der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end); if (der == NULL) { SOSCreateErrorWithFormat(kSOSErrorDecodeFailure, NULL, error, NULL, CFSTR("Bad paramter encoding, got: %@"), parameters); return NULL; } if (keysize != 256) { SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, CFSTR("Key size not supported, requested %zd."), keysize); return NULL; } if (saltlen < 4) { SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, CFSTR("Salt length not supported, requested %zd."), saltlen); return NULL; } if (iterations < ITERATIONMIN) { SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, CFSTR("Too few iterations, params suggested %zd."), iterations); return NULL; } const uint8_t *password_bytes = CFDataGetBytePtr(password); size_t password_length = CFDataGetLength(password); const size_t maxbytes = 128; ccec_const_cp_t cp = ccec_get_cp(keysize); struct ccrng_pbkdf2_prng_state pbkdf2_prng; ccec_full_ctx_decl_cp(cp, tmpkey); secnotice("keygen", "Generating key for: iterations %zd, keysize %zd: %@", iterations, keysize, parameters); if (ccrng_pbkdf2_prng_init(&pbkdf2_prng, maxbytes, password_length, password_bytes, saltlen, salt, iterations)) { SOSCreateError(kSOSErrorProcessingFailure, CFSTR("prng init failed"), NULL, error); return NULL; } if (ccec_generate_key(cp, (struct ccrng_state *)&pbkdf2_prng, tmpkey)) { SOSCreateError(kSOSErrorProcessingFailure, CFSTR("Keygen failed"), NULL, error); return NULL; } return ccec2SecKey(tmpkey); }
SOSCoderStatus SOSCoderUnwrap(SOSCoderRef coder, CFDataRef codedMessage, CFMutableDataRef *message, CFStringRef clientId, CFErrorRef *error) { if(codedMessage == NULL) return kSOSCoderDataReturned; if(coder->sessRef == NULL) return nullCoder(codedMessage, message); CFMutableStringRef action = CFStringCreateMutable(kCFAllocatorDefault, 0); /* This should be the "normal" case. We just use OTR to unwrap the received message. */ SOSCoderStatus result = kSOSCoderFailure; CFStringRef beginState = CFCopyDescription(coder->sessRef); enum SecOTRSMessageKind kind = SecOTRSGetMessageKind(coder->sessRef, codedMessage); switch (kind) { case kOTRNegotiationPacket: { /* If we're in here we haven't completed negotiating a session. Use SecOTRSProcessPacket() to go through the negotiation steps and immediately send a reply back if necessary using the sendBlock. This assumes the sendBlock is still available. */ CFMutableDataRef response = CFDataCreateMutable(kCFAllocatorDefault, 0); OSStatus ppstatus = errSecSuccess; if (response) { switch (ppstatus = SecOTRSProcessPacket(coder->sessRef, codedMessage, response)) { case errSecSuccess: if (CFDataGetLength(response) > 1) { CFStringAppendFormat(action, NULL, CFSTR("Sending OTR Response %s"), SecOTRPacketTypeString(response)); CFRetainAssign(coder->pendingResponse, response); result = kSOSCoderNegotiating; if (SecOTRSGetIsReadyForMessages(coder->sessRef)) { CFStringAppend(action, CFSTR(" begin waiting for data packet")); coder->waitingForDataPacket = true; } } else if(!SecOTRSGetIsReadyForMessages(coder->sessRef)) { CFStringAppend(action, CFSTR("stuck?")); result = kSOSCoderNegotiating; } else { CFStringAppend(action, CFSTR("completed negotiation")); result = kSOSCoderNegotiationCompleted; coder->waitingForDataPacket = false; } break; case errSecDecode: CFStringAppend(action, CFSTR("resending dh")); result = SOSCoderResendDH(coder, error); break; default: SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ Cannot negotiate session (%ld)"), clientId, (long)ppstatus); result = kSOSCoderFailure; break; }; } else { SOSCreateErrorWithFormat(kSOSErrorAllocationFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ Cannot allocate CFData"), clientId); result = kSOSCoderFailure; } CFReleaseNull(response); break; } case kOTRDataPacket: if(!SecOTRSGetIsReadyForMessages(coder->sessRef)) { CFStringAppend(action, CFSTR("not ready, resending DH packet")); SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncFailed, 1); CFStringAppend(action, CFSTR("not ready for data; resending dh")); result = SOSCoderResendDH(coder, error); } else { if (coder->waitingForDataPacket) { CFStringAppend(action, CFSTR("got data packet we were waiting for ")); coder->waitingForDataPacket = false; } CFMutableDataRef exposed = CFDataCreateMutable(0, 0); OSStatus otrResult = SecOTRSVerifyAndExposeMessage(coder->sessRef, codedMessage, exposed); CFStringAppend(action, CFSTR("verify and expose message")); if (otrResult) { if (otrResult == errSecOTRTooOld) { CFStringAppend(action, CFSTR(" too old")); result = kSOSCoderStaleEvent; } else { SecError(otrResult, error, CFSTR("%@ Cannot expose message: %" PRIdOSStatus), clientId, otrResult); secerror("%@ Decode OTR Protected Packet: %@", clientId, error ? *error : NULL); result = kSOSCoderFailure; } } else { CFStringAppend(action, CFSTR("decoded OTR protected packet")); *message = exposed; exposed = NULL; result = kSOSCoderDataReturned; } CFReleaseNull(exposed); } break; default: secerror("%@ Unknown packet type: %@", clientId, codedMessage); SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Unknown packet type"), (error != NULL) ? *error : NULL, error); result = kSOSCoderFailure; break; }; // Uber state log if (result == kSOSCoderFailure && error && *error) CFStringAppendFormat(action, NULL, CFSTR(" %@"), *error); secnotice("coder", "%@ %@ %s %@ %@ returned %s", clientId, beginState, SecOTRPacketTypeString(codedMessage), action, coder->sessRef, SOSCoderString(result)); CFReleaseSafe(beginState); CFRelease(action); return result; }