Ejemplo n.º 1
0
static void nodeForAddress(struct PFChan_Node* nodeOut, struct Address* addr, uint32_t metric)
{
    Bits_memset(nodeOut, 0, PFChan_Node_SIZE);
    nodeOut->version_be = Endian_hostToBigEndian32(addr->protocolVersion);
    nodeOut->metric_be = Endian_hostToBigEndian32(metric | 0xffff0000);
    nodeOut->path_be = Endian_hostToBigEndian64(addr->path);
    Bits_memcpy(nodeOut->publicKey, addr->key, 32);
    Bits_memcpy(nodeOut->ip6, addr->ip6.bytes, 16);
}
Ejemplo n.º 2
0
static struct Message* pathfinderMsg(enum PFChan_Core ev,
                                     struct Pathfinder* pf,
                                     struct Allocator* alloc)
{
    struct Message* msg = Message_new(PFChan_Core_Pathfinder_SIZE, 512, alloc);
    struct PFChan_Core_Pathfinder* pathfinder = (struct PFChan_Core_Pathfinder*) msg->bytes;
    pathfinder->superiority_be = Endian_hostToBigEndian32(pf->superiority);
    pathfinder->pathfinderId_be = Endian_hostToBigEndian32(pf->pathfinderId);
    Bits_memcpy(pathfinder->userAgent, pf->userAgent, 64);
    Message_push32(msg, 0xffffffff, NULL);
    Message_push32(msg, ev, NULL);
    return msg;
}
Ejemplo n.º 3
0
int main()
{
    printInfo();

    volatile uint64_t b =  0x0123456789abcdef;
    volatile uint64_t sb = 0xefcdab8967452301;

    volatile uint32_t a =  0x01234567;
    volatile uint32_t sa = 0x67452301;

    volatile uint16_t c =  0xcabe;
    volatile uint16_t sc = 0xbeca;

    if (!Endian_isBigEndian()) {
        Assert_true(c == Endian_bigEndianToHost16(sc));
        Assert_true(c == Endian_hostToBigEndian16(sc));
        Assert_true(c == Endian_hostToLittleEndian16(c));
        Assert_true(c == Endian_littleEndianToHost16(c));

        Assert_true(a == Endian_bigEndianToHost32(sa));
        Assert_true(a == Endian_hostToBigEndian32(sa));
        Assert_true(a == Endian_hostToLittleEndian32(a));
        Assert_true(a == Endian_littleEndianToHost32(a));

        Assert_true(b == Endian_bigEndianToHost64(sb));
        Assert_true(b == Endian_hostToBigEndian64(sb));
        Assert_true(b == Endian_hostToLittleEndian64(b));
        Assert_true(b == Endian_littleEndianToHost64(b));
    } else {
        Assert_true(c == Endian_bigEndianToHost16(c));
        Assert_true(c == Endian_hostToBigEndian16(c));
        Assert_true(c == Endian_hostToLittleEndian16(sc));
        Assert_true(c == Endian_littleEndianToHost16(sc));

        Assert_true(a == Endian_bigEndianToHost32(a));
        Assert_true(a == Endian_hostToBigEndian32(a));
        Assert_true(a == Endian_hostToLittleEndian32(sa));
        Assert_true(a == Endian_littleEndianToHost32(sa));

        Assert_true(b == Endian_bigEndianToHost64(b));
        Assert_true(b == Endian_hostToBigEndian64(b));
        Assert_true(b == Endian_hostToLittleEndian64(sb));
        Assert_true(b == Endian_littleEndianToHost64(sb));
    }

    Assert_true(b == Endian_byteSwap64(sb));
    Assert_true(a == Endian_byteSwap32(sa));
    Assert_true(c == Endian_byteSwap16(sc));
    return 0;
}
Ejemplo n.º 4
0
String* VersionList_stringify(struct VersionList* list, struct Allocator* alloc)
{
    uint8_t numberSize = 1;
    uint32_t max = 0xff;
    for (int i = 0; i < (int)list->length; i++) {
        while (list->versions[i] >= max) {
            numberSize++;
            max = max << 8 | 0xff;
        }
    }

    String* out = String_newBinary(NULL, (numberSize * list->length + 1), alloc);

    struct Writer* w = ArrayWriter_new(out->bytes, out->len, alloc);
    Writer_write(w, &numberSize, 1);

    for (int i = 0; i < (int)list->length; i++) {
        uint32_t ver = list->versions[i] << ((4-numberSize) * 8);
        ver = Endian_hostToBigEndian32(ver);
        Writer_write(w, (uint8_t*) &ver, numberSize);
    }
    Writer_write(w, &numberSize, 1);

    return out;
}
Ejemplo n.º 5
0
static void sendMsg(struct MsgCore_pvt* mcp,
                    Dict* msgDict,
                    struct Address* addr,
                    struct Allocator* allocator)
{
    struct Allocator* alloc = Allocator_child(allocator);

    // Send the encoding scheme definition
    Dict_putString(msgDict, CJDHTConstants_ENC_SCHEME, mcp->schemeDefinition, allocator);

    // And tell the asker which interface the message came from
    int encIdx = EncodingScheme_getFormNum(mcp->scheme, addr->path);
    Assert_true(encIdx != EncodingScheme_getFormNum_INVALID);
    Dict_putInt(msgDict, CJDHTConstants_ENC_INDEX, encIdx, allocator);

    // send the protocol version
    Dict_putInt(msgDict, CJDHTConstants_PROTOCOL, Version_CURRENT_PROTOCOL, allocator);

    if (!Defined(SUBNODE)) {
        String* q = Dict_getStringC(msgDict, "q");
        String* sq = Dict_getStringC(msgDict, "sq");
        if (q || sq) {
            Log_debug(mcp->log, "Send query [%s] to [%s]",
                ((q) ? q->bytes : sq->bytes),
                Address_toString(addr, alloc)->bytes);
            String* txid = Dict_getStringC(msgDict, "txid");
            Assert_true(txid);
            String* newTxid = String_newBinary(NULL, txid->len + 1, alloc);
            Bits_memcpy(&newTxid->bytes[1], txid->bytes, txid->len);
            newTxid->bytes[0] = '1';
            Dict_putStringC(msgDict, "txid", newTxid, alloc);
        }
    }

    struct Message* msg = Message_new(0, 2048, alloc);
    BencMessageWriter_write(msgDict, msg, NULL);

    //Log_debug(mcp->log, "Sending msg [%s]", Escape_getEscaped(msg->bytes, msg->length, alloc));

    // Sanity check (make sure the addr was actually calculated)
    Assert_true(addr->ip6.bytes[0] == 0xfc);

    struct DataHeader data;
    Bits_memset(&data, 0, sizeof(struct DataHeader));
    DataHeader_setVersion(&data, DataHeader_CURRENT_VERSION);
    DataHeader_setContentType(&data, ContentType_CJDHT);
    Message_push(msg, &data, sizeof(struct DataHeader), NULL);

    struct RouteHeader route;
    Bits_memset(&route, 0, sizeof(struct RouteHeader));
    Bits_memcpy(route.ip6, addr->ip6.bytes, 16);
    route.version_be = Endian_hostToBigEndian32(addr->protocolVersion);
    route.sh.label_be = Endian_hostToBigEndian64(addr->path);
    Bits_memcpy(route.publicKey, addr->key, 32);
    Message_push(msg, &route, sizeof(struct RouteHeader), NULL);

