Example #1
0
static void showConn(struct IpTunnel_Connection* conn,
                     String* txid,
                     struct Admin* admin,
                     struct Allocator* alloc)
{
    Dict* d = Dict_new(alloc);

    if (!Bits_isZero(conn->connectionIp6, 16)) {
        struct Sockaddr* addr = Sockaddr_clone(Sockaddr_LOOPBACK6, alloc);
        uint8_t* address;
        Assert_true(16 == Sockaddr_getAddress(addr, &address));
        Bits_memcpy(address, conn->connectionIp6, 16);
        char* printedAddr = Sockaddr_print(addr, alloc);
        Dict_putString(d, String_CONST("ip6Address"), String_CONST(printedAddr), alloc);
        Dict_putInt(d, String_CONST("ip6Prefix"), conn->connectionIp6Prefix, alloc);
    }

    if (!Bits_isZero(conn->connectionIp4, 4)) {
        struct Sockaddr* addr = Sockaddr_clone(Sockaddr_LOOPBACK, alloc);
        uint8_t* address;
        Assert_true(4 == Sockaddr_getAddress(addr, &address));
        Bits_memcpy(address, conn->connectionIp4, 4);
        char* printedAddr = Sockaddr_print(addr, alloc);
        Dict_putString(d, String_CONST("ip4Address"), String_CONST(printedAddr), alloc);
        Dict_putInt(d, String_CONST("ip4Prefix"), conn->connectionIp4Prefix, alloc);
    }

    Dict_putString(d, String_CONST("key"),
                      Key_stringify(conn->routeHeader.publicKey, alloc), alloc);
    Dict_putInt(d, String_CONST("outgoing"), (conn->isOutgoing) ? 1 : 0, alloc);
    Dict_putString(d, String_CONST("error"), String_CONST("none"), alloc);

    Admin_sendMessage(d, txid, admin);
}
Example #2
0
/** @return 0 on success, -1 otherwise. */
int CryptoAuth_encrypt(struct CryptoAuth_Session* sessionPub, struct Message* msg)
{
    struct CryptoAuth_Session_pvt* session =
        Identity_check((struct CryptoAuth_Session_pvt*) sessionPub);

    // 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.
    // this will reset the session if it has timed out.
    resetIfTimeout(session);

    // If the nonce wraps, start over.
    if (session->nextNonce >= 0xfffffff0) {
        reset(session);
    }

    Assert_true(!((uintptr_t)msg->bytes % 4) || !"alignment fault");

    // 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 (session->nextNonce < 5) {
        if (session->nextNonce < 4) {
            encryptHandshake(msg, session, 0);
            return 0;
        } else {
            cryptoAuthDebug0(session, "Doing final step to send message. nonce=4");
            Assert_ifParanoid(!Bits_isZero(session->ourTempPrivKey, 32));
            Assert_ifParanoid(!Bits_isZero(session->herTempPubKey, 32));
            getSharedSecret(session->sharedSecret,
                            session->ourTempPrivKey,
                            session->herTempPubKey,
                            NULL,
                            session->context->logger);
        }
    }

    Assert_true(msg->length > 0 && "Empty packet during handshake");
    Assert_true(msg->padding >= 36 || !"not enough padding");

    encrypt(session->nextNonce, msg, session->sharedSecret, session->isInitiator);

    Message_push32(msg, session->nextNonce, NULL);
    session->nextNonce++;
    return 0;
}
Example #3
0
static void checkBytes(struct Random* rand, int alignment, int length)
{
    Assert_true(length < 128 && alignment < 8);

    uint64_t buff64[20] = {0};
    uint8_t* buff = (uint8_t*) (&buff64[1]);
    buff += alignment;

    // Check for bytes which are always the same, a few \0s are ok
    // but if every cycle they are always zero then there's a bug.
    uint8_t oldBuff[128] = {0};
    // Preload into the output buff so alignment is same.
    Random_bytes(rand, buff, length);
    Bits_memcpy(oldBuff, buff, length);

    uint8_t sameAsOld[128];
    Bits_memset(sameAsOld, 0xff, 128);

    // Check for bytes which are the same as other bytes every time.
    // if buff[3] always equals buff[8] then there's a bug.
    uint8_t sameBytes[128+128];
    Bits_memset(sameBytes, 0xff, 128+128);

    for (int i = 0; i < 100; i++) {
        Random_bytes(rand, buff, length);

        for (int j = 0; j < length; j++) {
            for (int jj = j; jj < length; jj++) {
                sameBytes[j+jj] &= (jj != j && buff[j] == buff[jj]);
            }
        }

        for (int j = 0; j < length; j++) {
            sameAsOld[j] &= (oldBuff[i] == buff[i]);
        }

        // Check that the function did not write after or before the buffer.
        uint8_t* origBuff = (uint8_t*) (buff64);
        Assert_true(Bits_isZero(origBuff, 8+alignment));
        Assert_true(Bits_isZero(buff+length, 8));
    }

    for (int i = 0; i < length+length-1; i++) {
        Assert_true(!sameBytes[i]);
    }
    for (int i = 0; i < length; i++) {
        Assert_true(!sameAsOld[i]);
    }
}
Example #4
0
static void adminPingOnResponse(struct SwitchPinger_Response* resp, void* vping)
{
    struct Allocator* pingAlloc = resp->ping->pingAlloc;
    struct Ping* ping = vping;

    Dict* rd = Dict_new(pingAlloc);

    if (resp->res == SwitchPinger_Result_LABEL_MISMATCH) {
        uint8_t path[20] = {0};
        AddrTools_printPath(path, resp->label);
        String* pathStr = String_new(path, pingAlloc);
        Dict_putString(rd, String_CONST("rpath"), pathStr, pingAlloc);
    }

    Dict_putInt(rd, String_CONST("version"), resp->version, pingAlloc);
    Dict_putInt(rd, String_CONST("ms"), resp->milliseconds, pingAlloc);
    Dict_putString(rd, String_CONST("result"), SwitchPinger_resultString(resp->res), pingAlloc);
    Dict_putString(rd, String_CONST("path"), ping->path, pingAlloc);
    if (resp->data) {
        Dict_putString(rd, String_CONST("data"), resp->data, pingAlloc);
    }

    if (!Bits_isZero(resp->key, 32)) {
        Dict_putString(rd, String_CONST("key"), Key_stringify(resp->key, pingAlloc), pingAlloc);
    }

    Admin_sendMessage(rd, ping->txid, ping->context->admin);
}
static int get(struct RandomSeed* randomSeed, uint64_t output[8])
{
    int mib[] = { CTL_KERN, KERN_ARND };
    Bits_memset(output, 0, 64);
    size_t len = 64;
    if (sysctl(mib, 2, output, &len, NULL, 0) == -1) {
        // TOR/Libevent retry this 4 bytes at a time if it fails initially.
        size_t four = 4;
        int tries = 0;
        union {
            uint64_t longs[8];
            uint32_t ints[16];
        } num;
        for (int i = 0; i < 16; i++) {
            if (sysctl(mib, 2, &num.ints[i], &four, NULL, 0) == -1) {
                return -1;
            }
            if (num.ints[i] == 0) {
                i--;
                if (++tries > MAX_TRIES) {
                    return -1;
                }
            }
        }
    }
    return Bits_isZero(output, 64) ? -1 : 0;
}
Example #6
0
static uint8_t responseWithIpCallback(struct Message* message, struct Interface* iface)
{
    struct IpTunnel_PacketInfoHeader* pi = (struct IpTunnel_PacketInfoHeader*) message->bytes;
    Assert_true(!Bits_memcmp(nodeCjdnsIp6, pi->nodeIp6Addr, 16));
    Assert_true(!Bits_memcmp(fakePubKey, pi->nodeKey, 32));

    Message_shift(message, -IpTunnel_PacketInfoHeader_SIZE, NULL);
    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
    Assert_true(Headers_getIpVersion(ip) == 6);
    uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be);
    Assert_true(length + Headers_IP6Header_SIZE == message->length);
    Assert_true(ip->nextHeader == 17);
    Assert_true(Bits_isZero(ip->sourceAddr, 32));

    Message_shift(message, -Headers_IP6Header_SIZE, NULL);
    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;
    Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length));

    Assert_true(uh->srcPort_be == 0);
    Assert_true(uh->destPort_be == 0);
    Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length);

    Message_shift(message, -Headers_UDPHeader_SIZE, NULL);
    char* expectedResponse =
        "d"
          "9:addresses" "d"
            "3:ip6" "16:\xfd\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
          "e"
          "4:txid" "4:abcd"
        "e";
    Assert_true(message->length == (int32_t) CString_strlen(expectedResponse));
    Assert_true(!Bits_memcmp(message->bytes, expectedResponse, message->length));
    called = 1;
    return 0;
}
Example #7
0
/**
 * Incoming message from someone we don't know, maybe someone responding to a beacon?
 * expects: [ struct LLAddress ][ content ]
 */
