Esempio n. 1
0
static inline bool authValid(Dict* message, uint8_t* buffer, uint32_t length, struct Admin* admin)
{
    String* cookieStr = Dict_getString(message, String_CONST("cookie"));
    uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0;
    if (!cookie) {
        int64_t* cookieInt = Dict_getInt(message, String_CONST("cookie"));
        cookie = (cookieInt) ? *cookieInt : 0;
    }
    uint64_t nowSecs = Time_currentTimeSeconds(admin->eventBase);
    String* submittedHash = Dict_getString(message, String_CONST("hash"));
    if (cookie >  nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) {
        return false;
    }

    uint8_t* hashPtr = (uint8_t*) strstr((char*) buffer, submittedHash->bytes);

    if (!hashPtr || !admin->password) {
        return false;
    }

    uint8_t passAndCookie[64];
    snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie);
    uint8_t hash[32];
    crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie));
    Hex_encode(hashPtr, 64, hash, 32);

    crypto_hash_sha256(hash, buffer, length);
    Hex_encode(hashPtr, 64, hash, 32);
    return memcmp(hashPtr, submittedHash->bytes, 64) == 0;
}
Esempio n. 2
0
struct CryptoAuth_Session* CryptoAuth_newSession(struct CryptoAuth* ca,
                                                 struct Allocator* alloc,
                                                 const uint8_t herPublicKey[32],
                                                 const uint8_t herIp6[16],
                                                 const bool requireAuth,
                                                 char* displayName)
{
    struct CryptoAuth_pvt* context = Identity_check((struct CryptoAuth_pvt*) ca);
    struct CryptoAuth_Session_pvt* session =
        Allocator_calloc(alloc, sizeof(struct CryptoAuth_Session_pvt), 1);
    Identity_set(session);
    session->context = context;
    session->requireAuth = requireAuth;
    session->pub.displayName = String_new(displayName, alloc);
    session->timeOfLastPacket = Time_currentTimeSeconds(context->eventBase);
    session->alloc = alloc;

    if (herPublicKey != NULL) {
        Bits_memcpyConst(session->pub.herPublicKey, herPublicKey, 32);
        uint8_t calculatedIp6[16];
        AddressCalc_addressForPublicKey(calculatedIp6, herPublicKey);
        Bits_memcpyConst(session->pub.herIp6, calculatedIp6, 16);
        if (herIp6 != NULL) {
            Assert_true(!Bits_memcmp(calculatedIp6, herIp6, 16));
        }
    } else if (herIp6) {
        Bits_memcpyConst(session->pub.herIp6, herIp6, 16);
    }

    return &session->pub;
}
Esempio n. 3
0
static void handleRequestFromChild(struct Admin* admin,
                                   uint8_t buffer[MAX_API_REQUEST_SIZE],
                                   size_t amount,
                                   struct Allocator* allocator)
{
    String* txid = NULL;
    int skip = 0;

    if (!memcmp(buffer, "0123", 4)) {
        // out of band txid
        txid = &(String) { .len = 4, .bytes = (char*) buffer + 4 };
        skip = 8;
    }

    struct Reader* reader = ArrayReader_new(buffer + skip, amount - skip, allocator);
    Dict message;
    if (List_getStandardBencSerializer()->parseDictionary(reader, allocator, &message)) {
        return;
    }

    String* query = Dict_getString(&message, CJDHTConstants_QUERY);
    if (!query) {
        return;
    }

    // If they're asking for a cookie then lets give them one.
    String* cookie = BSTR("cookie");
    if (String_equals(query, cookie)) {
        Dict* d = Dict_new(allocator);
        char bytes[32];
        snprintf(bytes, 32, "%u", (uint32_t) Time_currentTimeSeconds(admin->eventBase));
        String* theCookie = &(String) { .len = strlen(bytes), .bytes = bytes };
        Dict_putString(d, cookie, theCookie, allocator);
        Admin_sendMessage(d, txid, admin);
        return;
    }