    Iface_send(&mcp->pub.interRouterIf, msg);
}
Ejemplo n.º 6
0
uint16_t Checksum_udpIp6(const uint8_t sourceAndDestAddrs[32],
                         const uint8_t udpHeaderAndContent[8],
                         uint16_t length)
{
    return ip6PacketChecksum(sourceAndDestAddrs,
                             udpHeaderAndContent,
                             length,
                             Endian_hostToBigEndian32(17));
}
Ejemplo n.º 7
0
uint16_t Checksum_icmp6(const uint8_t sourceAndDestAddrs[32],
                        const uint8_t icmpHeaderAndContent[4],
                        uint16_t length)
{
    return ip6PacketChecksum(sourceAndDestAddrs,
                             icmpHeaderAndContent,
                             length,
                             Endian_hostToBigEndian32(58));
}
Ejemplo n.º 8
0
static int incomingFromDHT(struct DHTMessage* dmessage, void* vpf)
{
    struct Pathfinder_pvt* pf = Identity_check((struct Pathfinder_pvt*) vpf);
    struct Message* msg = dmessage->binMessage;
    struct Address* addr = dmessage->address;

    if (addr->path == 1) {
        // Message to myself, can't handle this later because encrypting a message to yourself
        // causes problems.
        DHTModuleRegistry_handleIncoming(dmessage, pf->registry);
        return 0;
    }

    // Sanity check (make sure the addr was actually calculated)
    Assert_true(AddressCalc_validAddress(addr->ip6.bytes));

    Message_shift(msg, PFChan_Msg_MIN_SIZE, NULL);
    struct PFChan_Msg* emsg = (struct PFChan_Msg*) msg->bytes;
    Bits_memset(emsg, 0, PFChan_Msg_MIN_SIZE);

    DataHeader_setVersion(&emsg->data, DataHeader_CURRENT_VERSION);
    DataHeader_setContentType(&emsg->data, ContentType_CJDHT);

    Bits_memcpy(emsg->route.ip6, addr->ip6.bytes, 16);
    emsg->route.version_be = Endian_hostToBigEndian32(addr->protocolVersion);
    emsg->route.sh.label_be = Endian_hostToBigEndian64(addr->path);
    emsg->route.flags |= RouteHeader_flags_PATHFINDER;
    SwitchHeader_setVersion(&emsg->route.sh, SwitchHeader_CURRENT_VERSION);
    Bits_memcpy(emsg->route.publicKey, addr->key, 32);

    Assert_true(!Bits_isZero(emsg->route.publicKey, 32));
    Assert_true(emsg->route.sh.label_be);
    Assert_true(emsg->route.version_be);

    Message_push32(msg, PFChan_Pathfinder_SENDMSG, NULL);

    if (dmessage->replyTo) {
        // see incomingMsg
        dmessage->replyTo->pleaseRespond = true;
        //Log_debug(pf->log, "send DHT reply");
        return 0;
    }
    //Log_debug(pf->log, "send DHT request");

    Iface_send(&pf->pub.eventIf, msg);
    return 0;
}
Ejemplo n.º 9
0
static void sendPeer(uint32_t pathfinderId,
                     enum PFChan_Core ev,
                     struct Peer* peer)
{
    struct InterfaceController_pvt* ic = Identity_check(peer->ici->ic);
    struct Allocator* alloc = Allocator_child(ic->alloc);
    struct Message* msg = Message_new(PFChan_Node_SIZE, 512, alloc);
    struct PFChan_Node* node = (struct PFChan_Node*) msg->bytes;
    Bits_memcpyConst(node->ip6, peer->addr.ip6.bytes, 16);
    Bits_memcpyConst(node->publicKey, peer->addr.key, 32);
    node->path_be = Endian_hostToBigEndian64(peer->addr.path);
    node->metric_be = 0xffffffff;
    node->version_be = Endian_hostToBigEndian32(peer->addr.protocolVersion);
    Message_push32(msg, pathfinderId, NULL);
    Message_push32(msg, ev, NULL);
    Iface_send(&ic->eventEmitterIf, msg);
    Allocator_free(alloc);
}
Ejemplo n.º 10
0
static uint16_t ip6PacketChecksum(const uint8_t sourceAndDestAddrs[32],
                                  const uint8_t packetHeaderAndContent[8],
                                  uint16_t length,
                                  uint32_t packetType_be)
{
    Assert_true(!((uintptr_t)sourceAndDestAddrs % 2));
    Assert_true(!((uintptr_t)packetHeaderAndContent % 2));

    // http://tools.ietf.org/html/rfc2460#page-27
    uint64_t sum = STEP(sourceAndDestAddrs, 32, 0);

    const uint32_t length_be = Endian_hostToBigEndian32(length);
    sum = STEP((uint8_t*) &length_be, 4, sum);
    sum = STEP((uint8_t*) &packetType_be, 4, sum);
    sum = STEP(packetHeaderAndContent, length, sum);

    return COMPLETE(sum);
}
Ejemplo n.º 11
0
static inline uint8_t encryptMessage(struct Message* message,
                                     struct CryptoAuth_Wrapper* wrapper)
{
    Assert_true(message->padding >= 36 || !"not enough padding");

    encrypt(wrapper->nextNonce,
            message,
            wrapper->sharedSecret,
            wrapper->isInitiator);

    Message_shift(message, 4, NULL);

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;
    header->nonce = Endian_hostToBigEndian32(wrapper->nextNonce);
    wrapper->nextNonce++;

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}
Ejemplo n.º 12
0
List* EncodingScheme_asList(struct EncodingScheme* list, struct Allocator* alloc)
{
    Assert_true(EncodingScheme_isSane(list));
    String* prefixLen = String_new("prefixLen", alloc);
    String* bitCount = String_new("bitCount", alloc);
    String* prefix = String_new("prefix", alloc);
    List* scheme = NULL;
    for (int i = 0; i < (int)list->count; i++) {
        Dict* form = Dict_new(alloc);
        Dict_putInt(form, prefixLen, list->forms[i].prefixLen, alloc);
        Dict_putInt(form, bitCount, list->forms[i].bitCount, alloc);
        String* pfx = String_newBinary(NULL, 8, alloc);
        uint32_t prefix_be = Endian_hostToBigEndian32(list->forms[i].prefix);
        Hex_encode(pfx->bytes, 8, (uint8_t*)&prefix_be, 4);
        Dict_putString(form, prefix, pfx, alloc);
        scheme = List_addDict(scheme, form, alloc);
    }
    return scheme;
}
Ejemplo n.º 13
0
static inline uint8_t encryptMessage(struct Message* message,
                                     struct Wrapper* wrapper)
{
    assert(message->padding >= 36 || !"not enough padding");

    encrypt(wrapper->nextNonce,
            message,
            wrapper->secret,
            wrapper->isInitiator,
            wrapper->authenticatePackets);