static Iface_DEFUN handleUnexpectedIncoming(struct Message* msg,
                                            struct InterfaceController_Iface_pvt* ici)
{
    struct InterfaceController_pvt* ic = ici->ic;

    struct Sockaddr* lladdr = (struct Sockaddr*) msg->bytes;
    Message_shift(msg, -lladdr->addrLen, NULL);
    if (msg->length < CryptoHeader_SIZE) {
        return NULL;
    }
    struct Allocator* epAlloc = Allocator_child(ici->alloc);
    lladdr = Sockaddr_clone(lladdr, epAlloc);

    Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault");

    struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1);
    Identity_set(ep);
    ep->alloc = epAlloc;
    ep->ici = ici;
    ep->lladdr = lladdr;
    ep->alloc = epAlloc;
    ep->peerLink = PeerLink_new(ic->eventBase, epAlloc);
    struct CryptoHeader* ch = (struct CryptoHeader*) msg->bytes;
    ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, ch->publicKey, true, "outer");
    if (CryptoAuth_decrypt(ep->caSession, msg)) {
        // If the first message is a dud, drop all state for this peer.
        // probably some random crap that wandered in the socket.
        Allocator_free(epAlloc);
        return NULL;
    }
    Assert_true(!Bits_isZero(ep->caSession->herPublicKey, 32));
    Assert_true(Map_EndpointsBySockaddr_indexForKey(&lladdr, &ici->peerMap) == -1);
    int index = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap);
    Assert_true(index >= 0);
    ep->handle = ici->peerMap.handles[index];
    Allocator_onFree(epAlloc, closeInterface, ep);
    ep->state = InterfaceController_PeerState_UNAUTHENTICATED;
    ep->isIncomingConnection = true;
    ep->switchIf.send = sendFromSwitch;

    if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) {
        Log_debug(ic->logger, "handleUnexpectedIncoming() SwitchCore out of space");
        Allocator_free(epAlloc);
        return NULL;
    }

    // We want the node to immedietly be pinged but we don't want it to appear unresponsive because
    // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to
    // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node".
    ep->timeOfLastMessage =
        Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1;

    Bits_memcpy(ep->addr.key, ep->caSession->herPublicKey, 32);
    Bits_memcpy(ep->addr.ip6.bytes, ep->caSession->herIp6, 16);
    Log_info(ic->logger, "Added peer [%s] from incoming message",
        Address_toString(&ep->addr, msg->alloc)->bytes);

    return receivedPostCryptoAuth(msg, ep, ic);
}
Example #8
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.
    // this will reset the session if it has timed out.
    CryptoAuth_getState(interface);

    // If the nonce wraps, start over.
    if (wrapper->nextNonce >= 0xfffffff0) {
        reset(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, 0);
        } else {
            cryptoAuthDebug0(wrapper, "Doing final step to send message. nonce=4");
            Assert_true(!Bits_isZero(wrapper->ourTempPrivKey, 32));
            Assert_true(!Bits_isZero(wrapper->herTempPubKey, 32));
            getSharedSecret(wrapper->sharedSecret,
                            wrapper->ourTempPrivKey,
                            wrapper->herTempPubKey,
                            NULL,
                            wrapper->context->logger);
        }
    }

    Assert_true(message->length > 0 && "Empty packet during handshake");

    return encryptMessage(message, wrapper);
}
Example #9
0
static void check(struct SessionManager* sm, int mapIndex)
{
    Assert_true(sm->ifaceMap.keys[mapIndex].bytes[0] == 0xfc);
    uint8_t* herPubKey = CryptoAuth_getHerPublicKey(sm->ifaceMap.values[mapIndex]->pub.internal);
    if (!Bits_isZero(herPubKey, 32)) {
        uint8_t ip6[16];
        AddressCalc_addressForPublicKey(ip6, herPubKey);
        Assert_true(!Bits_memcmp(&sm->ifaceMap.keys[mapIndex], ip6, 16));
    }
}
static int getUUID(uint64_t output[2])
{
    int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
    size_t sixteen = 16;

    Bits_memset(output, 0, 16);
    if (sysctl(mib, 3, output, &sixteen, NULL, 0)
        || Bits_isZero(output, 16))
    {
        return -1;
    }
    return 0;
}
Example #11
0
static void showConn(struct IpTunnel_Connection* conn, String* txid, struct Admin* admin)
{
    struct Allocator* alloc;
    BufferAllocator_STACK(alloc, 1024);
    Dict* d = Dict_new(alloc);

    char ip6[40];
    if (!Bits_isZero(conn->connectionIp6, 16)) {
        Assert_always(evutil_inet_ntop(AF_INET6, conn->connectionIp6, ip6, 40));
        Dict_putString(d, String_CONST("ip6Address"), String_CONST(ip6), alloc);
    }

    char ip4[16];
    if (!Bits_isZero(conn->connectionIp4, 4)) {
        Assert_always(evutil_inet_ntop(AF_INET, conn->connectionIp4, ip4, 16));
        Dict_putString(d, String_CONST("ip4Address"), String_CONST(ip4), alloc);
    }

    Dict_putString(d, String_CONST("key"), Key_stringify(conn->header.nodeKey, alloc), alloc);
    Dict_putInt(d, String_CONST("outgoing"), conn->isOutgoing, alloc);

    Admin_sendMessage(d, txid, admin);
}
Example #12
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;
}
static int get(struct RandomSeed* randomSeed, uint64_t output[8])
{

#ifdef SYS_getrandom
    // Try using getrandom instead sysctl as with systems with getrandom
    // sysctl is probably alrady deprecated and possibly disabled.
    Bits_memset(output, 0, 64); // Just make sure that it is zero all along.

    long ret = syscall(SYS_getrandom, output, 64, 0);
    if (ret == 64 && !Bits_isZero(output, 64)) {
        return 0;
    }
#endif
    if (getUUID(output) || getUUID(output+2) || getUUID(output+4) || getUUID(output+6)) {
        return -1;
    }
    return 0;
}
Example #14
0
static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* external)
{
    struct TAPWrapper_pvt* tw = Identity_containerOf(external, struct TAPWrapper_pvt, external);

    if (msg->length < Ethernet_SIZE-2) {
        Log_debug(tw->log, "runt");
        return 0;
    }

    // wacky 14 byte headers, back off into outer-space to create the padding...
    Message_shift(msg, 2, NULL);

    struct Ethernet eth;
    Message_pop(msg, &eth, sizeof(struct Ethernet), NULL);

    // Not for us and not multicast...
    if (Bits_memcmp(eth.destAddr, TAPWrapper_LOCAL_MAC, Ethernet_ADDRLEN)
        && !(eth.destAddr[0] & 0x01))
    {
        if (Defined(Log_DEBUG)) {
            uint8_t printedMac[18];
            AddrTools_printMac(printedMac, eth.destAddr);
            Log_debug(tw->log, "Packet destine for unknown ethernet MAC [%s]", printedMac);
        }
        //return 0;
    }

    if (Bits_memcmp(eth.srcAddr, tw->pub.peerAddress, Ethernet_ADDRLEN)) {
        if (Bits_isZero(tw->pub.peerAddress, Ethernet_ADDRLEN)) {
            Bits_memcpy(tw->pub.peerAddress, eth.srcAddr, Ethernet_ADDRLEN);
        } else {
            #ifdef Log_DEBUG
                uint8_t printedMac[18];
                AddrTools_printMac(printedMac, eth.srcAddr);
                Log_debug(tw->log, "DROP Packet with unexpected source MAC [%s]", printedMac);
            #endif
            return 0;
        }
    }
    TUNMessageType_push(msg, eth.ethertype, NULL);
    return Iface_next(&tw->pub.internal, msg);
}
Example #15
0
static Iface_DEFUN responseWithIpCallback(struct Message* message, struct Iface* iface)
{
    struct Context* ctx = Identity_check(((struct IfaceContext*)iface)->ctx);
    struct RouteHeader* rh = (struct RouteHeader*) message->bytes;
    Assert_true(!Bits_memcmp(ctx->ipv6, rh->ip6, 16));
    Assert_true(!Bits_memcmp(ctx->pubKey, rh->publicKey, 32));

    Message_shift(message, -(RouteHeader_SIZE + DataHeader_SIZE), NULL);
    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
    Assert_true(Headers_getIpVersion(ip) == 6);
    uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be);
    Assert_true(length + Headers_IP6Header_SIZE == message->length);
    Assert_true(ip->nextHeader == 17);
    Assert_true(Bits_isZero(ip->sourceAddr, 32));

    Message_shift(message, -Headers_IP6Header_SIZE, NULL);
    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;
    Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length));

    Assert_true(uh->srcPort_be == 0);
    Assert_true(uh->destPort_be == 0);
    Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length);

    Message_shift(message, -Headers_UDPHeader_SIZE, NULL);

    struct Allocator* alloc = Allocator_child(ctx->alloc);
    char* messageContent = Escape_getEscaped(message->bytes, message->length, alloc);
    char* expectedContent =
        Escape_getEscaped(ctx->expectedResponse->bytes, ctx->expectedResponse->len, alloc);
    Log_debug(ctx->log, "Response: [%s]", messageContent);
    Log_debug(ctx->log, "Expected: [%s]", expectedContent);
    Allocator_free(alloc);

    // We can't check that the message is an exact match because the padding depends on the
    // alignment of the output but we can make sure the right content is there...
    // Message should start with "d0000" (with some number of zeros)
    Assert_true((int)ctx->expectedResponse->len == message->length);
    Assert_true(!Bits_memcmp(message->bytes, ctx->expectedResponse->bytes, message->length));
    ctx->called |= 2;

    return NULL;
}
Example #16
0
static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* internal)
{
    struct TAPWrapper_pvt* tw = Identity_containerOf(internal, struct TAPWrapper_pvt, pub.internal);

    uint16_t etherType = TUNMessageType_pop(msg, NULL);
    struct Ethernet eth = { .ethertype = etherType };
    Bits_memcpyConst(eth.srcAddr, TAPWrapper_LOCAL_MAC, Ethernet_ADDRLEN);
    Bits_memcpyConst(eth.destAddr, tw->pub.peerAddress, Ethernet_ADDRLEN);
    if (Bits_isZero(tw->pub.peerAddress, Ethernet_ADDRLEN)) {
        Log_debug(tw->log, "DROP Packet because peers MAC is not yet known");
        return NULL;
    }

    Message_push(msg, &eth, sizeof(struct Ethernet), NULL);

    // struct Ethernet contains 2 bytes of padding at the beginning.
    Message_shift(msg, -2, NULL);

    return Iface_next(&tw->external, msg);
}
Example #17
0
static Iface_DEFUN responseWithIpCallback(struct Message* message, struct Iface* iface)
{
    struct RouteHeader* rh = (struct RouteHeader*) message->bytes;
    Assert_true(!Bits_memcmp(nodeCjdnsIp6, rh->ip6, 16));
    Assert_true(!Bits_memcmp(fakePubKey, rh->publicKey, 32));

    Message_shift(message, -(RouteHeader_SIZE + DataHeader_SIZE), NULL);
    struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes;
    Assert_true(Headers_getIpVersion(ip) == 6);
    uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be);
    Assert_true(length + Headers_IP6Header_SIZE == message->length);
    Assert_true(ip->nextHeader == 17);
    Assert_true(Bits_isZero(ip->sourceAddr, 32));

    Message_shift(message, -Headers_IP6Header_SIZE, NULL);
    struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes;
    Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length));

    Assert_true(uh->srcPort_be == 0);
    Assert_true(uh->destPort_be == 0);
    Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length);

    Message_shift(message, -Headers_UDPHeader_SIZE, NULL);

    // We can't check that the message is an exact match because the padding depends on the
    // alignment of the output but we can make sure the right content is there...
    // Message should start with "d0000" (with some number of zeros)
    char* expectedResponse =
        "9:addresses" "d"
            "3:ip6" "16:\xfd\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
            "9:ip6Prefix" "i128e"
          "e"
          "4:txid" "4:abcd"
        "e";
    Assert_true(message->length >= (int32_t) CString_strlen(expectedResponse));
    Assert_true(CString_strstr(message->bytes, expectedResponse));
    called |= 2;
    return 0;
}
Example #18
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);
}
Example #19
0
static uint8_t decryptHandshake(struct Wrapper* wrapper,
                                const uint32_t nonce,
                                struct Message* message,
                                union Headers_CryptoAuth* header)
{
    if (message->length < sizeof(union Headers_CryptoAuth)) {
        Log_debug(wrapper->context->logger, "Dropped runt packet\n");
        return Error_UNDERSIZE_MESSAGE;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (wrapper->nextNonce < 2 && nonce == UINT32_MAX && !wrapper->requireAuth) {
        // Reset without knowing key is allowed until state reaches 2.
        // this is because we don't know that the other end knows our key until we
        // have received a valid packet from them.
        // We can't allow the upper layer to see this message because it's not authenticated.
        if (!knowHerKey(wrapper)) {
            memcpy(wrapper->herPerminentPubKey, header->handshake.publicKey, 32);
        }
        Message_shift(message, -Headers_CryptoAuth_SIZE);
        message->length = 0;
        wrapper->nextNonce = 0;
        wrapper->user = NULL;
        // Send an empty response (to initiate the connection).
        encryptHandshake(message, wrapper);
        return Error_NONE;
    }

    void* user = NULL;
    uint8_t passwordHashStore[32];
    uint8_t* passwordHash = tryAuth(header, passwordHashStore, wrapper, &user);
    if (wrapper->requireAuth && !user) {
        Log_debug(wrapper->context->logger,
                  "Dropping message because auth was not given and is required.\n");
        return Error_AUTHENTICATION;
    }
    if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) {
        Log_debug(wrapper->context->logger,
                  "Dropping message because it contans an authenticator which is unrecognized.\n");
        return Error_AUTHENTICATION;
    }

    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = NULL;
    if (nonce < 2) {
        if (nonce == 0) {
            Log_debug1(wrapper->context->logger,
                       "Received a hello packet, using auth: %d\n",
                       (passwordHash != NULL));
        } else {
            Log_debug(wrapper->context->logger, "Received a repeat hello packet\n");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(wrapper) || wrapper->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            #ifdef Log_DEBUG
                if (Bits_isZero(header->handshake.publicKey, 32)) {
                    Log_debug(wrapper->context->logger, "Node sent public key of ZERO!\n");
                }
            #endif
        } else {
            herPermKey = wrapper->herPerminentPubKey;
            if (memcmp(header->handshake.publicKey, herPermKey, 32)) {
                Log_debug(wrapper->context->logger, "Packet contains different perminent key.\n");
                return Error_AUTHENTICATION;
            }
        }

        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        herPermKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            Log_debug(wrapper->context->logger, "Received a key packet\n");
        } else if (nonce == 3) {
            Log_debug(wrapper->context->logger, "Received a repeat key packet\n");
        } else {
            Log_debug1(wrapper->context->logger,
                       "Received a packet of unknown type! nonce=%u\n", nonce);
        }
        if (memcmp(header->handshake.publicKey, wrapper->herPerminentPubKey, 32)) {
            Log_debug(wrapper->context->logger, "Packet contains different perminent key.\n");
            return Error_AUTHENTICATION;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        wrapper->secret,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - Headers_CryptoAuth_SIZE);

    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,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret) != 0) {
        // just in case
        memset(header, 0, Headers_CryptoAuth_SIZE);
        Log_debug(wrapper->context->logger,
                  "Dropped message because authenticated decryption failed.\n");
        return Error_AUTHENTICATION;
    }

    wrapper->user = user;
    memcpy(wrapper->tempKey, header->handshake.encryptedTempKey, 32);

    #ifdef Log_DEBUG
        assert(!Bits_isZero(header->handshake.encryptedTempKey, 32));
    #endif
    #ifdef Log_KEYS
        uint8_t tempKeyHex[65];
        Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32);
        Log_keys1(wrapper->context->logger,
                  "Unwrapping temp public key:\n"
                  "    %s\n",
                  tempKeyHex);
    #endif

    Message_shift(message, -32);
    wrapper->nextNonce = nextNonce;
    if (nextNonce == 2) {
        wrapper->isInitiator = false;
    }
    if (herPermKey && herPermKey != wrapper->herPerminentPubKey) {
        memcpy(wrapper->herPerminentPubKey, herPermKey, 32);
    }

    // If this is a handshake which was initiated in reverse because we
    // didn't know the other node's key, now send what we were going to send.
    if (wrapper->hasBufferedMessage && message->length == 0) {
        Log_debug(wrapper->context->logger, "Sending buffered message.\n");
        sendMessage(wrapper->bufferedMessage, &wrapper->externalInterface);
        wrapper->hasBufferedMessage = false;
        return Error_NONE;
    } else if (wrapper->hasBufferedMessage) {
        Log_debug(wrapper->context->logger, "There is a buffered message.\n");
    }

    memset(&wrapper->replayProtector, 0, sizeof(struct ReplayProtector));

    setRequiredPadding(wrapper);
    return callReceivedMessage(wrapper, message);
}
Example #20
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);
}
Example #21
0
static inline bool knowHerKey(struct Wrapper* wrapper)
{
    return !Bits_isZero(wrapper->herPerminentPubKey, 32);
}
Example #22
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);
}
Example #23
0
static inline bool knowHerKey(struct CryptoAuth_Session_pvt* session)
{
    return !Bits_isZero(session->pub.herPublicKey, 32);
}
Example #24
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);
}
Example #25
0
static Gcc_USE_RET int decryptHandshake(struct CryptoAuth_Session_pvt* session,
                                        const uint32_t nonce,
                                        struct Message* message,
                                        union CryptoHeader* header)
{
    if (message->length < CryptoHeader_SIZE) {
        cryptoAuthDebug0(session, "DROP runt");
        return -1;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (knowHerKey(session)) {
        if (Bits_memcmp(session->pub.herPublicKey, header->handshake.publicKey, 32)) {
            cryptoAuthDebug0(session, "DROP a packet with different public key than this session");
            return -1;
        }
    } else if (Bits_isZero(session->pub.herIp6, 16)) {
        // ok fallthrough
    } else if (!ip6MatchesKey(session->pub.herIp6, header->handshake.publicKey)) {
        cryptoAuthDebug0(session, "DROP packet with public key not matching ip6 for session");
        return -1;
    }

    struct CryptoAuth_User* userObj = getAuth(&header->handshake.auth, session->context);
    uint8_t* restrictedToip6 = NULL;
    uint8_t* passwordHash = NULL;
    if (userObj) {
        passwordHash = userObj->secret;
        if (userObj->restrictedToip6[0]) {
            restrictedToip6 = userObj->restrictedToip6;
            if (!ip6MatchesKey(restrictedToip6, header->handshake.publicKey)) {
                cryptoAuthDebug0(session, "DROP packet with key not matching restrictedToip6");
                return -1;
            }
        }
    }
    if (session->requireAuth && !userObj) {
        cryptoAuthDebug0(session, "DROP message because auth was not given");
        return -1;
    }
    if (!userObj && header->handshake.auth.challenge.type != 0) {
        cryptoAuthDebug0(session, "DROP message with unrecognized authenticator");
        return -1;
    }
    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = session->pub.herPublicKey;
    if (nonce < 2) {
        if (nonce == 0) {
            cryptoAuthDebug(session, "Received a hello packet, using auth: %d",
                            (userObj != NULL));
        } else {
            cryptoAuthDebug0(session, "Received a repeat hello packet");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(session) || session->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            if (Defined(Log_DEBUG) && Bits_isZero(header->handshake.publicKey, 32)) {
                cryptoAuthDebug0(session, "DROP Node sent public key of ZERO!");
                // This is strictly informational, we will not alter the execution path for it.
            }
        }

        getSharedSecret(sharedSecret,
                        session->context->privateKey,
                        herPermKey,
                        passwordHash,
                        session->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            cryptoAuthDebug0(session, "Received a key packet");
        } else {
            Assert_true(nonce == 3);
            cryptoAuthDebug0(session, "Received a repeat key packet");
        }
        if (Bits_memcmp(header->handshake.publicKey, session->pub.herPublicKey, 32)) {
            cryptoAuthDebug0(session, "DROP packet contains different perminent key");
            return -1;
        }
        if (!session->isInitiator) {
            cryptoAuthDebug0(session, "DROP a stray key packet");
            return -1;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        session->ourTempPrivKey,
                        session->pub.herPublicKey,
                        passwordHash,
                        session->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - CryptoHeader_SIZE, NULL);

    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,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    }

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret)) {
        // just in case
        Bits_memset(header, 0, CryptoHeader_SIZE);
        cryptoAuthDebug(session, "DROP message with nonce [%d], decryption failed", nonce);
        return -1;
    }

    if (Bits_isZero(header->handshake.encryptedTempKey, 32)) {
        // we need to reject 0 public keys outright because they will be confused with "unknown"
        cryptoAuthDebug0(session, "DROP message with zero as temp public key");
        return -1;
    }

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

    Message_shift(message, -32, NULL);

    // Post-decryption checking
    if (nonce == 0) {
        // A new hello packet
        if (!Bits_memcmp(session->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            // possible replay attack or duped packet
            cryptoAuthDebug0(session, "DROP dupe hello packet with same temp key");
            return -1;
        }
    } else if (nonce == 2 && session->nextNonce >= 4) {
        // we accept a new key packet and let it change the session since the other end might have
        // killed off the session while it was in the midst of setting up.
        // This is NOT a repeat key packet because it's nonce is 2, not 3
        if (!Bits_memcmp(session->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(session->herTempPubKey, 32));
            cryptoAuthDebug0(session, "DROP dupe key packet with same temp key");
            return -1;
        }

    } else if (nonce == 3 && session->nextNonce >= 4) {
        // Got a repeat key packet, make sure the temp key is the same as the one we know.
        if (Bits_memcmp(session->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(session->herTempPubKey, 32));
            cryptoAuthDebug0(session, "DROP repeat key packet with different temp key");
            return -1;
        }
    }

    // If Alice sent a hello packet then Bob sent a hello packet and they crossed on the wire,
    // somebody has to yield and the other has to stand firm otherwise they will either deadlock
    // each believing their hello packet is superior or they will livelock, each switching to the
    // other's session and never synchronizing.
    // In this event whoever has the lower permanent public key wins.

    // If we receive a (possibly repeat) key packet
    if (nextNonce == 4) {
        if (session->nextNonce <= 4) {
            // and have not yet begun sending "run" data
            Bits_memcpyConst(session->herTempPubKey, header->handshake.encryptedTempKey, 32);
        } else {
            // It's a (possibly repeat) key packet and we have begun sending run data.
            // We will change the shared secret to the one specified in the new key packet but
            // intentionally avoid de-incrementing the nonce just in case
            getSharedSecret(session->sharedSecret,
                            session->ourTempPrivKey,
                            header->handshake.encryptedTempKey,
                            NULL,
                            session->context->logger);
            nextNonce = session->nextNonce + 1;
            cryptoAuthDebug0(session, "New key packet but we are already sending data");
        }

    } else if (nextNonce != 2) {

        Assert_true(!"should never happen");

    } else if (!session->isInitiator || session->established) {
        // This is a hello packet and we are either in ESTABLISHED state or we are
        // not the initiator of the connection.
        // If the case is that we are in ESTABLISHED state, the other side tore down the session
        // and we have not so lets tear it down.
        // If we are not in ESTABLISHED state then we don't allow resetting of the session unless
        // they are the sender of the hello packet or their permanent public key is lower.
        // this is a tie-breaker in case hello packets cross on the wire.
        if (session->established) {
            cryptoAuthDebug0(session, "new hello during established session, resetting");
            reset(session);
        }
        // We got a (possibly repeat) hello packet and we have not sent any hello packet,
        // new session.
        if (session->nextNonce == 3) {
            // We sent a key packet so the next packet is a repeat key but we got another hello
            // We'll just keep steaming along sending repeat key packets
            nextNonce = 3;
        }

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

    } else if (Bits_memcmp(header->handshake.publicKey, session->context->pub.publicKey, 32) < 0) {
        // It's a hello and we are the initiator but their permant public key is numerically lower
        // than ours, this is so that in the event of two hello packets crossing on the wire, the
        // nodes will agree on who is the initiator.
        cryptoAuthDebug0(session, "Incoming hello from node with lower key, resetting");
        reset(session);

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

    } else {
        cryptoAuthDebug0(session, "DROP Incoming hello from node with higher key, not resetting");
        return -1;
    }

    if (herPermKey && herPermKey != session->pub.herPublicKey) {
        Bits_memcpyConst(session->pub.herPublicKey, herPermKey, 32);
    }
    if (restrictedToip6) {
        Bits_memcpyConst(session->pub.herIp6, restrictedToip6, 16);
    }

    // Nonces can never go backward and can only "not advance" if they're 0,1,2,3,4 session state.
    Assert_true(session->nextNonce < nextNonce ||
        (session->nextNonce <= 4 && nextNonce == session->nextNonce)
    );
    session->nextNonce = nextNonce;

    Bits_memset(&session->pub.replayProtector, 0, sizeof(struct ReplayProtector));

    return 0;
}
Example #26
0
static uint8_t receiveMessage(struct Message* received, struct Interface* interface)
{
    struct CryptoAuth_Wrapper* wrapper =
        Identity_check((struct CryptoAuth_Wrapper*) interface->receiverContext);

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

    if (received->length < 20) {
        cryptoAuthDebug0(wrapper, "DROP runt");
        return Error_UNDERSIZE_MESSAGE;
    }
    Assert_true(received->padding >= 12 || "need at least 12 bytes of padding in incoming message");
    Assert_true(!((uintptr_t)received->bytes % 4) || !"alignment fault");

    Message_shift(received, -4, NULL);

    uint32_t nonce = Endian_bigEndianToHost32(header->nonce);

    if (!wrapper->established) {
        if (nonce > 3 && nonce != UINT32_MAX) {
            if (wrapper->nextNonce < 3) {
                // This is impossible because we have not exchanged hello and key messages.
                cryptoAuthDebug0(wrapper, "DROP Received a run message to an un-setup session");
                return Error_UNDELIVERABLE;
            }
            cryptoAuthDebug(wrapper, "Trying final handshake step, nonce=%u\n", nonce);
            uint8_t secret[32];
            Assert_ifParanoid(!Bits_isZero(wrapper->ourTempPrivKey, 32));
            Assert_ifParanoid(!Bits_isZero(wrapper->herTempPubKey, 32));
            getSharedSecret(secret,
                            wrapper->ourTempPrivKey,
                            wrapper->herTempPubKey,
                            NULL,
                            wrapper->context->logger);

            // We'll optimistically advance the nextNonce value because decryptMessage()
            // passes the message on to the upper level and if this message causes a
            // response, we want the CA to be in ESTABLISHED state.
            // if the decryptMessage() call fails, we CryptoAuth_reset() it back.
            wrapper->nextNonce += 3;

            if (decryptMessage(wrapper, nonce, received, secret)) {
                cryptoAuthDebug0(wrapper, "Final handshake step succeeded");
                Bits_memcpyConst(wrapper->sharedSecret, secret, 32);

                // Now we're in run mode, no more handshake packets will be accepted
                Bits_memset(wrapper->ourTempPrivKey, 0, 32);
                Bits_memset(wrapper->ourTempPubKey, 0, 32);
                Bits_memset(wrapper->herTempPubKey, 0, 32);
                wrapper->established = true;

                return callReceivedMessage(wrapper, received);
            }
            CryptoAuth_reset(&wrapper->externalInterface);
            cryptoAuthDebug0(wrapper, "DROP Final handshake step failed");
            return Error_UNDELIVERABLE;
        }

        Message_shift(received, 4, NULL);
        return decryptHandshake(wrapper, nonce, received, header);

    } else if (nonce > 3 && nonce != UINT32_MAX) {
        Assert_ifParanoid(!Bits_isZero(wrapper->sharedSecret, 32));
        if (decryptMessage(wrapper, nonce, received, wrapper->sharedSecret)) {
            return callReceivedMessage(wrapper, received);
        } else {
            cryptoAuthDebug0(wrapper, "DROP Failed to decrypt message");
            return Error_UNDELIVERABLE;
        }
    } else if (nonce < 2) {
        cryptoAuthDebug(wrapper, "hello packet during established session nonce=[%d]", nonce);
        Message_shift(received, 4, NULL);
        return decryptHandshake(wrapper, nonce, received, header);
    } else {
        // setup keys are already zeroed, not much we can do here.
        cryptoAuthDebug(wrapper, "DROP key packet during established session nonce=[%d]", nonce);
        return Error_UNDELIVERABLE;
    }
    Assert_true(0);
}
Example #27
0
static void beginConnection(Dict* args,
                            void* vcontext,
                            String* txid,
                            struct Allocator* requestAlloc)
{
    struct Context* ctx = vcontext;