    // If this is a permitted query, make sure the cookie is right.
    String* auth = BSTR("auth");
    bool authed = false;
    if (String_equals(query, auth)) {
        if (!authValid(&message, buffer + skip, reader->bytesRead(reader), admin)) {
            Dict* d = Dict_new(allocator);
            Dict_putString(d, BSTR("error"), BSTR("Auth failed."), allocator);
            Admin_sendMessage(d, txid, admin);
            return;
        }
        query = Dict_getString(&message, BSTR("aq"));
        authed = true;
    }

    for (int i = 0; i < admin->functionCount; i++) {
        if (String_equals(query, admin->functions[i].name)
            && (authed || !admin->functions[i].needsAuth))
        {
            admin->functions[i].call(&message, admin->functions[i].context, txid);
        }
    }
    return;
}
Esempio n. 4
0
/** Call the external interface and tell it that a message has been received. */
static inline uint8_t callReceivedMessage(struct CryptoAuth_Wrapper* wrapper,
                                          struct Message* message)
{
    wrapper->timeOfLastPacket = Time_currentTimeSeconds(wrapper->context->eventBase);

    uint8_t ret = 0;
    if (wrapper->externalInterface.receiveMessage != NULL) {
        ret = wrapper->externalInterface.receiveMessage(message, &wrapper->externalInterface);
    }