    Message_shift(message, 4);

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;
    header->nonce = Endian_hostToBigEndian32(wrapper->nextNonce);
    wrapper->nextNonce++;

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}
Ejemplo n.º 14
0
static bool trySend4(struct Allocator* alloc,
                     uint32_t addr,
                     struct Iface* sendTo,
                     struct Context* ctx)
{
    struct Message* msg4 = Message_new(0, 512, alloc);
    Message_push(msg4, "hello world", 12, NULL);
    Message_push(msg4, NULL, Headers_IP4Header_SIZE, NULL);
    struct Headers_IP4Header* iph = (struct Headers_IP4Header*) msg4->bytes;
    Headers_setIpVersion(iph);
    uint32_t addr_be = Endian_hostToBigEndian32(addr);
    Bits_memcpy(iph->sourceAddr, &addr_be, 4);
    Bits_memcpy(ctx->sendingAddress, &addr_be, 4);
    Bits_memcpy(iph->destAddr, ((uint8_t[]){ 11, 0, 0, 1 }), 4);
    pushRouteDataHeaders(ctx, msg4);
    Iface_send(sendTo, msg4);
    if (ctx->called == 1) {
        ctx->called = 0;
        return true;
    }
    Assert_true(ctx->called == 0);
    return false;
}
Ejemplo n.º 15
0
// incoming message from network, pointing to the beginning of the switch header.
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
{
    struct SwitchPinger* ctx = Identity_check((struct SwitchPinger*) iface->receiverContext);
    struct SwitchHeader* switchHeader = (struct SwitchHeader*) msg->bytes;
    ctx->incomingLabel = Endian_bigEndianToHost64(switchHeader->label_be);
    ctx->incomingVersion = 0;
    Message_shift(msg, -SwitchHeader_SIZE, NULL);

    uint32_t handle = Message_pop32(msg, NULL);
    #ifdef Version_7_COMPAT
    if (handle != 0xffffffff) {
        Message_push32(msg, handle, NULL);
        handle = 0xffffffff;
        Assert_true(SwitchHeader_isV7Ctrl(switchHeader));
    }
    #endif
    Assert_true(handle == 0xffffffff);

    struct Control* ctrl = (struct Control*) msg->bytes;
    if (ctrl->type_be == Control_PONG_be) {
        Message_shift(msg, -Control_HEADER_SIZE, NULL);
        ctx->error = Error_NONE;
        if (msg->length >= Control_Pong_MIN_SIZE) {
            struct Control_Ping* pongHeader = (struct Control_Ping*) msg->bytes;
            ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be);
            if (pongHeader->magic != Control_Pong_MAGIC) {
                Log_debug(ctx->logger, "dropped invalid switch pong");
                return Error_INVALID;
            }
            Message_shift(msg, -Control_Pong_HEADER_SIZE, NULL);
        } else {
            Log_debug(ctx->logger, "got runt pong message, length: [%d]", msg->length);
            return Error_INVALID;
        }

    } else if (ctrl->type_be == Control_KEYPONG_be) {
        Message_shift(msg, -Control_HEADER_SIZE, NULL);
        ctx->error = Error_NONE;
        if (msg->length >= Control_KeyPong_HEADER_SIZE && msg->length <= Control_KeyPong_MAX_SIZE) {
            struct Control_KeyPing* pongHeader = (struct Control_KeyPing*) msg->bytes;
            ctx->incomingVersion = Endian_bigEndianToHost32(pongHeader->version_be);
            if (pongHeader->magic != Control_KeyPong_MAGIC) {
                Log_debug(ctx->logger, "dropped invalid switch key-pong");
                return Error_INVALID;
            }
            Bits_memcpyConst(ctx->incomingKey, pongHeader->key, 32);
            Message_shift(msg, -Control_KeyPong_HEADER_SIZE, NULL);
        } else if (msg->length > Control_KeyPong_MAX_SIZE) {
            Log_debug(ctx->logger, "got overlong key-pong message, length: [%d]", msg->length);
            return Error_INVALID;
        } else {
            Log_debug(ctx->logger, "got runt key-pong message, length: [%d]", msg->length);
            return Error_INVALID;
        }

    } else if (ctrl->type_be == Control_ERROR_be) {
        Message_shift(msg, -Control_HEADER_SIZE, NULL);
        Assert_true((uint8_t*)&ctrl->content.error.errorType_be == msg->bytes);
        if (msg->length < (Control_Error_HEADER_SIZE + SwitchHeader_SIZE + Control_HEADER_SIZE)) {
            Log_debug(ctx->logger, "runt error packet");
            return Error_NONE;
        }

        ctx->error = Message_pop32(msg, NULL);
        Message_push32(msg, 0, NULL);

        Message_shift(msg, -(Control_Error_HEADER_SIZE + SwitchHeader_SIZE), NULL);

        struct Control* origCtrl = (struct Control*) msg->bytes;

        Log_debug(ctx->logger, "error [%s] was caused by our [%s]",
                  Error_strerror(ctx->error),
                  Control_typeString(origCtrl->type_be));

        int shift;
        if (origCtrl->type_be == Control_PING_be) {
            shift = -(Control_HEADER_SIZE + Control_Ping_HEADER_SIZE);
        } else if (origCtrl->type_be == Control_KEYPING_be) {
            shift = -(Control_HEADER_SIZE + Control_KeyPing_HEADER_SIZE);
        } else {
            Assert_failure("problem in Ducttape.c");
        }
        if (msg->length < -shift) {
            Log_debug(ctx->logger, "runt error packet");
        }
        Message_shift(msg, shift, NULL);

    } else {
        // If it gets here then Ducttape.c is failing.
        Assert_true(false);
    }

    String* msgStr = &(String) { .bytes = (char*) msg->bytes, .len = msg->length };
    Pinger_pongReceived(msgStr, ctx->pinger);
    Bits_memset(ctx->incomingKey, 0, 32);
    return Error_NONE;
}

static void onPingResponse(String* data, uint32_t milliseconds, void* vping)
{
    struct Ping* p = Identity_check((struct Ping*) vping);
    enum SwitchPinger_Result err = SwitchPinger_Result_OK;
    uint64_t label = p->context->incomingLabel;
    if (data) {
        if (label != p->label) {
            err = SwitchPinger_Result_LABEL_MISMATCH;
        } else if ((p->data || data->len > 0) && !String_equals(data, p->data)) {
            err = SwitchPinger_Result_WRONG_DATA;
        } else if (p->context->error == Error_LOOP_ROUTE) {
            err = SwitchPinger_Result_LOOP_ROUTE;
        } else if (p->context->error) {
            err = SwitchPinger_Result_ERROR_RESPONSE;
        }
    } else {
        err = SwitchPinger_Result_TIMEOUT;
    }

    uint32_t version = p->context->incomingVersion;
    struct SwitchPinger_Response* resp =
        Allocator_calloc(p->pub.pingAlloc, sizeof(struct SwitchPinger_Response), 1);
    resp->version = p->context->incomingVersion;
    resp->res = err;
    resp->label = label;
    resp->data = data;
    resp->milliseconds = milliseconds;
    resp->version = version;
    Bits_memcpyConst(resp->key, p->context->incomingKey, 32);
    resp->ping = &p->pub;
    p->onResponse(resp, p->pub.onResponseContext);
}

static void sendPing(String* data, void* sendPingContext)
{
    struct Ping* p = Identity_check((struct Ping*) sendPingContext);

    struct Message* msg = Message_new(0, data->len + 512, p->pub.pingAlloc);

    while (((uintptr_t)msg->bytes - data->len) % 4) {
        Message_push8(msg, 0, NULL);
    }
    msg->length = 0;

    Message_push(msg, data->bytes, data->len, NULL);
    Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault");

    if (p->pub.keyPing) {
        Message_shift(msg, Control_KeyPing_HEADER_SIZE, NULL);
        struct Control_KeyPing* keyPingHeader = (struct Control_KeyPing*) msg->bytes;
        keyPingHeader->magic = Control_KeyPing_MAGIC;
        keyPingHeader->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);
        Bits_memcpyConst(keyPingHeader->key, p->context->myAddr->key, 32);
    } else {
        Message_shift(msg, Control_Ping_HEADER_SIZE, NULL);
        struct Control_Ping* pingHeader = (struct Control_Ping*) msg->bytes;
        pingHeader->magic = Control_Ping_MAGIC;
        pingHeader->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);
    }

    Message_shift(msg, Control_HEADER_SIZE, NULL);
    struct Control* ctrl = (struct Control*) msg->bytes;
    ctrl->checksum_be = 0;
    ctrl->type_be = (p->pub.keyPing) ? Control_KEYPING_be : Control_PING_be;
    ctrl->checksum_be = Checksum_engine(msg->bytes, msg->length);

    #ifdef Version_7_COMPAT
        if (0) {
    #endif
    Message_push32(msg, 0xffffffff, NULL);
    #ifdef Version_7_COMPAT
        }
    #endif

    Message_shift(msg, SwitchHeader_SIZE, NULL);
    struct SwitchHeader* switchHeader = (struct SwitchHeader*) msg->bytes;
    switchHeader->label_be = Endian_hostToBigEndian64(p->label);

    SwitchHeader_setVersion(switchHeader, SwitchHeader_CURRENT_VERSION);
    SwitchHeader_setPenalty(switchHeader, 0);
    SwitchHeader_setCongestion(switchHeader, 0);

    #ifdef Version_7_COMPAT
        // v7 detects ctrl packets by the bit which has been
        // re-appropriated for suppression of errors.
        switchHeader->congestAndSuppressErrors = 1;
        SwitchHeader_setVersion(switchHeader, 0);
    #endif

    p->context->iface->sendMessage(msg, p->context->iface);
}

static String* RESULT_STRING_OK =             String_CONST_SO("pong");
static String* RESULT_STRING_LABEL_MISMATCH = String_CONST_SO("diff_label");
static String* RESULT_STRING_WRONG_DATA =     String_CONST_SO("diff_data");
static String* RESULT_STRING_ERROR_RESPONSE = String_CONST_SO("err_switch");
static String* RESULT_STRING_TIMEOUT =        String_CONST_SO("timeout");
static String* RESULT_STRING_UNKNOWN =        String_CONST_SO("err_unknown");
static String* RESULT_STRING_LOOP =           String_CONST_SO("err_loop");

String* SwitchPinger_resultString(enum SwitchPinger_Result result)
{
    switch (result) {
        case SwitchPinger_Result_OK:
            return RESULT_STRING_OK;

        case SwitchPinger_Result_LABEL_MISMATCH:
            return RESULT_STRING_LABEL_MISMATCH;

        case SwitchPinger_Result_WRONG_DATA:
            return RESULT_STRING_WRONG_DATA;

        case SwitchPinger_Result_ERROR_RESPONSE:
            return RESULT_STRING_ERROR_RESPONSE;

        case SwitchPinger_Result_TIMEOUT:
            return RESULT_STRING_TIMEOUT;

        case SwitchPinger_Result_LOOP_ROUTE:
            return RESULT_STRING_LOOP;

        default:
            return RESULT_STRING_UNKNOWN;
    };
}