    String* password = Dict_getString(args, String_CONST("password"));
    String* publicKey = Dict_getString(args, String_CONST("publicKey"));
    String* address = Dict_getString(args, String_CONST("address"));
    int64_t* interfaceNumber = Dict_getInt(args, String_CONST("interfaceNumber"));
    uint32_t ifNum = (interfaceNumber) ? ((uint32_t) *interfaceNumber) : 0;
    String* peerName = Dict_getString(args, String_CONST("peerName"));
    String* error = NULL;

    Log_debug(ctx->logger, "Peering with [%s]", publicKey->bytes);

    struct Sockaddr_storage ss;
    uint8_t pkBytes[32];
    int ret;
    if (interfaceNumber && *interfaceNumber < 0) {
        error = String_CONST("negative interfaceNumber");

    } else if ((ret = Key_parse(publicKey, pkBytes, NULL))) {
        error = String_CONST(Key_parse_strerror(ret));

    } else if (Sockaddr_parse(address->bytes, &ss)) {
        error = String_CONST("unable to parse ip address and port.");

    } else if (Sockaddr_getFamily(&ss.addr) != Sockaddr_getFamily(ctx->udpIf->addr)) {
        error = String_CONST("different address type than this socket is bound to.");

    } else {

        struct Sockaddr* addr = &ss.addr;
        char* addrPtr = NULL;
        int addrLen = Sockaddr_getAddress(&ss.addr, &addrPtr);
        Assert_true(addrLen > 0);
        struct Allocator* tempAlloc = Allocator_child(ctx->alloc);
        if (Bits_isZero(addrPtr, addrLen)) {
            // unspec'd address, convert to loopback
            if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET) {
                addr = Sockaddr_clone(Sockaddr_LOOPBACK, tempAlloc);
            } else if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET6) {
                addr = Sockaddr_clone(Sockaddr_LOOPBACK6, tempAlloc);
            } else {
                Assert_failure("Sockaddr which is not AF_INET nor AF_INET6");
            }
            Sockaddr_setPort(addr, Sockaddr_getPort(&ss.addr));
        }

        int ret = InterfaceController_bootstrapPeer(
            ctx->ic, ifNum, pkBytes, addr, password, peerName, ctx->alloc);

        Allocator_free(tempAlloc);

        if (ret) {
            switch(ret) {
                case InterfaceController_bootstrapPeer_BAD_IFNUM:
                    error = String_CONST("no such interface for interfaceNumber");
                    break;

                case InterfaceController_bootstrapPeer_BAD_KEY:
                    error = String_CONST("invalid cjdns public key.");
                    break;

                case InterfaceController_bootstrapPeer_OUT_OF_SPACE:
                    error = String_CONST("no more space to register with the switch.");
                    break;

                default:
                    error = String_CONST("unknown error");
                    break;
            }
        } else {
            error = String_CONST("none");
        }
    }

    Dict out = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL);
    Admin_sendMessage(&out, txid, ctx->admin);
}
Example #28
0
static uint8_t decryptHandshake(struct CryptoAuth_Wrapper* wrapper,
                                const uint32_t nonce,
                                struct Message* message,
                                union Headers_CryptoAuth* header)
{
    if (message->length < Headers_CryptoAuth_SIZE) {
        cryptoAuthDebug0(wrapper, "DROP runt");
        return Error_UNDERSIZE_MESSAGE;
    }