    return ret;
}
Esempio n. 5
0
static void cleanup(void* vsm)
{
    struct SessionManager* sm = (struct SessionManager*) vsm;
    uint64_t nowSecs = Time_currentTimeSeconds(sm->eventBase);
    for (uint32_t i = 0; i < sm->ifaceMap.count; i++) {
        if (sm->ifaceMap.values[i].lastMessageTime < (nowSecs - SESSION_TIMEOUT_SECONDS)) {
            struct Allocator* ifAllocator = sm->ifaceMap.values[i].iface.allocator;
            ifAllocator->free(ifAllocator);
            Map_OfSessionsByIp6_remove(i, &sm->ifaceMap);
            i--;
        }
    }
}
Esempio n. 6
0
/** Call the external interface and tell it that a message has been received. */
static inline uint8_t callReceivedMessage(struct Wrapper* wrapper, struct Message* message)
{
    uint8_t ret = 0;
    if (wrapper->externalInterface.receiveMessage != NULL) {
        ret = wrapper->externalInterface.receiveMessage(message, &wrapper->externalInterface);
    }

    // If the message is authenticated OR if the packet is considered valid by the next level,
    // then don't allow the connection to timeout.
    if (!ret || wrapper->authenticatePackets) {
        wrapper->timeOfLastPacket = Time_currentTimeSeconds(wrapper->context->eventBase);
    }

    return ret;
}
Esempio n. 7
0
static uint8_t sendMessage(struct Message* message, struct Interface* interface)
{
    struct CryptoAuth_Wrapper* wrapper =
        Identity_cast((struct CryptoAuth_Wrapper*) interface->senderContext);

    // If there has been no incoming traffic for a while, reset the connection to state 0.
    // This will prevent "connection in bad state" situations from lasting forever.
    uint64_t nowSecs = Time_currentTimeSeconds(wrapper->context->eventBase);

    if (nowSecs - wrapper->timeOfLastPacket > wrapper->context->pub.resetAfterInactivitySeconds) {
        Log_debug(wrapper->context->logger, "No traffic in [%d] seconds, resetting connection.",
                  (int) (nowSecs - wrapper->timeOfLastPacket));

        wrapper->timeOfLastPacket = nowSecs;
        CryptoAuth_reset(interface);
        return encryptHandshake(message, wrapper);
    }

    #ifdef Log_DEBUG
        Assert_true(!((uintptr_t)message->bytes % 4) || !"alignment fault");
    #endif

    // nextNonce 0: sending hello, we are initiating connection.
    // nextNonce 1: sending another hello, nothing received yet.
    // nextNonce 2: sending key, hello received.
    // nextNonce 3: sending key again, no data packet recieved yet.
    // nextNonce >3: handshake complete
    //
    // if it's a blind handshake, every message will be empty and nextNonce will remain
    // zero until the first message is received back.
    if (wrapper->nextNonce < 5) {
        if (wrapper->nextNonce < 4) {
            return encryptHandshake(message, wrapper);
        } else {
            Log_debug(wrapper->context->logger,
                       "@%p Doing final step to send message. nonce=4\n", (void*) wrapper);
            uint8_t secret[32];
            getSharedSecret(secret,
                            wrapper->secret,
                            wrapper->tempKey,
                            NULL,
                            wrapper->context->logger);
            Bits_memcpyConst(wrapper->secret, secret, 32);
        }
    }

    return encryptMessage(message, wrapper);
}
Esempio n. 8
0
static void resetIfTimeout(struct CryptoAuth_Session_pvt* session)
{
    if (session->nextNonce == 1) {
        // Lets not reset the session, we just sent one or more hello packets and
        // have not received a response, if they respond after we reset then we'll
        // be in a tough state.
        return;
    }

    uint64_t nowSecs = Time_currentTimeSeconds(session->context->eventBase);
    if (nowSecs - session->timeOfLastPacket > session->context->pub.resetAfterInactivitySeconds) {
        cryptoAuthDebug(session, "No traffic in [%d] seconds, resetting connection.",
                  (int) (nowSecs - session->timeOfLastPacket));

        session->timeOfLastPacket = nowSecs;
        reset(session);
    }
}
Esempio n. 9
0
        cleanup(sm);

        struct Allocator* ifAllocator = Allocator_child(sm->allocator);
        struct Interface* outsideIf =
            ifAllocator->clone(sizeof(struct Interface), ifAllocator, &(struct Interface) {
                .sendMessage = sm->encryptedOutgoing,
                .senderContext = sm->interfaceContext,
                .allocator = ifAllocator
            });
        struct Interface* insideIf =
            CryptoAuth_wrapInterface(outsideIf, cryptoKey, false, true, sm->cryptoAuth);
        insideIf->receiveMessage = sm->decryptedIncoming;
        insideIf->receiverContext = sm->interfaceContext;

        struct SessionManager_Session s = {
            .lastMessageTime = Time_currentTimeSeconds(sm->eventBase),

            // Create a trick interface which pretends to be on both sides of the crypto.
            .iface = {
                .sendMessage = insideIf->sendMessage,
                .senderContext = insideIf->senderContext,
                .receiveMessage = outsideIf->receiveMessage,
                .receiverContext = outsideIf->receiverContext,
                .allocator = ifAllocator
            }
        };

        int index = Map_OfSessionsByIp6_put((struct Ip6*)lookupKey, &s, &sm->ifaceMap);
        struct SessionManager_Session* sp = &sm->ifaceMap.values[index];
        sp->receiveHandle_be = Endian_hostToBigEndian32(sm->ifaceMap.handles[index]);
        Bits_memcpyConst(sp->ip6, lookupKey, 16);
Esempio n. 10
0
                                           const bool requireAuth,
                                           char* name,
                                           struct CryptoAuth* ca)
{
    struct CryptoAuth_pvt* context = Identity_check((struct CryptoAuth_pvt*) ca);
    struct CryptoAuth_Wrapper* wrapper = Allocator_clone(toWrap->allocator,
        (&(struct CryptoAuth_Wrapper) {
            .user = NULL,
            .nextNonce = 0,
            .context = context,
            .wrappedInterface = toWrap,
            .requireAuth = requireAuth,
            .name = name
        }));

    wrapper->timeOfLastPacket = Time_currentTimeSeconds(context->eventBase);
    Identity_set(wrapper);
    toWrap->receiverContext = wrapper;
    toWrap->receiveMessage = receiveMessage;

    struct Interface iface = {
        .senderContext = wrapper,
        .sendMessage = sendMessage,
        .allocator = toWrap->allocator
    };
    Bits_memcpyConst(&wrapper->externalInterface, &iface, sizeof(struct Interface));