static int onPingFree(struct Allocator_OnFreeJob* job)
{
    struct Ping* ping = Identity_check((struct Ping*)job->userData);
    struct SwitchPinger* ctx = Identity_check(ping->context);
    ctx->outstandingPings--;
    Assert_true(ctx->outstandingPings >= 0);
    return 0;
}

struct SwitchPinger_Ping* SwitchPinger_newPing(uint64_t label,
                                               String* data,
                                               uint32_t timeoutMilliseconds,
                                               SwitchPinger_ResponseCallback onResponse,
                                               struct Allocator* alloc,
                                               struct SwitchPinger* ctx)
{
    if (data && data->len > Control_Ping_MAX_SIZE) {
        return NULL;
    }

    if (ctx->outstandingPings > ctx->maxConcurrentPings) {
        Log_debug(ctx->logger, "Skipping switch ping because there are already [%d] outstanding",
                  ctx->outstandingPings);
        return NULL;
    }

    struct Pinger_Ping* pp =
        Pinger_newPing(data, onPingResponse, sendPing, timeoutMilliseconds, alloc, ctx->pinger);

    struct Ping* ping = Allocator_clone(pp->pingAlloc, (&(struct Ping) {
        .pub = {
            .pingAlloc = pp->pingAlloc
        },
        .label = label,
        .data = String_clone(data, pp->pingAlloc),
        .context = ctx,
        .onResponse = onResponse,
        .pingerPing = pp
    }));
Ejemplo n.º 16
0
static void switching(struct Context* ctx)
{
    Log_info(ctx->log, "Setting up salsa20/poly1305 benchmark (encryption and decryption only)");
    struct Allocator* alloc = Allocator_child(ctx->alloc);;

    struct SwitchingContext* sc = Allocator_calloc(alloc, sizeof(struct SwitchingContext), 1);
    Identity_set(sc);
    sc->benchmarkCtx = ctx;
    sc->aliceIf.send = aliceToBob;
    sc->bobIf.send = bobToAlice;
    sc->aliceCtrlIf.send = aliceCtrlRecv;

    struct NetCore* alice = NetCore_new(SECRETA, alloc, ctx->base, ctx->rand, ctx->log);
    struct InterfaceController_Iface* aliceIci =
        InterfaceController_newIface(alice->ifController, String_CONST("alice"), alloc);
    Iface_plumb(&sc->aliceIf, &aliceIci->addrIf);

    struct NetCore* bob = NetCore_new(SECRETB, alloc, ctx->base, ctx->rand, ctx->log);
    struct InterfaceController_Iface* bobIci =
        InterfaceController_newIface(bob->ifController, String_CONST("bob"), alloc);
    Iface_plumb(&sc->bobIf, &bobIci->addrIf);

    CryptoAuth_addUser(String_CONST("abcdefg123"), 1, String_CONST("TEST"), bob->ca);

    // Client has pubKey and passwd for the server.
    int ret = InterfaceController_bootstrapPeer(alice->ifController,
                                                aliceIci->ifNum,
                                                bob->ca->publicKey,
                                                Sockaddr_LOOPBACK,
                                                String_CONST("abcdefg123"),
                                                alloc);
    Assert_true(!ret);

    Iface_unplumb(alice->switchAdapter->controlIf.connectedIf, &alice->switchAdapter->controlIf);
    Iface_plumb(&alice->switchAdapter->controlIf, &sc->aliceCtrlIf);

    struct Message* msg = Message_new(Control_Ping_MIN_SIZE + Control_Header_SIZE, 256, alloc);
    struct Control_Header* ch = (struct Control_Header*) msg->bytes;
    struct Control_Ping* ping = (struct Control_Ping*) &ch[1];
    ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);
    Message_push32(msg, 0xffffffff, NULL);
    uint32_t* handle_be = (uint32_t*)msg->bytes;
    Message_push(msg, NULL, SwitchHeader_SIZE, NULL);
    struct SwitchHeader* sh = (struct SwitchHeader*) msg->bytes;
    // TODO(cjd): this will fail with a different encoding scheme
    sh->label_be = Endian_hostToBigEndian64(0x13);

    for (int i = 1; i < 6; i++) {
        ping->magic = Control_Ping_MAGIC;
        ch->type_be = Control_PING_be;
        ch->checksum_be = 0;
        ch->checksum_be = Checksum_engine((void*)ch, Control_Ping_MIN_SIZE + Control_Header_SIZE);

        Iface_send(&sc->aliceCtrlIf, msg);

        Assert_true(sc->msgCount == i);
        Assert_true(msg->bytes == (void*)sh);
        Assert_true(ping->magic == Control_Pong_MAGIC);
        Assert_true(ch->type_be = Control_PONG_be);
        Assert_true(!Checksum_engine((void*)ch, Control_Ping_MIN_SIZE + Control_Header_SIZE));
    }

    *handle_be = 0xfffffff0;
    int count = 1000000;
    begin(ctx, "Switching", count, "packets");
    for (int i = 0; i < count; i++) {
        sh->versionAndLabelShift = SwitchHeader_CURRENT_VERSION << 6;
        Iface_send(&sc->aliceCtrlIf, msg);
        Assert_true(msg->bytes == (void*)sh);
    }
    done(ctx);

    Log_info(ctx->log, "DONE");
    Allocator_free(alloc);
}
Ejemplo n.º 17
0
        Bits_memcpyConst(ss->pub.ip6, lookupKey, 16);
        ss->pub.internal = CryptoAuth_wrapInterface(&ss->pub.external,
                                                    cryptoKey,
                                                    lookupKey,
                                                    false,
                                                    "inner",
                                                    sm->cryptoAuth);

        ss->pub.internal->receiveMessage = receiveMessage;
        ss->pub.internal->receiverContext = ss;

        ifaceIndex = Map_OfSessionsByIp6_put((struct Ip6*)lookupKey, &ss, &sm->ifaceMap);

        ss->pub.receiveHandle_be =
            Endian_hostToBigEndian32(sm->ifaceMap.handles[ifaceIndex] + sm->first);

    } else {
        uint8_t* herPubKey =
            CryptoAuth_getHerPublicKey(sm->ifaceMap.values[ifaceIndex]->pub.internal);
        if (Bits_isZero(herPubKey, 32) && cryptoKey) {
            Bits_memcpyConst(herPubKey, cryptoKey, 32);
        }
    }

    check(sm, ifaceIndex);

    return &Identity_check(sm->ifaceMap.values[ifaceIndex])->pub;
}