    // handshake
    // nextNonce 0: recieving hello.
    // nextNonce 1: recieving key, we sent hello.
    // nextNonce 2: recieving first data packet or duplicate hello.
    // nextNonce 3: recieving first data packet.
    // nextNonce >3: handshake complete

    if (knowHerKey(wrapper)) {
        if (Bits_memcmp(wrapper->herPerminentPubKey, header->handshake.publicKey, 32)) {
            cryptoAuthDebug0(wrapper, "DROP a packet with different public key than this session");
            return Error_AUTHENTICATION;
        }
    } else if (!Bits_isZero(wrapper->herIp6, 16)) {
        uint8_t calculatedIp6[16];
        AddressCalc_addressForPublicKey(calculatedIp6, header->handshake.publicKey);
        if (Bits_memcmp(wrapper->herIp6, calculatedIp6, 16)) {
            cryptoAuthDebug0(wrapper, "DROP packet with public key not matching ip6 for session");
            return Error_AUTHENTICATION;
        }
    }

    if (wrapper->nextNonce < 2 && nonce == UINT32_MAX && !wrapper->requireAuth) {
        // Reset without knowing key is allowed until state reaches 2.
        // this is because we don't know that the other end knows our key until we
        // have received a valid packet from them.
        // We can't allow the upper layer to see this message because it's not authenticated.
        if (!knowHerKey(wrapper)) {
            Bits_memcpyConst(wrapper->herPerminentPubKey, header->handshake.publicKey, 32);
        }
        Message_shift(message, -Headers_CryptoAuth_SIZE, NULL);
        message->length = 0;
        reset(wrapper);
        wrapper->user = NULL;
        cryptoAuthDebug0(wrapper, "Got a connect-to-me message, sending a hello");
        // Send an empty response (to initiate the connection).
        encryptHandshake(message, wrapper, 1);
        return Error_NONE;
    }