    if (herPublicKey != NULL) {
        Bits_memcpyConst(wrapper->herPerminentPubKey, herPublicKey, 32);
        uint8_t calculatedIp6[16];
        AddressCalc_addressForPublicKey(calculatedIp6, herPublicKey);
Esempio n. 11
0
/** Call the external interface and tell it that a message has been received. */
static inline void updateTime(struct CryptoAuth_Session_pvt* session, struct Message* message)
{
    session->timeOfLastPacket = Time_currentTimeSeconds(session->context->eventBase);
}
Esempio n. 12
0
static void handleRequestFromChild(struct Admin* admin,
                                   union Admin_TxidPrefix* txid_prefix,
                                   Dict* message,
                                   uint8_t* buffer,
                                   size_t amount,
                                   struct Allocator* allocator)
{
    String* query = Dict_getString(message, CJDHTConstants_QUERY);
    if (!query) {
        Log_info(admin->logger,
                 "Got a non-query from admin interface on channel [%u].",
                 admin->messageHeader.channelNum);
        adminChannelClose(admin, admin->messageHeader.channelNum);
        return;
    }

    // txid becomes the user supplied txid combined with the inter-process txid.
    String* userTxid = Dict_getString(message, TXID);
    uint32_t txidlen = ((userTxid) ? userTxid->len : 0) + Admin_TxidPrefix_SIZE;
    String* txid = String_newBinary(NULL, txidlen, allocator);
    Bits_memcpyConst(txid->bytes, txid_prefix->raw, Admin_TxidPrefix_SIZE);
    if (userTxid) {
        Bits_memcpy(txid->bytes + Admin_TxidPrefix_SIZE, userTxid->bytes, userTxid->len);
    }

    // If they're asking for a cookie then lets give them one.
    String* cookie = String_CONST("cookie");
    if (String_equals(query, cookie)) {
        Dict* d = Dict_new(allocator);
        char bytes[32];
        snprintf(bytes, 32, "%u", (uint32_t) Time_currentTimeSeconds(admin->eventBase));
        String* theCookie = &(String) { .len = strlen(bytes), .bytes = bytes };
        Dict_putString(d, cookie, theCookie, allocator);
        Admin_sendMessage(d, txid, admin);
        return;
    }

    // If this is a permitted query, make sure the cookie is right.
    String* auth = String_CONST("auth");
    bool authed = false;
    if (String_equals(query, auth)) {
        if (!authValid(message, buffer, amount, admin)) {
            Dict* d = Dict_new(allocator);
            Dict_putString(d, String_CONST("error"), String_CONST("Auth failed."), allocator);
            Admin_sendMessage(d, txid, admin);
            return;
        }
        query = Dict_getString(message, String_CONST("aq"));
        authed = true;
    }

    Dict* args = Dict_getDict(message, String_CONST("args"));
    bool noFunctionsCalled = true;
    for (int i = 0; i < admin->functionCount; i++) {
        if (String_equals(query, admin->functions[i].name)
            && (authed || !admin->functions[i].needsAuth))
        {
            if (checkArgs(args, &admin->functions[i], txid, admin)) {
                admin->functions[i].call(args, admin->functions[i].context, txid);
            }
            noFunctionsCalled = false;
        }
    }

    if (noFunctionsCalled) {
        Dict* d = Dict_new(allocator);
        Dict_putString(d,
                       String_CONST("error"),
                       String_CONST("No functions matched your request."),
                       allocator);
        Dict* functions = Dict_new(allocator);
        for (int i = 0; i < admin->functionCount; i++) {
            Dict_putDict(functions, admin->functions[i].name, admin->functions[i].args, allocator);
        }
        if (functions) {
            Dict_putDict(d, String_CONST("availableFunctions"), functions, allocator);
        }
        Admin_sendMessage(d, txid, admin);
        return;
    }

    return;
}
Esempio n. 13
0
/**
 * send a message
 */
static void adminChannelSendData(struct Admin* admin,
                                 uint32_t channelNum,
                                 const void *data,
                                 uint32_t length)
{
    /* if this changes, we need to fragment the messages
    * into MAX_MESSAGE_SIZE chunks
    */
    Assert_compileTime(MAX_API_REQUEST_SIZE == MAX_MESSAGE_SIZE);

    Assert_true(length <= MAX_MESSAGE_SIZE);

    struct Admin_MessageHeader header = {
        .magic = admin->pipeMagic,
        .length = length,
        .channelNum = channelNum
    };
    const uint8_t* buf = (const uint8_t*) data;

    // TODO: check result, buffer writes
    write(admin->outFd, &header, Admin_MessageHeader_SIZE);
    if (length > 0) {
        write(admin->outFd, buf, length);
    }
}

/**
 * public function to send responses
 */
void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin)
{
    if (!admin) {
        return;
    }
    Assert_true(txid);

    uint32_t channelNum;
    struct Admin_Channel* channel = adminChannelFindByTxid(admin, txid, &channelNum);

    if (!channel) {
        // txid too short, invalid channel number, closed channel or not matching serial
        Log_debug(admin->logger,
                  "Dropped response because channel isn't open anymore.");
        return;
    }

    uint8_t buff[MAX_API_REQUEST_SIZE];

    uint8_t allocBuff[256];
    struct Allocator* allocator = BufferAllocator_new(allocBuff, 256);

    // Bounce back the user-supplied txid.
    String userTxid = {
        .bytes = txid->bytes + Admin_TxidPrefix_SIZE,
        .len = txid->len - Admin_TxidPrefix_SIZE
    };
    if (txid->len > Admin_TxidPrefix_SIZE) {
        Dict_putString(message, TXID, &userTxid, allocator);
    }

    struct Writer* w = ArrayWriter_new(buff, sizeof(buff), allocator);
    StandardBencSerializer_get()->serializeDictionary(w, message);

    adminChannelSendData(admin, channelNum, buff, w->bytesWritten(w));
}

/**
 * close a channel (for example if an error happened or we received non-empty
 * messages on a invalid channel number)
 * also used to cleanup if we receive a close message
 */
static void adminChannelClose(struct Admin* admin, uint32_t channelNum)
{
    struct Admin_Channel* channel = adminChannelFindById(admin, channelNum);

    if (channel) {
        switch (channel->state) {
        case Admin_ChannelState_OPEN:
            break;
        case Admin_ChannelState_CLOSED:
        case Admin_ChannelState_WAIT_FOR_CLOSE:
            return; // already sent close, nothing to do
        }
        channel->state = Admin_ChannelState_WAIT_FOR_CLOSE;

        // clean up bufers
        channel->bufferLen = 0;
        channel->buffer = NULL;
        if (channel->allocator) {
            channel->allocator->free(channel->allocator);
            channel->allocator = NULL;
        }
    }
    adminChannelSendData(admin, channelNum, NULL, 0);
}

/**
 * handle a received channel close (the received header is in admin->messageHeader)
 * as invalid channels are never OPEN we never have to ACK a close on them
 */
static void adminChannelHandleClose(struct Admin* admin)
{
    uint32_t channelNum = admin->messageHeader.channelNum;
    struct Admin_Channel* channel = adminChannelFindById(admin, channelNum);

    if (channel) {
        switch (channel->state) {
        case Admin_ChannelState_OPEN:
            // close active channel
            adminChannelClose(admin, channelNum);
            // now the state is WAIT_FOR_CLOSE, set it to CLOSED
            channel->state = Admin_ChannelState_CLOSED;
            break;
        case Admin_ChannelState_WAIT_FOR_CLOSE:
            channel->state = Admin_ChannelState_CLOSED;
            channel->serial++;
            break;
        case Admin_ChannelState_CLOSED:
            // nothing to do
            break;
        }
    }
}

static inline bool authValid(Dict* message, uint8_t* buffer, uint32_t length, struct Admin* admin)
{
    String* cookieStr = Dict_getString(message, String_CONST("cookie"));
    uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0;
    if (!cookie) {
        int64_t* cookieInt = Dict_getInt(message, String_CONST("cookie"));
        cookie = (cookieInt) ? *cookieInt : 0;
    }
    uint64_t nowSecs = Time_currentTimeSeconds(admin->eventBase);
    String* submittedHash = Dict_getString(message, String_CONST("hash"));
    if (cookie >  nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) {
        return false;
    }

    uint8_t* hashPtr = (uint8_t*) strstr((char*) buffer, submittedHash->bytes);

    if (!hashPtr || !admin->password) {
        return false;
    }

    uint8_t passAndCookie[64];
    snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie);
    uint8_t hash[32];
    crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie));
    Hex_encode(hashPtr, 64, hash, 32);

    crypto_hash_sha256(hash, buffer, length);
    Hex_encode(hashPtr, 64, hash, 32);
    return memcmp(hashPtr, submittedHash->bytes, 64) == 0;
}
Esempio n. 14
0
static void handleRequestFromChild(struct Admin* admin,
                                   uint8_t buffer[MAX_API_REQUEST_SIZE],
                                   size_t amount,
                                   struct Allocator* allocator)
{
    struct Reader* reader = ArrayReader_new(buffer + TXID_LEN, amount - TXID_LEN, allocator);
    Dict message;
    if (StandardBencSerializer_get()->parseDictionary(reader, allocator, &message)) {
        Log_info(admin->logger, "Got unparsable data from admin interface.");
        return;
    }