struct SessionManager_Session* SessionManager_sessionForHandle(uint32_t handle,
Ejemplo n.º 18
0
static uint8_t encryptHandshake(struct Message* message, struct Wrapper* wrapper)
{
    assert(message->padding >= sizeof(union Headers_CryptoAuth) || !"not enough padding");

    Message_shift(message, sizeof(union Headers_CryptoAuth));

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;

    // garbage the auth field to frustrate DPI and set the nonce (next 24 bytes after the auth)
    randombytes((uint8_t*) &header->handshake.auth, sizeof(union Headers_AuthChallenge) + 24);
    memcpy(&header->handshake.publicKey, wrapper->context->publicKey, 32);

    if (!knowHerKey(wrapper)) {
        return genReverseHandshake(message, wrapper, header);
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    if (wrapper->password != NULL) {
        struct Auth auth;
        passwordHash = hashPassword(&auth, wrapper->password, wrapper->authType);
        memcpy(header->handshake.auth.bytes, &auth.challenge, sizeof(union Headers_AuthChallenge));
    }
    header->handshake.auth.challenge.type = wrapper->authType;

    Headers_setPacketAuthRequired(&header->handshake.auth, wrapper->authenticatePackets);

    // set the session state
    uint32_t sessionState_be = Endian_hostToBigEndian32(wrapper->nextNonce);
    header->nonce = sessionState_be;

    if (wrapper->nextNonce == 0 || wrapper->nextNonce == 2) {
        // If we're sending a hello or a key
        crypto_box_curve25519xsalsa20poly1305_keypair(header->handshake.encryptedTempKey,
                                                      wrapper->secret);
        if (wrapper->nextNonce == 0) {
            memcpy(wrapper->tempKey, header->handshake.encryptedTempKey, 32);
        }
        #ifdef Log_DEBUG
            assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
            assert(!Bits_isZero(wrapper->secret, 32));
        #endif
    } else if (wrapper->nextNonce == 3) {
        // Dupe key
        // If nextNonce is 1 then we have our pubkey stored in wrapper->tempKey,
        // If nextNonce is 3 we need to recalculate it each time
        // because tempKey the final secret.
        crypto_scalarmult_curve25519_base(header->handshake.encryptedTempKey,
                                          wrapper->secret);
    } else {
        // Dupe hello
        // wrapper->nextNonce == 1
        // Our public key is cached in wrapper->tempKey so lets copy it out.
        memcpy(header->handshake.encryptedTempKey, wrapper->tempKey, 32);
    }

    uint8_t sharedSecret[32];
    if (wrapper->nextNonce < 2) {
        if (wrapper->nextNonce == 0) {
            Log_debug(wrapper->context->logger, "Sending hello packet\n");
        } else {
            Log_debug(wrapper->context->logger, "Sending repeat hello packet\n");
        }
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        wrapper->isInitiator = true;
        wrapper->nextNonce = 1;
        #ifdef Log_DEBUG
            assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
            uint8_t myTempPubKey[32];
            crypto_scalarmult_curve25519_base(myTempPubKey, wrapper->secret);
            assert(!memcmp(header->handshake.encryptedTempKey, myTempPubKey, 32));
        #endif
        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
            Log_keys1(wrapper->context->logger,
                      "Wrapping temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    } else {
        if (wrapper->nextNonce == 2) {
            Log_debug(wrapper->context->logger, "Sending key packet\n");
        } else {
            Log_debug(wrapper->context->logger, "Sending repeat key packet\n");
        }
        // Handshake2 wrapper->tempKey holds her public temp key.
        // it was put there by receiveMessage()
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->tempKey,
                        passwordHash,
                        wrapper->context->logger);
        wrapper->nextNonce = 3;

        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32);
            Log_keys1(wrapper->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - Headers_CryptoAuth_SIZE);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    Log_debug1(wrapper->context->logger, "Message length: %u\n", message->length);
    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys3(wrapper->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif
    #ifdef Log_DEBUG
        assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
    #endif

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, Headers_CryptoAuth_SIZE - 32 - 16);

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}
Ejemplo n.º 19
0
        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);
        return sp;
    } else {
        // Interface already exists, set the time of last message to "now".
        sm->ifaceMap.values[ifaceIndex].lastMessageTime = Time_currentTimeSeconds(sm->eventBase);
        uint8_t* herPubKey = CryptoAuth_getHerPublicKey(&sm->ifaceMap.values[ifaceIndex].iface);
        if (Bits_isZero(herPubKey, 32) && cryptoKey) {
            Bits_memcpyConst(herPubKey, cryptoKey, 32);
        }
    }

    return &sm->ifaceMap.values[ifaceIndex];
}

