static void serializeAndDeserialize(SecOTRSessionRef* thisOne)
{
    CFMutableDataRef serialized = CFDataCreateMutable(kCFAllocatorDefault, 0);

    SecOTRSAppendSerialization(*thisOne, serialized);
    CFReleaseNull(*thisOne);
    *thisOne = SecOTRSessionCreateFromData(kCFAllocatorDefault, serialized);

    CFReleaseSafe(serialized);
}
SOSCoderRef SOSCoderCreateFromData(CFDataRef exportedData, CFErrorRef *error) {
    
    SOSCoderRef p = calloc(1, sizeof(struct __OpaqueSOSCoder));
    
    const uint8_t *der = CFDataGetBytePtr(exportedData);
    const uint8_t *der_end = der + CFDataGetLength(exportedData);
    
    CFDataRef otr_data = NULL;

    ccder_tag tag;
    require(ccder_decode_tag(&tag, der, der_end),fail);

    switch (tag) {
        case CCDER_OCTET_STRING: // TODO: this code is safe to delete?
        {
            der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, der_end);
            p->waitingForDataPacket = false;
        }
        break;
        
        case CCDER_CONSTRUCTED_SEQUENCE:
        {
            const uint8_t *sequence_end = NULL;
            der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
            
            require_action_quiet(sequence_end == der_end, fail, SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Extra data in SOS coder"), NULL, error));
            
            der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, sequence_end);
            der = der_decode_bool(&p->waitingForDataPacket, der, sequence_end);
            if (der != sequence_end) { // optionally a pending response
                der = der_decode_data(kCFAllocatorDefault, 0, &p->pendingResponse, error, der, sequence_end);
            }
        }
        break;
        
        default:
            SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Unsupported SOS Coder DER"), NULL, error);
            goto fail;
    }

    require(der, fail);
    
    p->sessRef = SecOTRSessionCreateFromData(NULL, otr_data);
    require(p->sessRef, fail);

    CFReleaseSafe(otr_data);
    return p;
        
fail:
    SOSCoderDispose(p);
    CFReleaseSafe(otr_data);
    return NULL;
}
bool _SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error) {
    
    SecOTRSessionRef session = SecOTRSessionCreateFromData(kCFAllocatorDefault, sessionData);
    
    CFMutableDataRef negotiationResponse = CFDataCreateMutable(kCFAllocatorDefault, 0);
    
    if (inputPacket) {
        SecOTRSProcessPacket(session, inputPacket, negotiationResponse);
    } else {
        SecOTRSAppendStartPacket(session, negotiationResponse);
    }
    
    CFMutableDataRef outputSession = CFDataCreateMutable(kCFAllocatorDefault, 0);
    
    SecOTRSAppendSerialization(session, outputSession);
    *outputSessionData = outputSession;
    
    *outputPacket = negotiationResponse;
    
    *readyForMessages = SecOTRSGetIsReadyForMessages(session);
    
    return true;
}