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); }
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; }
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; }
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; }
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); }
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)); }
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)); }
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 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); }
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); }
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); }
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; }
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); }
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; }
// 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 }));
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); }
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,
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); }
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,
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); }
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); }
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); }
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; }
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; }
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); }
.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,