struct SessionManager_Session* SessionManager_sessionForHandle(uint32_t handle,
Ejemplo n.º 20
0
static uint8_t encryptHandshake(struct Message* message,
                                struct CryptoAuth_Wrapper* wrapper,
                                int setupMessage)
{
    Message_shift(message, sizeof(union Headers_CryptoAuth));

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;

    // garbage the auth challenge and set the nonce which follows it
    Random_bytes(wrapper->context->rand, (uint8_t*) &header->handshake.auth,
                 sizeof(union Headers_AuthChallenge) + 24);

    // set the permanent key
    Bits_memcpyConst(&header->handshake.publicKey, wrapper->context->pub.publicKey, 32);

    if (!knowHerKey(wrapper)) {
        return genReverseHandshake(message, wrapper, header);
    }

    if (wrapper->bufferedMessage) {
        // We wanted to send a message but we didn't know the peer's key so we buffered it
        // and sent a connectToMe, this or it's reply was lost in the network.
        // Now we just discovered their key and we're sending a hello packet.
        // Lets send 2 hello packets instead and on one will attach our buffered message.

        // This can never happen when the machine is beyond the first hello packet because
        // it should have been sent either by this or in the recipet of a hello packet from
        // the other node.
        Assert_true(wrapper->nextNonce == 0);

        struct Message* bm = wrapper->bufferedMessage;
        wrapper->bufferedMessage = NULL;
        cryptoAuthDebug0(wrapper, "Sending buffered message");
        sendMessage(bm, &wrapper->externalInterface);
        Allocator_free(bm->alloc);
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    struct CryptoAuth_Auth auth;
    if (wrapper->password != NULL) {
        passwordHash = hashPassword(&auth, wrapper->password, wrapper->authType);
        Bits_memcpyConst(header->handshake.auth.bytes,
                         &auth.challenge,
                         sizeof(union Headers_AuthChallenge));
    }
    header->handshake.auth.challenge.type = wrapper->authType;

    Headers_setPacketAuthRequired(&header->handshake.auth, wrapper->authenticatePackets);

    // This is a special packet which the user should never see.
    Headers_setSetupPacket(&header->handshake.auth, setupMessage);

    // Set the session state
    uint32_t sessionState_be = Endian_hostToBigEndian32(wrapper->nextNonce);
    header->nonce = sessionState_be;

    if (wrapper->nextNonce == 0 || wrapper->nextNonce == 2) {
        // If we're sending a hello or a key
        Random_bytes(wrapper->context->rand, wrapper->secret, 32);
        crypto_scalarmult_curve25519_base(header->handshake.encryptedTempKey,  wrapper->secret);

        #ifdef Log_KEYS
            uint8_t tempPrivateKeyHex[65];
            Hex_encode(tempPrivateKeyHex, 65, wrapper->secret, 32);
            uint8_t tempPubKeyHex[65];
            Hex_encode(tempPubKeyHex, 65, header->handshake.encryptedTempKey, 32);
            Log_keys(wrapper->context->logger, "Generating temporary keypair\n"
                                                "    myTempPrivateKey=%s\n"
                                                "     myTempPublicKey=%s\n",
                      tempPrivateKeyHex, tempPubKeyHex);
        #endif
        if (wrapper->nextNonce == 0) {
            Bits_memcpyConst(wrapper->tempKey, header->handshake.encryptedTempKey, 32);
        }
        #ifdef Log_DEBUG
            Assert_true(!Bits_isZero(header->handshake.encryptedTempKey, 32));
            Assert_true(!Bits_isZero(wrapper->secret, 32));
        #endif
    } else if (wrapper->nextNonce == 3) {
        // Dupe key
        // If nextNonce is 1 then we have our pubkey stored in wrapper->tempKey,
        // If nextNonce is 3 we need to recalculate it each time
        // because tempKey the final secret.
        crypto_scalarmult_curve25519_base(header->handshake.encryptedTempKey,
                                          wrapper->secret);
    } else {
        // Dupe hello
        // wrapper->nextNonce == 1
        // Our public key is cached in wrapper->tempKey so lets copy it out.
        Bits_memcpyConst(header->handshake.encryptedTempKey, wrapper->tempKey, 32);
    }
    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(wrapper->context->logger,
                  "Wrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    cryptoAuthDebug(wrapper, "Sending %s%s packet",
                    ((wrapper->nextNonce & 1) ? "repeat " : ""),
                    ((wrapper->nextNonce < 2) ? "hello" : "key"));

    uint8_t sharedSecret[32];
    if (wrapper->nextNonce < 2) {
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);

        wrapper->isInitiator = true;
        wrapper->nextNonce = 1;
    } else {
        // Handshake2 wrapper->tempKey holds her public temp key.
        // it was put there by receiveMessage()
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->tempKey,
                        passwordHash,
                        wrapper->context->logger);
        wrapper->nextNonce = 3;

        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32);
            Log_keys(wrapper->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - Headers_CryptoAuth_SIZE);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(wrapper->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif
    #ifdef Log_DEBUG
        Assert_true(!Bits_isZero(header->handshake.encryptedTempKey, 32));
    #endif

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, Headers_CryptoAuth_SIZE - 32 - 16);

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}
Ejemplo n.º 21
0
static uint8_t encryptHandshake(struct Message* message,
                                struct CryptoAuth_Wrapper* wrapper,
                                int setupMessage)
{
    Message_shift(message, sizeof(union Headers_CryptoAuth), NULL);

    union Headers_CryptoAuth* header = (union Headers_CryptoAuth*) message->bytes;

    // garbage the auth challenge and set the nonce which follows it
    Random_bytes(wrapper->context->rand, (uint8_t*) &header->handshake.auth,
                 sizeof(union Headers_AuthChallenge) + 24);

    // set the permanent key
    Bits_memcpyConst(&header->handshake.publicKey, wrapper->context->pub.publicKey, 32);

    if (!knowHerKey(wrapper)) {
        return genReverseHandshake(message, wrapper, header);
    } else if (!Bits_isZero(wrapper->herIp6, 16)) {
        // If someone starts a CA session and then discovers the key later and memcpy's it into the
        // result of getHerPublicKey() then we want to make sure they didn't memcpy in an invalid
        // key.
        uint8_t calculatedIp6[16];
        AddressCalc_addressForPublicKey(calculatedIp6, wrapper->herPerminentPubKey);
        Assert_true(!Bits_memcmp(wrapper->herIp6, calculatedIp6, 16));
    }

    if (wrapper->bufferedMessage) {
        // We wanted to send a message but we didn't know the peer's key so we buffered it
        // and sent a connectToMe.
        // Now we just discovered their key and we're sending a hello packet.
        // Lets send 2 hello packets instead and on one will attach our buffered message.

        // This can never happen when the machine is beyond the first hello packet because
        // it should have been sent either by this or in the recipet of a hello packet from
        // the other node.
        Assert_true(wrapper->nextNonce == 0);

        struct Message* bm = wrapper->bufferedMessage;
        wrapper->bufferedMessage = NULL;
        cryptoAuthDebug0(wrapper, "Sending buffered message");
        sendMessage(bm, &wrapper->externalInterface);
        Allocator_free(bm->alloc);
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    struct CryptoAuth_Auth auth;
    if (wrapper->password != NULL) {
        passwordHash = hashPassword(&auth, wrapper->password, wrapper->authType);
        Bits_memcpyConst(header->handshake.auth.bytes,
                         &auth.challenge,
                         sizeof(union Headers_AuthChallenge));
    }
    header->handshake.auth.challenge.type = wrapper->authType;

    // Packet authentication option is deprecated, it must always be enabled.
    Headers_setPacketAuthRequired(&header->handshake.auth, 1);

    // This is a special packet which the user should never see.
    Headers_setSetupPacket(&header->handshake.auth, setupMessage);

    // Set the session state
    uint32_t sessionState_be = Endian_hostToBigEndian32(wrapper->nextNonce);
    header->nonce = sessionState_be;

    if (wrapper->nextNonce == 0 || wrapper->nextNonce == 2) {
        // If we're sending a hello or a key
        // Here we make up a temp keypair
        Random_bytes(wrapper->context->rand, wrapper->ourTempPrivKey, 32);
        crypto_scalarmult_curve25519_base(wrapper->ourTempPubKey, wrapper->ourTempPrivKey);

        #ifdef Log_KEYS
            uint8_t tempPrivateKeyHex[65];
            Hex_encode(tempPrivateKeyHex, 65, wrapper->ourTempPrivKey, 32);
            uint8_t tempPubKeyHex[65];
            Hex_encode(tempPubKeyHex, 65, header->handshake.encryptedTempKey, 32);
            Log_keys(wrapper->context->logger, "Generating temporary keypair\n"
                                                "    myTempPrivateKey=%s\n"
                                                "     myTempPublicKey=%s\n",
                      tempPrivateKeyHex, tempPubKeyHex);
        #endif
    }

    Bits_memcpyConst(header->handshake.encryptedTempKey, wrapper->ourTempPubKey, 32);

    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(wrapper->context->logger,
                  "Wrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    cryptoAuthDebug(wrapper, "Sending %s%s packet",
                    ((wrapper->nextNonce & 1) ? "repeat " : ""),
                    ((wrapper->nextNonce < 2) ? "hello" : "key"));

    uint8_t sharedSecret[32];
    if (wrapper->nextNonce < 2) {
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);

        wrapper->isInitiator = true;

        Assert_true(wrapper->nextNonce <= 1);
        wrapper->nextNonce = 1;
    } else {
        // Handshake2
        // herTempPubKey was set by receiveMessage()
        Assert_ifParanoid(!Bits_isZero(wrapper->herTempPubKey, 32));
        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        wrapper->herTempPubKey,
                        passwordHash,
                        wrapper->context->logger);

        Assert_true(wrapper->nextNonce <= 3);
        wrapper->nextNonce = 3;

        #ifdef Log_KEYS
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, wrapper->herTempPubKey, 32);
            Log_keys(wrapper->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        #endif
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - Headers_CryptoAuth_SIZE, NULL);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    #ifdef Log_KEYS
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(wrapper->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, Headers_CryptoAuth_SIZE - 32 - 16, NULL);

    return wrapper->wrappedInterface->sendMessage(message, wrapper->wrappedInterface);
}
Ejemplo n.º 22
0
static Iface_DEFUN handlePing(struct Message* msg,
                              struct ControlHandler_pvt* ch,
                              uint64_t label,
                              uint8_t* labelStr,
                              uint16_t messageType_be)
{
    if (msg->length < handlePing_MIN_SIZE) {
        Log_info(ch->log, "DROP runt ping");
        return NULL;
    }

    struct Control* ctrl = (struct Control*) msg->bytes;
    Message_shift(msg, -Control_Header_SIZE, NULL);

    // Ping and keyPing share version location
    struct Control_Ping* ping = (struct Control_Ping*) msg->bytes;
    uint32_t herVersion = Endian_bigEndianToHost32(ping->version_be);
    if (!Version_isCompatible(Version_CURRENT_PROTOCOL, herVersion)) {
        Log_debug(ch->log, "DROP ping from incompatible version [%d]", herVersion);
        return NULL;
    }

    if (messageType_be == Control_KEYPING_be) {
        Log_debug(ch->log, "got switch keyPing from [%s]", labelStr);
        if (msg->length < Control_KeyPing_HEADER_SIZE) {
            // min keyPing size is longer
            Log_debug(ch->log, "DROP runt keyPing");
            return NULL;
        }
        if (msg->length > Control_KeyPing_MAX_SIZE) {
            Log_debug(ch->log, "DROP long keyPing");
            return NULL;
        }
        if (ping->magic != Control_KeyPing_MAGIC) {
            Log_debug(ch->log, "DROP keyPing (bad magic)");
            return NULL;
        }

        struct Control_KeyPing* keyPing = (struct Control_KeyPing*) msg->bytes;
        keyPing->magic = Control_KeyPong_MAGIC;
        ctrl->header.type_be = Control_KEYPONG_be;
        Bits_memcpy(keyPing->key, ch->myPublicKey, 32);

    } else if (messageType_be == Control_PING_be) {
        // Happens in benchmark.
        //Log_debug(ch->log, "got switch ping from [%s]", labelStr);
        if (ping->magic != Control_Ping_MAGIC) {
            Log_debug(ch->log, "DROP ping (bad magic)");
            return NULL;
        }
        ping->magic = Control_Pong_MAGIC;
        ctrl->header.type_be = Control_PONG_be;

    } else {
        Assert_failure("2+2=5");
    }

    ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);

    Message_shift(msg, Control_Header_SIZE, NULL);

    ctrl->header.checksum_be = 0;
    ctrl->header.checksum_be = Checksum_engine(msg->bytes, msg->length);

    Message_shift(msg, RouteHeader_SIZE, NULL);

    struct RouteHeader* routeHeader = (struct RouteHeader*) msg->bytes;
    Bits_memset(routeHeader, 0, RouteHeader_SIZE);
    SwitchHeader_setVersion(&routeHeader->sh, SwitchHeader_CURRENT_VERSION);
    routeHeader->sh.label_be = Endian_hostToBigEndian64(label);
    routeHeader->flags |= RouteHeader_flags_CTRLMSG;

    return Iface_next(&ch->pub.coreIf, msg);
}
Ejemplo n.º 23
0
static int handleFromPathfinder(enum PFChan_Pathfinder ev,
                                struct Message* msg,
                                struct EventEmitter_pvt* ee,
                                struct Pathfinder* pf)
{
    switch (ev) {
        default: return false;

        case PFChan_Pathfinder_CONNECT: {
            struct PFChan_Pathfinder_Connect connect;
            Message_shift(msg, -8, NULL);
            Message_pop(msg, &connect, PFChan_Pathfinder_Connect_SIZE, NULL);
            pf->superiority = Endian_bigEndianToHost32(connect.superiority_be);
            pf->version = Endian_bigEndianToHost32(connect.version_be);
            Bits_memcpy(pf->userAgent, connect.userAgent, 64);
            pf->state = Pathfinder_state_CONNECTED;

            struct PFChan_Core_Connect resp;
            resp.version_be = Endian_bigEndianToHost32(Version_CURRENT_PROTOCOL);
            resp.pathfinderId_be = Endian_hostToBigEndian32(pf->pathfinderId);
            Bits_memcpy(resp.publicKey, ee->publicKey, 32);
            Message_push(msg, &resp, PFChan_Core_Connect_SIZE, NULL);
            Message_push32(msg, PFChan_Core_CONNECT, NULL);
            struct Message* sendMsg = Message_clone(msg, msg->alloc);
            Iface_CALL(sendToPathfinder, sendMsg, pf);
            break;
        }
        case PFChan_Pathfinder_SUPERIORITY: {
            Message_shift(msg, -8, NULL);
            pf->superiority = Message_pop32(msg, NULL);
            struct Message* resp = pathfinderMsg(PFChan_Core_PATHFINDER, pf, msg->alloc);
            Iface_CALL(incomingFromCore, resp, &ee->trickIf);
            break;
        }

        case PFChan_Pathfinder_PING: {
            struct Message* sendMsg = Message_clone(msg, msg->alloc);
            Iface_send(&pf->iface, sendMsg);
            break;
        }
        case PFChan_Pathfinder_PONG: {
            Message_shift(msg, -8, NULL);
            uint32_t cookie = Message_pop32(msg, NULL);
            uint32_t count = Message_pop32(msg, NULL);
            if (cookie != PING_MAGIC || count > pf->bytesSinceLastPing) {
                pf->state = Pathfinder_state_ERROR;
                struct Message* resp = pathfinderMsg(PFChan_Core_PATHFINDER_GONE, pf, msg->alloc);
                Iface_CALL(incomingFromCore, resp, &ee->trickIf);
            } else {
                pf->bytesSinceLastPing -= count;
            }
            break;
        }
        case PFChan_Pathfinder_PATHFINDERS: {
            for (int i = 0; i < ee->pathfinders->length; i++) {
                struct Pathfinder* xpf = ArrayList_Pathfinders_get(ee->pathfinders, i);
                if (!xpf || xpf->state != Pathfinder_state_CONNECTED) { continue; }
                struct Allocator* alloc = Allocator_child(msg->alloc);
                struct Message* resp = pathfinderMsg(PFChan_Core_PATHFINDER, pf, alloc);
                Iface_CALL(sendToPathfinder, resp, pf);
                Allocator_free(alloc);
            }
            break;
        }
    }
    return true;
}
Ejemplo n.º 24
0
static inline int incomingFromRouter(struct Message* message,
                                     struct Ducttape_MessageHeader* dtHeader,
                                     struct SessionManager_Session* session,
                                     struct Ducttape_pvt* context)
{
    uint8_t* pubKey = CryptoAuth_getHerPublicKey(&session->iface);
    if (!validEncryptedIP6(message)) {
        // Not valid cjdns IPv6, we'll try it as an IPv4 or ICANN-IPv6 packet
        // and check if we have an agreement with the node who sent it.
        Message_shift(message, IpTunnel_PacketInfoHeader_SIZE);
        struct IpTunnel_PacketInfoHeader* header =
            (struct IpTunnel_PacketInfoHeader*) message->bytes;

        uint8_t* addr = session->ip6;
        Bits_memcpyConst(header->nodeIp6Addr, addr, 16);
        Bits_memcpyConst(header->nodeKey, pubKey, 32);

        struct Interface* ipTun = &context->ipTunnel->nodeInterface;
        return ipTun->sendMessage(message, ipTun);
    }

