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;
}
Example #5
0
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;
}