SOSCoderRef SOSCoderCreate(SOSPeerInfoRef peerInfo, SOSFullPeerInfoRef myPeerInfo, CFErrorRef *error) { CFAllocatorRef allocator = CFGetAllocator(peerInfo); SOSCoderRef coder = calloc(1, sizeof(struct __OpaqueSOSCoder)); CFErrorRef localError = NULL; SecOTRFullIdentityRef myRef = NULL; SecOTRPublicIdentityRef peerRef = NULL; SecKeyRef privateKey = NULL; SecKeyRef publicKey = NULL; if (myPeerInfo && peerInfo) { privateKey = SOSFullPeerInfoCopyDeviceKey(myPeerInfo, &localError); require_quiet(privateKey, errOut); myRef = SecOTRFullIdentityCreateFromSecKeyRef(allocator, privateKey, &localError); require_quiet(myRef, errOut); CFReleaseNull(privateKey); publicKey = SOSPeerInfoCopyPubKey(peerInfo); peerRef = SecOTRPublicIdentityCreateFromSecKeyRef(allocator, publicKey, &localError); require_quiet(peerRef, errOut); coder->sessRef = SecOTRSessionCreateFromID(allocator, myRef, peerRef); require(coder->sessRef, errOut); coder->waitingForDataPacket = false; coder->pendingResponse = NULL; CFReleaseNull(publicKey); CFReleaseNull(privateKey); CFReleaseNull(myRef); CFReleaseNull(peerRef); } else { secnotice("coder", "NULL Coder requested, no transport security"); } SOSCoderStart(coder, NULL); return coder; errOut: secerror("Coder create failed: %@\n", localError ? localError : (CFTypeRef)CFSTR("No local error in SOSCoderCreate")); secerror("Coder create failed: %@\n", error ? *error : (CFTypeRef)CFSTR("WTF NULL?")); CFReleaseNull(myRef); CFReleaseNull(peerRef); CFReleaseNull(publicKey); CFReleaseNull(privateKey); free(coder); return NULL; }
// Convert from securityd error codes to OSStatus for legacy API. OSStatus SecErrorGetOSStatus(CFErrorRef error) { OSStatus status; if (error == NULL) { status = errSecSuccess; } else { CFStringRef domain = CFErrorGetDomain(error); if (domain == NULL) { secerror("No error domain for error: %@", error); status = errSecInternal; } else if (CFEqual(kSecErrorDomain, domain)) { status = (OSStatus)CFErrorGetCode(error); } else if (CFEqual(kSecDbErrorDomain, domain)) { status = osstatus_for_s3e((int)CFErrorGetCode(error)); } else if (CFEqual(kSecErrnoDomain, domain)) { status = (OSStatus)CFErrorGetCode(error); } else if (CFEqual(kSecKernDomain, domain)) { status = osstatus_for_kern_return(CFErrorGetCode(error)); } else if (CFEqual(sSecXPCErrorDomain, domain)) { status = osstatus_for_xpc_error(CFErrorGetCode(error)); } else if (CFEqual(sSecDERErrorDomain, domain)) { status = osstatus_for_der_error(CFErrorGetCode(error)); } else { secnotice("securityd", "unknown error domain: %@ for error: %@", domain, error); status = errSecInternal; } } return status; }
SharedMemoryListener::SharedMemoryListener(const char* segmentName, SegmentOffsetType segmentSize, uid_t uid, gid_t gid) : Listener (kNotificationDomainAll, kNotificationAllEvents), SharedMemoryServer (segmentName, segmentSize, uid, gid), mActive (false) { if (segmentName == NULL) { secerror("Attempted to start securityd with a NULL segmentName"); abort(); } }
bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) { SOSEnginePeerMessageSentBlock sent = NULL; CFDataRef message_to_send = NULL; bool ok = false; SOSPeerRef peer = SOSPeerCreateWithEngine(SOSTransportMessageGetEngine(transport), peer_id); CFDataRef coderData = SOSEngineGetCoderData(SOSTransportMessageGetEngine(transport), peer_id); require(coderData, fail); SOSCoderRef coder = SOSCoderCreateFromData(coderData, error); require(coder, fail); SOSPeerSetCoder(peer, coder); ok = SOSPeerCoderSendMessageIfNeeded(peer, &message_to_send, circle_id, peer_id, &sent, error); coder = SOSPeerGetCoder(peer); if (message_to_send) { CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peer_id, message_to_send, NULL); CFDictionaryRef circle_peers = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, circle_id, peer_dict, NULL); ok = ok && SOSTransportMessageSendMessages(transport, circle_peers, error); SOSPeerCoderConsume(&sent, ok); CFReleaseSafe(peer_dict); CFReleaseSafe(circle_peers); } Block_release(sent); CFReleaseSafe(message_to_send); coderData = SOSCoderCopyDER(coder, error); if(!SOSEngineSetCoderData(SOSTransportMessageGetEngine(transport), peer_id, coderData, error)){ secerror("SOSTransportMessageSendMessageIfNeeded, Could not save peer state"); } CFReleaseNull(coderData); if (coder) SOSCoderDispose(coder); fail: CFReleaseNull(peer); return ok; }
static const char * get_host_uuid() { static uuid_string_t hostuuid = {}; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ struct timespec timeout = {30, 0}; uuid_t uuid = {}; if (gethostuuid(uuid, &timeout) == 0) { uuid_unparse(uuid, hostuuid); } else { secerror("failed to get host uuid"); } });
static bool postIDTimestamp(dispatch_queue_t theq, dispatch_group_t dgroup) { bool result = false; CFStringRef macaddr = myMacAddress(); CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); const char *nowstr = cfabsoluteTimeToStringLocal(now); CFStringRef cfidstr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@: %@ %s"), kTestKeyIDTimestamp, macaddr ,nowstr); secerror("Setting %@ key: %@", kTestKeyIDTimestamp, cfidstr); result = testPostGet(kTestKeyIDTimestamp, cfidstr, theq, dgroup); if (nowstr) free((void *)nowstr); CFReleaseSafe(cfidstr); return result; }
static void handle_server_response(CFReadStreamRef stream, CFStreamEventType type, void *info) { asynchttp_t *http = (asynchttp_t *)info; if (!http->stream) { secerror("Avoiding crash due to CFReadStream invoking us after we called CFReadStreamSetDispatchQueue(stream, NULL) on a different block on our serial queue"); return; } switch (type) { case kCFStreamEventHasBytesAvailable: { UInt8 buffer[POST_BUFSIZE]; CFIndex length; do { #if 1 length = CFReadStreamRead(stream, buffer, sizeof(buffer)); #else const UInt8 *buffer = CFReadStreamGetBuffer(stream, -1, &length); #endif secdebug("http", "stream: %@ kCFStreamEventHasBytesAvailable read: %lu bytes", stream, length); if (length < 0) { /* Negative length == error */ asynchttp_complete(http); break; } else if (length > 0) { //CFHTTPMessageAppendBytes(http->response, buffer, length); CFDataAppendBytes(http->data, buffer, length); } else { /* Read 0 bytes, are we are done or do we wait for kCFStreamEventEndEncountered? */ asynchttp_complete(http); break; } } while (CFReadStreamHasBytesAvailable(stream)); break; } case kCFStreamEventErrorOccurred: { CFStreamError error = CFReadStreamGetError(stream); secdebug("http", "stream: %@ kCFStreamEventErrorOccurred domain: %ld error: %ld", stream, error.domain, (long) error.error); if (error.domain == kCFStreamErrorDomainPOSIX) { ocspdErrorLog("CFReadStream posix: %s", strerror(error.error)); } else if (error.domain == kCFStreamErrorDomainMacOSStatus) { ocspdErrorLog("CFReadStream osstatus: %"PRIstatus, error.error); } else { ocspdErrorLog("CFReadStream domain: %ld error: %"PRIstatus, error.domain, error.error); } asynchttp_complete(http); break; } case kCFStreamEventEndEncountered: { http->response = (CFHTTPMessageRef)CFReadStreamCopyProperty( stream, kCFStreamPropertyHTTPResponseHeader); secdebug("http", "stream: %@ kCFStreamEventEndEncountered hdr: %@", stream, http->response); CFHTTPMessageSetBody(http->response, http->data); asynchttp_complete(http); break; } default: ocspdErrorLog("handle_server_response unexpected event type: %lu", type); break; } }
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; }