    struct Address srcAddr = {
        .path = Endian_bigEndianToHost64(dtHeader->switchHeader->label_be)
    };
    Bits_memcpyConst(srcAddr.key, pubKey, 32);

    //Log_debug(context->logger, "Got message from router.\n");
    int ret = core(message, dtHeader, session, context);

    struct Node* n = RouterModule_getNode(srcAddr.path, context->routerModule);
    if (!n) {
        Address_getPrefix(&srcAddr);
        RouterModule_addNode(context->routerModule, &srcAddr, session->version);
    } else {
        n->reach += 1;
        RouterModule_updateReach(n, context->routerModule);
    }

    return ret;
}


static uint8_t incomingFromCryptoAuth(struct Message* message, struct Interface* iface)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->receiverContext);
    struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, false);
    enum Ducttape_SessionLayer layer = dtHeader->layer;
    dtHeader->layer = Ducttape_SessionLayer_INVALID;
    struct SessionManager_Session* session =
        SessionManager_sessionForHandle(dtHeader->receiveHandle, context->sm);

    if (!session) {
        // This should never happen but there's no strong preventitive.
        Log_info(context->logger, "SESSION DISAPPEARED!");
        return 0;
    }

    // If the packet came from a new session, put the send handle in the session.
    if (CryptoAuth_getState(iface) < CryptoAuth_ESTABLISHED) {
        // If this is true then the incoming message is definitely a handshake.
        if (message->length < 4) {
            debugHandles0(context->logger, session, "runt");
            return Error_INVALID;
        }
        if (layer == Ducttape_SessionLayer_OUTER) {
            #ifdef Version_2_COMPAT
            if (dtHeader->currentSessionVersion >= 3) {
                session->version = dtHeader->currentSessionVersion;
            #endif
                Message_pop(message, &session->sendHandle_be, 4);
            #ifdef Version_2_COMPAT
            } else {
                session->sendHandle_be = dtHeader->currentSessionSendHandle_be;
            }
            #endif
        } else {
            // inner layer, always grab the handle
            Message_pop(message, &session->sendHandle_be, 4);
            debugHandles0(context->logger, session, "New session, incoming layer3");
        }
    }

    switch (layer) {
        case Ducttape_SessionLayer_OUTER:
            return incomingFromRouter(message, dtHeader, session, context);
        case Ducttape_SessionLayer_INNER:
            return incomingForMe(message, dtHeader, session, context,
                                 CryptoAuth_getHerPublicKey(iface));
        default:
            Assert_always(false);
    }
    // never reached.
    return 0;
}

static uint8_t outgoingFromCryptoAuth(struct Message* message, struct Interface* iface)
{
    struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->senderContext);
    struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, false);
    struct SessionManager_Session* session =
        SessionManager_sessionForHandle(dtHeader->receiveHandle, context->sm);

    enum Ducttape_SessionLayer layer = dtHeader->layer;
    dtHeader->layer = Ducttape_SessionLayer_INVALID;

    if (!session) {
        // This should never happen but there's no strong preventitive.
        Log_info(context->logger, "SESSION DISAPPEARED!");
        return 0;
    }

    if (layer == Ducttape_SessionLayer_OUTER) {
        return sendToSwitch(message, dtHeader, session, context);
    } else if (layer == Ducttape_SessionLayer_INNER) {
        Log_debug(context->logger, "Sending layer3 message");
        return outgoingFromMe(message, dtHeader, session, context);
    } else {
        Assert_true(0);
    }
}

/**
 * Handle an incoming control message from a switch.
 *
 * @param context the ducttape context.
 * @param message the control message, this should be alligned on the beginning of the content,
 *                that is to say, after the end of the switch header.
 * @param switchHeader the header.
 * @param switchIf the interface which leads to the switch.
 */
static uint8_t handleControlMessage(struct Ducttape_pvt* context,
                                    struct Message* message,
                                    struct Headers_SwitchHeader* switchHeader,
                                    struct Interface* switchIf)
{
    uint8_t labelStr[20];
    uint64_t label = Endian_bigEndianToHost64(switchHeader->label_be);
    AddrTools_printPath(labelStr, label);
    if (message->length < Control_HEADER_SIZE) {
        Log_info(context->logger, "dropped runt ctrl packet from [%s]", labelStr);
        return Error_NONE;
    }
    struct Control* ctrl = (struct Control*) message->bytes;

    if (Checksum_engine(message->bytes, message->length)) {
        Log_info(context->logger, "ctrl packet from [%s] with invalid checksum.", labelStr);
        return Error_NONE;
    }