    String* user = NULL;
    uint8_t passwordHashStore[32];
    uint8_t* passwordHash = tryAuth(header, passwordHashStore, wrapper, &user);
    if (wrapper->requireAuth && !user) {
        cryptoAuthDebug0(wrapper, "DROP message because auth was not given");
        return Error_AUTHENTICATION;
    }
    if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) {
        cryptoAuthDebug0(wrapper, "DROP message with unrecognized authenticator");
        return Error_AUTHENTICATION;
    }

    // What the nextNonce will become if this packet is valid.
    uint32_t nextNonce;

    // The secret for decrypting this message.
    uint8_t sharedSecret[32];

    uint8_t* herPermKey = NULL;
    if (nonce < 2) {
        if (nonce == 0) {
            cryptoAuthDebug(wrapper, "Received a hello packet, using auth: %d",
                            (passwordHash != NULL));
        } else {
            cryptoAuthDebug0(wrapper, "Received a repeat hello packet");
        }

        // Decrypt message with perminent keys.
        if (!knowHerKey(wrapper) || wrapper->nextNonce == 0) {
            herPermKey = header->handshake.publicKey;
            #ifdef Log_DEBUG
                if (Bits_isZero(header->handshake.publicKey, 32)) {
                    cryptoAuthDebug0(wrapper, "Node sent public key of ZERO!");
                }
            #endif
        } else {
            herPermKey = wrapper->herPerminentPubKey;
            if (Bits_memcmp(header->handshake.publicKey, herPermKey, 32)) {
                cryptoAuthDebug0(wrapper, "DROP packet contains different perminent key");
                return Error_AUTHENTICATION;
            }
        }

        getSharedSecret(sharedSecret,
                        wrapper->context->privateKey,
                        herPermKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 2;
    } else {
        if (nonce == 2) {
            cryptoAuthDebug0(wrapper, "Received a key packet");
        } else if (nonce == 3) {
            cryptoAuthDebug0(wrapper, "Received a repeat key packet");
        } else {
            cryptoAuthDebug(wrapper, "Received a packet of unknown type! nonce=%u", nonce);
        }
        if (Bits_memcmp(header->handshake.publicKey, wrapper->herPerminentPubKey, 32)) {
            cryptoAuthDebug0(wrapper, "DROP packet contains different perminent key");
            return Error_AUTHENTICATION;
        }
        if (!wrapper->isInitiator) {
            cryptoAuthDebug0(wrapper, "DROP a stray key packet");
            return Error_AUTHENTICATION;
        }
        // We sent the hello, this is a key
        getSharedSecret(sharedSecret,
                        wrapper->ourTempPrivKey,
                        wrapper->herPerminentPubKey,
                        passwordHash,
                        wrapper->context->logger);
        nextNonce = 4;
    }

    // Shift it on top of the authenticator before the encrypted public key
    Message_shift(message, 48 - Headers_CryptoAuth_SIZE, NULL);

    #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,
                  "Decrypting message with:\n"
                  "    nonce: %s\n"
                  "   secret: %s\n"
                  "   cipher: %s\n",
                  nonceHex, sharedSecretHex, cipherHex);
    #endif

    // Decrypt her temp public key and the message.
    if (decryptRndNonce(header->handshake.nonce, message, sharedSecret) != 0) {
        // just in case
        Bits_memset(header, 0, Headers_CryptoAuth_SIZE);
        cryptoAuthDebug(wrapper, "DROP message with nonce [%d], decryption failed", nonce);
        return Error_AUTHENTICATION;
    }

    Assert_ifParanoid(!Bits_isZero(header->handshake.encryptedTempKey, 32));

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

    Message_shift(message, -32, NULL);

    // Post-decryption checking
    if (nonce == 0) {
        // A new hello packet
        if (!Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            // possible replay attack or duped packet
            cryptoAuthDebug0(wrapper, "DROP dupe hello packet with same temp key");
            return Error_AUTHENTICATION;
        }
    } else if (nonce == 2 && wrapper->nextNonce >= 4) {
        // we accept a new key packet and let it change the session since the other end might have
        // killed off the session while it was in the midst of setting up.
        if (!Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(wrapper->herTempPubKey, 32));
            cryptoAuthDebug0(wrapper, "DROP dupe key packet with same temp key");
            return Error_AUTHENTICATION;
        }

    } else if (nonce == 3 && wrapper->nextNonce >= 4) {
        // Got a repeat key packet, make sure the temp key is the same as the one we know.
        if (Bits_memcmp(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32)) {
            Assert_true(!Bits_isZero(wrapper->herTempPubKey, 32));
            cryptoAuthDebug0(wrapper, "DROP repeat key packet with different temp key");
            return Error_AUTHENTICATION;
        }
    }

    // If Alice sent a hello packet then Bob sent a hello packet and they crossed on the wire,
    // somebody has to yield and the other has to stand firm otherwise they will either deadlock
    // each believing their hello packet is superior or they will livelock, each switching to the
    // other's session and never synchronizing.
    // In this event whoever has the lower permanent public key wins.

    // If we receive a (possibly repeat) key packet
    if (nextNonce == 4) {
        if (wrapper->nextNonce <= 4) {
            // and have not yet begun sending "run" data
            Assert_true(wrapper->nextNonce <= nextNonce);
            wrapper->nextNonce = nextNonce;

            wrapper->user = user;
            Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);
        } else {
            // It's a (possibly repeat) key packet and we have begun sending run data.
            // We will change the shared secret to the one specified in the new key packet but
            // intentionally avoid de-incrementing the nonce just in case
            getSharedSecret(wrapper->sharedSecret,
                            wrapper->ourTempPrivKey,
                            header->handshake.encryptedTempKey,
                            NULL,
                            wrapper->context->logger);
            cryptoAuthDebug0(wrapper, "New key packet but we are already sending data");
        }

    } else if (nextNonce == 2 && (!wrapper->isInitiator || wrapper->established)) {
        // This is a hello packet and we are either in ESTABLISHED state or we are
        // not the initiator of the connection.
        // If the case is that we are in ESTABLISHED state, the other side tore down the session
        // and we have not so lets tear it down.
        // If we are not in ESTABLISHED state then we don't allow resetting of the session unless
        // they are the sender of the hello packet or their permanent public key is lower.
        // this is a tie-breaker in case hello packets cross on the wire.
        if (wrapper->established) {
            reset(wrapper);
        }
        // We got a (possibly repeat) hello packet and we have not sent any hello packet,
        // new session.
        if (wrapper->nextNonce == 3 && nextNonce == 2) {
            // We sent a key packet so the next packet is a repeat key but we got another hello
            // We'll just keep steaming along sending repeat key packets
            nextNonce = 3;
        }

        Assert_true(wrapper->nextNonce <= nextNonce);
        wrapper->nextNonce = nextNonce;
        wrapper->user = user;
        Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else if (nextNonce == 2
        && Bits_memcmp(header->handshake.publicKey, wrapper->context->pub.publicKey, 32) < 0)
    {
        // It's a hello and we are the initiator but their permant public key is numerically lower
        // than ours, this is so that in the event of two hello packets crossing on the wire, the
        // nodes will agree on who is the initiator.
        cryptoAuthDebug0(wrapper, "Incoming hello from node with lower key, resetting");
        reset(wrapper);

        Assert_true(wrapper->nextNonce <= nextNonce);
        wrapper->nextNonce = nextNonce;
        wrapper->user = user;
        Bits_memcpyConst(wrapper->herTempPubKey, header->handshake.encryptedTempKey, 32);

    } else {
        cryptoAuthDebug0(wrapper, "Incoming hello from node with higher key, not resetting");
    }

    if (herPermKey && herPermKey != wrapper->herPerminentPubKey) {
        Bits_memcpyConst(wrapper->herPerminentPubKey, herPermKey, 32);
    }

    // If this is a handshake which was initiated in reverse because we
    // didn't know the other node's key, now send what we were going to send.

    if (wrapper->bufferedMessage) {
        // This can only happen when we have received a (maybe repeat) hello packet.
        Assert_true(wrapper->nextNonce == 2);

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

    if (message->length == 0 && Headers_isSetupPacket(&header->handshake.auth)) {
        return Error_NONE;
    }

    Bits_memset(&wrapper->replayProtector, 0, sizeof(struct ReplayProtector));

    setRequiredPadding(wrapper);
    return callReceivedMessage(wrapper, message);
}
Example #29
0
/** @return 0 on success, -1 otherwise. */
int CryptoAuth_decrypt(struct CryptoAuth_Session* sessionPub, struct Message* msg)
{
    struct CryptoAuth_Session_pvt* session =
        Identity_check((struct CryptoAuth_Session_pvt*) sessionPub);
    union CryptoHeader* header = (union CryptoHeader*) msg->bytes;

    if (msg->length < 20) {
        cryptoAuthDebug0(session, "DROP runt");
        return -1;
    }
    Assert_true(msg->padding >= 12 || "need at least 12 bytes of padding in incoming message");
    Assert_true(!((uintptr_t)msg->bytes % 4) || !"alignment fault");
    Assert_true(!(msg->capacity % 4) || !"length fault");

    Message_shift(msg, -4, NULL);

    uint32_t nonce = Endian_bigEndianToHost32(header->nonce);

    if (!session->established) {
        if (nonce > 3) {
            if (session->nextNonce < 3) {
                // This is impossible because we have not exchanged hello and key messages.
                cryptoAuthDebug0(session, "DROP Received a run message to an un-setup session");
                return -1;
            }
            cryptoAuthDebug(session, "Trying final handshake step, nonce=%u\n", nonce);
            uint8_t secret[32];
            Assert_ifParanoid(!Bits_isZero(session->ourTempPrivKey, 32));
            Assert_ifParanoid(!Bits_isZero(session->herTempPubKey, 32));
            getSharedSecret(secret,
                            session->ourTempPrivKey,
                            session->herTempPubKey,
                            NULL,
                            session->context->logger);

            if (decryptMessage(session, nonce, msg, secret)) {
                cryptoAuthDebug0(session, "Final handshake step succeeded");
                Bits_memcpyConst(session->sharedSecret, secret, 32);

                // Now we're in run mode, no more handshake packets will be accepted
                Bits_memset(session->ourTempPrivKey, 0, 32);
                Bits_memset(session->ourTempPubKey, 0, 32);
                Bits_memset(session->herTempPubKey, 0, 32);
                session->established = true;
                session->nextNonce += 3;
                updateTime(session, msg);
                return 0;
            }
            cryptoAuthDebug0(session, "DROP Final handshake step failed");
            return -1;
        }

        Message_shift(msg, 4, NULL);
        return decryptHandshake(session, nonce, msg, header);

    } else if (nonce > 3) {
        Assert_ifParanoid(!Bits_isZero(session->sharedSecret, 32));
        if (decryptMessage(session, nonce, msg, session->sharedSecret)) {
            updateTime(session, msg);
            return 0;
        } else {
            cryptoAuthDebug0(session, "DROP Failed to decrypt message");
            return -1;
        }
    } else if (nonce < 2) {
        cryptoAuthDebug(session, "hello packet during established session nonce=[%d]", nonce);
        Message_shift(msg, 4, NULL);
        return decryptHandshake(session, nonce, msg, header);
    } else {
        // setup keys are already zeroed, not much we can do here.
        cryptoAuthDebug(session, "DROP key packet during established session nonce=[%d]", nonce);
        return -1;
    }
    Assert_true(0);
}