    String* query = Dict_getString(&message, CJDHTConstants_QUERY);
    if (!query) {
        Log_info(admin->logger, "Got a non-query from admin interface.");
        return;
    }

    // txid becomes the user supplied txid combined with the inter-process txid.
    String* userTxid = Dict_getString(&message, TXID);
    String* txid =
        String_newBinary((char*)buffer, ((userTxid) ? userTxid->len : 0) + TXID_LEN, allocator);
    if (userTxid) {
        Bits_memcpy(txid->bytes + TXID_LEN, userTxid->bytes, userTxid->len);
    }

    // If they're asking for a cookie then lets give them one.
    String* cookie = String_CONST("cookie");
    if (String_equals(query, cookie)) {
        Dict* d = Dict_new(allocator);
        char bytes[32];
        snprintf(bytes, 32, "%u", (uint32_t) Time_currentTimeSeconds(admin->eventBase));
        String* theCookie = &(String) { .len = strlen(bytes), .bytes = bytes };
        Dict_putString(d, cookie, theCookie, allocator);
        Admin_sendMessage(d, txid, admin);
        return;
    }

    // If this is a permitted query, make sure the cookie is right.
    String* auth = String_CONST("auth");
    bool authed = false;
    if (String_equals(query, auth)) {
        if (!authValid(&message, buffer + TXID_LEN, reader->bytesRead(reader), admin)) {
            Dict* d = Dict_new(allocator);
            Dict_putString(d, String_CONST("error"), String_CONST("Auth failed."), allocator);
            Admin_sendMessage(d, txid, admin);
            return;
        }
        query = Dict_getString(&message, String_CONST("aq"));
        authed = true;
    }

    Dict* args = Dict_getDict(&message, String_CONST("args"));
    bool noFunctionsCalled = true;
    for (int i = 0; i < admin->functionCount; i++) {
        if (String_equals(query, admin->functions[i].name)
            && (authed || !admin->functions[i].needsAuth))
        {
            if (checkArgs(args, &admin->functions[i], txid, admin)) {
                admin->functions[i].call(args, admin->functions[i].context, txid);
            }
            noFunctionsCalled = false;
        }
    }

    if (noFunctionsCalled) {
        Dict* d = Dict_new(allocator);
        Dict_putString(d,
                       String_CONST("error"),
                       String_CONST("No functions matched your request."),
                       allocator);
        Dict* functions = Dict_new(allocator);
        for (int i = 0; i < admin->functionCount; i++) {
            Dict_putDict(functions, admin->functions[i].name, admin->functions[i].args, allocator);
        }
        if (functions) {
            Dict_putDict(d, String_CONST("availableFunctions"), functions, allocator);
        }
        Admin_sendMessage(d, txid, admin);
        return;
    }

    return;
}