    bool pong = false;
    if (ctrl->type_be == Control_ERROR_be) {
        if (message->length < Control_Error_MIN_SIZE) {
            Log_info(context->logger, "dropped runt error packet from [%s]", labelStr);
            return Error_NONE;
        }

        uint64_t path = Endian_bigEndianToHost64(switchHeader->label_be);
        RouterModule_brokenPath(path, context->routerModule);

        uint8_t causeType = Headers_getMessageType(&ctrl->content.error.cause);
        if (causeType == Headers_SwitchHeader_TYPE_CONTROL) {
            if (message->length < Control_Error_MIN_SIZE + Control_HEADER_SIZE) {
                Log_info(context->logger,
                          "error packet from [%s] containing runt cause packet",
                          labelStr);
                return Error_NONE;
            }
            struct Control* causeCtrl = (struct Control*) &(&ctrl->content.error.cause)[1];
            if (causeCtrl->type_be != Control_PING_be) {
                Log_info(context->logger,
                          "error packet from [%s] caused by [%s] packet ([%u])",
                          labelStr,
                          Control_typeString(causeCtrl->type_be),
                          Endian_bigEndianToHost16(causeCtrl->type_be));
            } else {
                if (LabelSplicer_isOneHop(label)
                    && ctrl->content.error.errorType_be
                        == Endian_hostToBigEndian32(Error_UNDELIVERABLE))
                {
                    // this is our own InterfaceController complaining
                    // because the node isn't responding to pings.
                    return Error_NONE;
                }
                Log_debug(context->logger,
                           "error packet from [%s] in response to ping, err [%u], length: [%u].",
                           labelStr,
                           Endian_bigEndianToHost32(ctrl->content.error.errorType_be),
                           message->length);
                // errors resulting from pings are forwarded back to the pinger.
                pong = true;
            }
        } else if (causeType != Headers_SwitchHeader_TYPE_DATA) {
            Log_info(context->logger,
                      "error packet from [%s] containing cause of unknown type [%u]",
                      labelStr, causeType);
        } else {
            Log_info(context->logger,
                      "error packet from [%s], error type [%u]",
                      labelStr,
                      Endian_bigEndianToHost32(ctrl->content.error.errorType_be));
        }
    } else if (ctrl->type_be == Control_PONG_be) {
        pong = true;
    } else if (ctrl->type_be == Control_PING_be) {

        Message_shift(message, -Control_HEADER_SIZE);

        if (message->length < Control_Ping_MIN_SIZE) {
            Log_info(context->logger, "dropped runt ping");
            return Error_INVALID;
        }
        struct Control_Ping* ping = (struct Control_Ping*) message->bytes;
        ping->magic = Control_Pong_MAGIC;
        ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL);
        Message_shift(message, Control_HEADER_SIZE);

        ctrl->type_be = Control_PONG_be;
        ctrl->checksum_be = 0;
        ctrl->checksum_be = Checksum_engine(message->bytes, message->length);
        Message_shift(message, Headers_SwitchHeader_SIZE);
        Log_info(context->logger, "got switch ping from [%s]", labelStr);
        switchIf->receiveMessage(message, switchIf);
    } else {
        Log_info(context->logger,
                  "control packet of unknown type from [%s], type [%d]",
                  labelStr, Endian_bigEndianToHost16(ctrl->type_be));
    }

    if (pong && context->pub.switchPingerIf.receiveMessage) {
        // Shift back over the header
        Message_shift(message, Headers_SwitchHeader_SIZE);
        context->pub.switchPingerIf.receiveMessage(
            message, &context->pub.switchPingerIf);
    }
    return Error_NONE;
}
Ejemplo n.º 25
0
static void encryptHandshake(struct Message* message,
                             struct CryptoAuth_Session_pvt* session,
                             int setupMessage)
{
    Message_shift(message, sizeof(union CryptoHeader), NULL);

    union CryptoHeader* header = (union CryptoHeader*) message->bytes;

    // garbage the auth challenge and set the nonce which follows it
    Random_bytes(session->context->rand, (uint8_t*) &header->handshake.auth,
                 sizeof(union CryptoHeader_Challenge) + 24);

    // set the permanent key
    Bits_memcpyConst(&header->handshake.publicKey, session->context->pub.publicKey, 32);

    Assert_true(knowHerKey(session));

    uint8_t calculatedIp6[16];
    AddressCalc_addressForPublicKey(calculatedIp6, session->pub.herPublicKey);
    if (!Bits_isZero(session->pub.herIp6, 16)) {
        // If someone starts a CA session and then discovers the key later and memcpy's it into the
        // result of getHerPublicKey() then we want to make sure they didn't memcpy in an invalid
        // key.
        Assert_true(!Bits_memcmp(session->pub.herIp6, calculatedIp6, 16));
    }

    // Password auth
    uint8_t* passwordHash = NULL;
    uint8_t passwordHashStore[32];
    if (session->password != NULL) {
        hashPassword(passwordHashStore,
                     &header->handshake.auth,
                     session->login,
                     session->password,
                     session->authType);
        passwordHash = passwordHashStore;
    } else {
        header->handshake.auth.challenge.type = session->authType;
        header->handshake.auth.challenge.additional = 0;
    }

    // Set the session state
    header->nonce = Endian_hostToBigEndian32(session->nextNonce);

    if (session->nextNonce == 0 || session->nextNonce == 2) {
        // If we're sending a hello or a key
        // Here we make up a temp keypair
        Random_bytes(session->context->rand, session->ourTempPrivKey, 32);
        crypto_scalarmult_curve25519_base(session->ourTempPubKey, session->ourTempPrivKey);

        if (Defined(Log_KEYS)) {
            uint8_t tempPrivateKeyHex[65];
            Hex_encode(tempPrivateKeyHex, 65, session->ourTempPrivKey, 32);
            uint8_t tempPubKeyHex[65];
            Hex_encode(tempPubKeyHex, 65, session->ourTempPubKey, 32);
            Log_keys(session->context->logger, "Generating temporary keypair\n"
                                                "    myTempPrivateKey=%s\n"
                                                "     myTempPublicKey=%s\n",
                      tempPrivateKeyHex, tempPubKeyHex);
        }
    }

    Bits_memcpyConst(header->handshake.encryptedTempKey, session->ourTempPubKey, 32);

    if (Defined(Log_KEYS)) {
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, header->handshake.encryptedTempKey, 32);
        Log_keys(session->context->logger,
                  "Wrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    }

    cryptoAuthDebug(session, "Sending %s%s packet",
                    ((session->nextNonce & 1) ? "repeat " : ""),
                    ((session->nextNonce < 2) ? "hello" : "key"));

    uint8_t sharedSecret[32];
    if (session->nextNonce < 2) {
        getSharedSecret(sharedSecret,
                        session->context->privateKey,
                        session->pub.herPublicKey,
                        passwordHash,
                        session->context->logger);

        session->isInitiator = true;

        Assert_true(session->nextNonce <= 1);
        session->nextNonce = 1;
    } else {
        // Handshake2
        // herTempPubKey was set by decryptHandshake()
        Assert_ifParanoid(!Bits_isZero(session->herTempPubKey, 32));
        getSharedSecret(sharedSecret,
                        session->context->privateKey,
                        session->herTempPubKey,
                        passwordHash,
                        session->context->logger);

        Assert_true(session->nextNonce <= 3);
        session->nextNonce = 3;

        if (Defined(Log_KEYS)) {
            uint8_t tempKeyHex[65];
            Hex_encode(tempKeyHex, 65, session->herTempPubKey, 32);
            Log_keys(session->context->logger,
                      "Using their temp public key:\n"
                      "    %s\n",
                      tempKeyHex);
        }
    }

    // Shift message over the encryptedTempKey field.
    Message_shift(message, 32 - CryptoHeader_SIZE, NULL);

    encryptRndNonce(header->handshake.nonce, message, sharedSecret);

    if (Defined(Log_KEYS)) {
        uint8_t sharedSecretHex[65];
        printHexKey(sharedSecretHex, sharedSecret);
        uint8_t nonceHex[49];
        Hex_encode(nonceHex, 49, header->handshake.nonce, 24);
        uint8_t cipherHex[65];
        printHexKey(cipherHex, message->bytes);
        Log_keys(session->context->logger,
                  "Encrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    }

    // Shift it back -- encryptRndNonce adds 16 bytes of authenticator.
    Message_shift(message, CryptoHeader_SIZE - 32 - 16, NULL);
}
Ejemplo n.º 26
0
            .version = Version_DEFAULT_ASSUMPTION,

            // 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] + FIRST_HANDLE);
        Bits_memcpyConst(sp->ip6, lookupKey, 16);
        return sp;
    } else {
        // Interface already exists, set the time of last message to "now".
        sm->ifaceMap.values[ifaceIndex].lastMessageTime = Time_currentTimeSeconds(sm->eventBase);
        uint8_t* herPubKey = CryptoAuth_getHerPublicKey(&sm->ifaceMap.values[ifaceIndex].iface);
        if (Bits_isZero(herPubKey, 32) && cryptoKey) {
            Bits_memcpyConst(herPubKey, cryptoKey, 32);
        }
    }

    return &sm->ifaceMap.values[ifaceIndex];
}

struct SessionManager_Session* SessionManager_sessionForHandle(uint32_t handle,