struct CryptoAuth* CryptoAuth_new(struct Allocator* allocator, const uint8_t* privateKey, struct event_base* eventBase, struct Log* logger) { struct CryptoAuth_pvt* ca = allocator->calloc(sizeof(struct CryptoAuth_pvt), 1, allocator); ca->allocator = allocator; ca->passwords = allocator->calloc(sizeof(struct CryptoAuth_Auth), 256, allocator); ca->passwordCount = 0; ca->passwordCapacity = 256; ca->eventBase = eventBase; ca->logger = logger; ca->pub.resetAfterInactivitySeconds = CryptoAuth_DEFAULT_RESET_AFTER_INACTIVITY_SECONDS; if (privateKey != NULL) { Bits_memcpyConst(ca->privateKey, privateKey, 32); crypto_scalarmult_curve25519_base(ca->pub.publicKey, ca->privateKey); } else { crypto_box_curve25519xsalsa20poly1305_keypair(ca->pub.publicKey, ca->privateKey); } #ifdef Log_KEYS uint8_t publicKeyHex[65]; printHexKey(publicKeyHex, ca->pub.publicKey); uint8_t privateKeyHex[65]; printHexKey(privateKeyHex, ca->privateKey); Log_keys(logger, "Initialized CryptoAuth:\n myPrivateKey=%s\n myPublicKey=%s\n", privateKeyHex, publicKeyHex); #endif return &ca->pub; }
struct CryptoAuth* CryptoAuth_new(struct Allocator* allocator, const uint8_t* privateKey, struct EventBase* eventBase, struct Log* logger, struct Random* rand) { struct CryptoAuth_pvt* ca = Allocator_calloc(allocator, sizeof(struct CryptoAuth_pvt), 1); Identity_set(ca); ca->allocator = allocator; ca->eventBase = eventBase; ca->logger = logger; ca->pub.resetAfterInactivitySeconds = CryptoAuth_DEFAULT_RESET_AFTER_INACTIVITY_SECONDS; ca->rand = rand; if (privateKey != NULL) { Bits_memcpyConst(ca->privateKey, privateKey, 32); } else { Random_bytes(rand, ca->privateKey, 32); } crypto_scalarmult_curve25519_base(ca->pub.publicKey, ca->privateKey); if (Defined(Log_KEYS)) { uint8_t publicKeyHex[65]; printHexKey(publicKeyHex, ca->pub.publicKey); uint8_t privateKeyHex[65]; printHexKey(privateKeyHex, ca->privateKey); Log_keys(logger, "Initialized CryptoAuth:\n myPrivateKey=%s\n myPublicKey=%s\n", privateKeyHex, publicKeyHex); } return &ca->pub; }
static void sendConfToCore(struct Interface* toCoreInterface, struct Allocator* tempAlloc, Dict* config, struct Except* eh, struct Log* logger) { #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE + 32] = {0}; uint8_t* start = buff + 32; struct Writer* writer = ArrayWriter_new(start, CONFIG_BUFF_SIZE - 33, tempAlloc); if (StandardBencSerializer_get()->serializeDictionary(writer, config)) { Except_raise(eh, -1, "Failed to serialize pre-configuration for core."); } struct Message* m = &(struct Message) { .bytes = start, .length = writer->bytesWritten, .padding = 32 }; m = Message_clone(m, tempAlloc); Log_keys(logger, "Sent [%d] bytes to core [%s].", m->length, m->bytes); toCoreInterface->sendMessage(m, toCoreInterface); } static void setUser(char* user, struct Log* logger, struct Except* eh) { struct Jmp jmp; Jmp_try(jmp) { Security_setUser(user, logger, &jmp.handler); } Jmp_catch { if (jmp.code == Security_setUser_PERMISSION) { return; } Except_raise(eh, jmp.code, "%s", jmp.message); } } static struct Pipe* getClientPipe(int argc, char** argv, struct EventBase* base, struct Except* eh, struct Allocator* alloc) { int inFromClientNo; int outToClientNo; if (argc < 4 || (inFromClientNo = atoi(argv[2])) == 0) { inFromClientNo = STDIN_FILENO; } if (argc < 4 || (outToClientNo = atoi(argv[3])) == 0) { outToClientNo = STDOUT_FILENO; } // named pipe. if (argc > 2 && inFromClientNo == STDIN_FILENO) { return Pipe_named(argv[2], base, eh, alloc); } return Pipe_forFiles(inFromClientNo, outToClientNo, base, eh, alloc); }
static void die(struct AdminClient_Result* res, struct Context* ctx, struct Allocator* alloc) { Log_keys(ctx->logger, "message bytes = [%s]", res->messageBytes); #ifndef Log_KEYS Log_critical(ctx->logger, "enable Log_LEVEL=KEYS to see message content."); #endif Dict d = NULL; struct AdminClient_Result* exitRes = AdminClient_rpcCall(String_CONST("Core_exit"), &d, ctx->client, alloc); if (exitRes->err) { Log_critical(ctx->logger, "Failed to stop the core."); } Log_critical(ctx->logger, "Aborting."); exit(1); }
static void die(struct AdminClient_Result* res, struct Context* ctx, struct Allocator* alloc) { Log_keys(ctx->logger, "message bytes = [%s]", res->messageBytes); #ifndef Log_KEYS Log_critical(ctx->logger, "enable Log_LEVEL=KEYS to see message content."); #endif Dict d = NULL; struct AdminClient_Promise* exitPromise = AdminClient_rpcCall(String_CONST("Core_exit"), &d, ctx->client, alloc); exitPromise->callback = rpcCallback; exitPromise->userData = ctx; EventBase_beginLoop(ctx->base); if (ctx->currentResult->err) { Log_critical(ctx->logger, "Failed to stop the core."); } Log_critical(ctx->logger, "Aborting."); exit(1); }
/** * Get a shared secret. * * @param outputSecret an array to place the shared secret in. * @param myPrivateKey * @param herPublicKey * @param logger * @param passwordHash a 32 byte value known to both ends, this must be provably pseudorandom * the first 32 bytes of a sha256 output from hashing a password is ok, * whatever she happens to send me in the Auth field is NOT ok. * If this field is null, the secret will be generated without the password. */ static inline void getSharedSecret(uint8_t outputSecret[32], uint8_t myPrivateKey[32], uint8_t herPublicKey[32], uint8_t passwordHash[32], struct Log* logger) { if (passwordHash == NULL) { crypto_box_curve25519xsalsa20poly1305_beforenm(outputSecret, herPublicKey, myPrivateKey); } else { union { struct { uint8_t key[32]; uint8_t passwd[32]; } components; uint8_t bytes[64]; } buff; crypto_scalarmult_curve25519(buff.components.key, myPrivateKey, herPublicKey); Bits_memcpyConst(buff.components.passwd, passwordHash, 32); crypto_hash_sha256(outputSecret, buff.bytes, 64); } #ifdef Log_KEYS uint8_t myPublicKeyHex[65]; printHexPubKey(myPublicKeyHex, myPrivateKey); uint8_t herPublicKeyHex[65]; printHexKey(herPublicKeyHex, herPublicKey); uint8_t passwordHashHex[65]; printHexKey(passwordHashHex, passwordHash); uint8_t outputSecretHex[65] = "NULL"; printHexKey(outputSecretHex, outputSecret); Log_keys(logger, "Generated a shared secret:\n" " myPublicKey=%s\n" " herPublicKey=%s\n" " passwordHash=%s\n" " outputSecret=%s\n", myPublicKeyHex, herPublicKeyHex, passwordHashHex, outputSecretHex); #endif }
static void udpInterface(Dict* config, struct Context* ctx) { Dict* udp = Dict_getDict(config, String_CONST("UDPInterface")); if (udp) { // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } rpcCall(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); struct Allocator* perCallAlloc = ctx->alloc->child(ctx->alloc); Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); perCallAlloc->free(perCallAlloc); entry = entry->next; } } } }
static void receiveMessage2(struct Message* msg, struct Hermes* hermes, struct Allocator* tempAlloc) { #ifdef Log_KEYS char lastChr = msg->bytes[msg->length - 1]; msg->bytes[msg->length - 1] = '\0'; Log_keys(hermes->logger, "Got message from angel [%s%c]", msg->bytes, lastChr); msg->bytes[msg->length - 1] = lastChr; #else Log_debug(hermes->logger, "Got message from angel"); #endif Dict* d = NULL; char* err = BencMessageReader_readNoExcept(msg, tempAlloc, &d); if (err) { Log_warn(hermes->logger, "Failed to parse message from angel [%s]", err); return; } String* txid = Dict_getString(d, String_CONST("txid")); uint32_t handle; if (!txid || txid->len != 8 || 4 != Hex_decode((uint8_t*)&handle, 4, (uint8_t*)txid->bytes, 8)) { Log_warn(hermes->logger, "Message from angel; txid missing or unrecognized"); return; } int index = Map_RequestSet_indexForHandle(handle, &hermes->requestSet); if (index < 0) { Log_warn(hermes->logger, "Message from angel references nonexistant request"); return; } struct Request* req = Identity_check((struct Request*) hermes->requestSet.values[index]); req->onResponse(d, req->onResponseContext); Allocator_free(req->alloc); }
static void ethInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("ETHInterface")); if (!ifaces) { ifaces = List_addDict(ifaces, Dict_getDict(config, String_CONST("ETHInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *eth = List_getDict(ifaces, i); if (!eth) { continue; } // Setup the interface. String* deviceStr = Dict_getString(eth, String_CONST("bind")); Log_info(ctx->logger, "Setting up ETHInterface [%d].", i); Dict* d = Dict_new(ctx->alloc); if (deviceStr) { Log_info(ctx->logger, "Binding to device [%s].", deviceStr->bytes); Dict_putString(d, String_CONST("bindDevice"), deviceStr, ctx->alloc); } if (rpcCall0(String_CONST("ETHInterface_new"), d, ctx, ctx->alloc, false)) { Log_warn(ctx->logger, "Failed to create ETHInterface."); continue; } // Make the connections. Dict* connectTo = Dict_getDict(eth, String_CONST("connectTo")); if (connectTo) { Log_info(ctx->logger, "ETHInterface should connect to a specific node."); struct Dict_Entry* entry = *connectTo; while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.ETHInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); // Turn the dict from the config into our RPC args dict by filling in all // the arguments, Dict_putString(value, String_CONST("macAddress"), key, perCallAlloc); Dict_putInt(value, String_CONST("interfaceNumber"), i, perCallAlloc); rpcCall(String_CONST("ETHInterface_beginConnection"), value, ctx, perCallAlloc); Allocator_free(perCallAlloc); entry = entry->next; } } int64_t* beaconP = Dict_getInt(eth, String_CONST("beacon")); if (beaconP) { int64_t beacon = *beaconP; if (beacon > 3 || beacon < 0) { Log_error(ctx->logger, "interfaces.ETHInterface.beacon may only be 0, 1,or 2"); } else { // We can cast beacon to an int here because we know it's small enough Log_info(ctx->logger, "Setting beacon mode on ETHInterface to [%d].", (int) beacon); Dict d = Dict_CONST(String_CONST("interfaceNumber"), Int_OBJ(i), Dict_CONST(String_CONST("state"), Int_OBJ(beacon), NULL)); rpcCall(String_CONST("ETHInterface_beacon"), &d, ctx, ctx->alloc); } } } }
static void ethInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("ETHInterface")); if (!ifaces) { ifaces = List_new(ctx->alloc); List_addDict(ifaces, Dict_getDict(config, String_CONST("ETHInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *eth = List_getDict(ifaces, i); if (!eth) { continue; } String* deviceStr = Dict_getString(eth, String_CONST("bind")); if (!deviceStr || !String_equals(String_CONST("all"), deviceStr)) { continue; } Log_info(ctx->logger, "Setting up all ETHInterfaces..."); Dict* res = NULL; Dict* d = Dict_new(ctx->alloc); if (rpcCall0(String_CONST("ETHInterface_listDevices"), d, ctx, ctx->alloc, &res, false)) { Log_info(ctx->logger, "Getting device list failed"); break; } List* devs = Dict_getList(res, String_CONST("devices")); uint32_t devCount = List_size(devs); for (uint32_t j = 0; j < devCount; j++) { Dict* d = Dict_new(ctx->alloc); String* deviceName = List_getString(devs, j); // skip loopback... if (String_equals(String_CONST("lo"), deviceName)) { continue; } Dict_putString(d, String_CONST("bindDevice"), deviceName, ctx->alloc); Dict* resp; Log_info(ctx->logger, "Creating new ETHInterface [%s]", deviceName->bytes); if (rpcCall0(String_CONST("ETHInterface_new"), d, ctx, ctx->alloc, &resp, false)) { Log_warn(ctx->logger, "Failed to create ETHInterface."); continue; } int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); ethInterfaceSetBeacon(ifNum, eth, ctx); } return; } for (uint32_t i = 0; i < count; i++) { Dict *eth = List_getDict(ifaces, i); if (!eth) { continue; } // Setup the interface. String* deviceStr = Dict_getString(eth, String_CONST("bind")); Log_info(ctx->logger, "Setting up ETHInterface [%d].", i); Dict* d = Dict_new(ctx->alloc); if (deviceStr) { Log_info(ctx->logger, "Binding to device [%s].", deviceStr->bytes); Dict_putString(d, String_CONST("bindDevice"), deviceStr, ctx->alloc); } Dict* resp = NULL; if (rpcCall0(String_CONST("ETHInterface_new"), d, ctx, ctx->alloc, &resp, false)) { Log_warn(ctx->logger, "Failed to create ETHInterface."); continue; } int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); ethInterfaceSetBeacon(ifNum, eth, ctx); // Make the connections. Dict* connectTo = Dict_getDict(eth, String_CONST("connectTo")); if (connectTo) { Log_info(ctx->logger, "ETHInterface should connect to a specific node."); struct Dict_Entry* entry = *connectTo; while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.ETHInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); // Turn the dict from the config into our RPC args dict by filling in all // the arguments, Dict_putString(value, String_CONST("macAddress"), key, perCallAlloc); Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc); rpcCall(String_CONST("ETHInterface_beginConnection"), value, ctx, perCallAlloc); Allocator_free(perCallAlloc); entry = entry->next; } } } }
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); }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif Assert_true(argc > 0); struct Except* eh = NULL; // Allow it to allocate 4MB struct Allocator* allocator = MallocAllocator_new(1<<22); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if (strcmp(argv[1], "--help") == 0) { return usage(argv[0]); } else if (strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (strcmp(argv[1], "--pidfile") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if (strcmp(argv[1], "--version") == 0) { //printf("Version ID: %s\n", RouterModule_gitVersion()); return 0; } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments\n", argv[0]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Setup Pipes to Angel --------------------- // int pipeToAngel[2]; int pipeFromAngel[2]; if (Pipe_createUniPipe(pipeToAngel) || Pipe_createUniPipe(pipeFromAngel)) { Except_raise(eh, -1, "Failed to create pipes to angel [%s]", Errno_getString()); } char pipeToAngelStr[8]; snprintf(pipeToAngelStr, 8, "%d", pipeToAngel[0]); char pipeFromAngelStr[8]; snprintf(pipeFromAngelStr, 8, "%d", pipeFromAngel[1]); char* args[] = { "angel", pipeToAngelStr, pipeFromAngelStr, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); String* corePath = getCorePath(allocator); if (!corePath) { Except_raise(eh, -1, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_raise(eh, -1, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath->bytes, args); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = strlen(adminPass->bytes); } if (!adminBind) { adminBind = String_new("127.0.0.1:0", allocator); } // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), corePath, allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; struct Writer* toAngelWriter = ArrayWriter_new(buff, CONFIG_BUFF_SIZE - 1, allocator); if (StandardBencSerializer_get()->serializeDictionary(toAngelWriter, preConf)) { Except_raise(eh, -1, "Failed to serialize pre-configuration"); } write(pipeToAngel[1], buff, toAngelWriter->bytesWritten(toAngelWriter)); Log_keys(logger, "Sent [%s] to angel process.", buff); // --------------------- Get Response from Angel --------------------- // uint32_t amount = Waiter_getData(buff, CONFIG_BUFF_SIZE, pipeFromAngel[0], eventBase, eh); Dict responseFromAngel; struct Reader* responseFromAngelReader = ArrayReader_new(buff, amount, allocator); if (StandardBencSerializer_get()->parseDictionary(responseFromAngelReader, allocator, &responseFromAngel)) { Except_raise(eh, -1, "Failed to parse pre-configuration response [%s]", buff); } // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(&responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_raise(eh, -1, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_raise(eh, -1, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check Assert_true(EventBase_eventCount(eventBase) == 0); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); return 0; }
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_new(ctx->alloc); List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } Dict* resp = NULL; rpcCall0(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc, &resp, true); int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* all = entry->val->as.dictionary; Dict* value = Dict_new(perCallAlloc); String* pub_d = Dict_getString(all, String_CONST("publicKey")); String* pss_d = Dict_getString(all, String_CONST("password")); String* peerName_d = Dict_getString(all, String_CONST("peerName")); String* login_d = Dict_getString(all, String_CONST("login")); if ( !pub_d || !pss_d ) { const char * error_name = "(unknown)"; if ( !pub_d ) { error_name = "publicKey"; } if ( !pss_d ) { error_name = "password"; } Log_warn(ctx->logger, "Skipping peer: missing %s for peer [%s]", error_name, key->bytes); if (abort_if_invalid_ref) { Assert_failure("Invalid peer reference"); } else { entry = entry->next; continue; } } Dict_putString(value, String_CONST("publicKey"), pub_d, perCallAlloc); Dict_putString(value, String_CONST("password"), pss_d, perCallAlloc); Dict_putString(value, String_CONST("peerName"), peerName_d, perCallAlloc); Dict_putString(value, String_CONST("login"), login_d, perCallAlloc); Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = CString_strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. int port = atoi(lastColon+1); if (!port) { Log_critical(ctx->logger, "Couldn't get port number from [%s]", key->bytes); exit(-1); } *lastColon = '\0'; struct Sockaddr* adr = Sockaddr_fromName(key->bytes, perCallAlloc); if (adr != NULL) { Sockaddr_setPort(adr, port); key = String_new(Sockaddr_print(adr, perCallAlloc), perCallAlloc); } else { Log_warn(ctx->logger, "Failed to lookup hostname [%s]", key->bytes); entry = entry->next; continue; } } struct Allocator* child = Allocator_child(ctx->alloc); struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE + 256, child); int r = BencMessageWriter_writeDictTry(value, msg, NULL); const int max_reference_size = 298; if (r != 0 || msg->length > max_reference_size) { Log_warn(ctx->logger, "Peer skipped:"); Log_warn(ctx->logger, "Too long peer reference for [%s]", key->bytes); if (abort_if_invalid_ref) { Assert_failure("Invalid peer reference"); } else { entry = entry->next; continue; } } Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc); Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_new(ctx->alloc); List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } Dict* resp = NULL; rpcCall0(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc, &resp, true); int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = CString_strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. Log_critical(ctx->logger, "Couldn't add connection [%s], " "hostnames aren't supported.", key->bytes); exit(-1); } Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc); Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); // Make a IPTunnel exception for this node Dict* aed = Dict_new(perCallAlloc); *lastColon = '\0'; Dict_putString(aed, String_CONST("route"), String_new(key->bytes, perCallAlloc), perCallAlloc); *lastColon = ':'; rpcCall(String_CONST("RouteGen_addException"), aed, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
/* * This process is started with 2 parameters, they must all be numeric in base 10. * toAngel the pipe which is used to send data back to the angel process. * fromAngel the pipe which is used to read incoming data from the angel. * * Upon initialization, this process will wait for an initial configuration to be sent to * it and then it will send an initial response. */ int Core_main(int argc, char** argv) { struct Except* eh = NULL; if (argc != 3) { Except_raise(eh, -1, "This is internal to cjdns and shouldn't started manually."); } struct Allocator* alloc = MallocAllocator_new(ALLOCATOR_FAILSAFE); struct Log* preLogger = FileWriterLog_new(stderr, alloc); struct EventBase* eventBase = EventBase_new(alloc); // -------------------- Setup the Pre-Logger ---------------------- // struct Log* logger = IndirectLog_new(alloc); IndirectLog_set(logger, preLogger); // -------------------- Setup the PRNG ---------------------- // struct Random* rand = LibuvEntropyProvider_newDefaultRandom(eventBase, logger, eh, alloc); // -------------------- Change Canary Value ---------------------- // MallocAllocator_setCanary(alloc, (long)Random_int64(rand)); struct Allocator* tempAlloc = Allocator_child(alloc); // The first read inside of getInitialConfig() will begin it waiting. struct Pipe* angelPipe = Pipe_named(argv[2], eventBase, eh, alloc); angelPipe->logger = logger; angelPipe->onClose = angelDied; struct Interface* angelIface = FramingInterface_new(65535, &angelPipe->iface, alloc); Dict* config = getInitialConfig(angelIface, eventBase, tempAlloc, eh); struct Hermes* hermes = Hermes_new(angelIface, eventBase, logger, alloc); String* privateKeyHex = Dict_getString(config, String_CONST("privateKey")); Dict* adminConf = Dict_getDict(config, String_CONST("admin")); String* pass = Dict_getString(adminConf, String_CONST("pass")); String* bind = Dict_getString(adminConf, String_CONST("bind")); if (!(pass && privateKeyHex && bind)) { if (!pass) { Except_raise(eh, -1, "Expected 'pass'"); } if (!bind) { Except_raise(eh, -1, "Expected 'bind'"); } if (!privateKeyHex) { Except_raise(eh, -1, "Expected 'privateKey'"); } Except_raise(eh, -1, "Expected 'pass', 'privateKey' and 'bind' in configuration."); } Log_keys(logger, "Starting core with admin password [%s]", pass->bytes); uint8_t privateKey[32]; if (privateKeyHex->len != 64 || Hex_decode(privateKey, 32, (uint8_t*) privateKeyHex->bytes, 64) != 32) { Except_raise(eh, -1, "privateKey must be 64 bytes of hex."); } struct Sockaddr_storage bindAddr; if (Sockaddr_parse(bind->bytes, &bindAddr)) { Except_raise(eh, -1, "bind address [%s] unparsable", bind->bytes); } struct AddrInterface* udpAdmin = UDPAddrInterface_new(eventBase, &bindAddr.addr, alloc, eh, logger); struct Admin* admin = Admin_new(udpAdmin, alloc, logger, eventBase, pass); char* boundAddr = Sockaddr_print(udpAdmin->addr, tempAlloc); Dict adminResponse = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST(boundAddr)), NULL ); Dict response = Dict_CONST( String_CONST("error"), String_OBJ(String_CONST("none")), Dict_CONST( String_CONST("admin"), Dict_OBJ(&adminResponse), NULL )); // This always times out because the angel doesn't respond. Hermes_callAngel(&response, angelResponse, NULL, alloc, eh, hermes); // --------------------- Setup the Logger --------------------- // Dict* logging = Dict_getDict(config, String_CONST("logging")); String* logTo = Dict_getString(logging, String_CONST("logTo")); if (logTo && String_equals(logTo, String_CONST("stdout"))) { // do nothing, continue logging to stdout. } else { struct Log* adminLogger = AdminLog_registerNew(admin, alloc, rand); IndirectLog_set(logger, adminLogger); logger = adminLogger; } // CryptoAuth struct Address addr; parsePrivateKey(privateKey, &addr, eh); struct CryptoAuth* cryptoAuth = CryptoAuth_new(alloc, privateKey, eventBase, logger, rand); struct Sockaddr* myAddr = Sockaddr_fromBytes(addr.ip6.bytes, Sockaddr_AF_INET6, alloc); struct SwitchCore* switchCore = SwitchCore_new(logger, alloc); struct DHTModuleRegistry* registry = DHTModuleRegistry_new(alloc); ReplyModule_register(registry, alloc); // Router struct RouterModule* router = RouterModule_register(registry, alloc, addr.key, eventBase, logger, admin, rand); SerializationModule_register(registry, logger, alloc); struct IpTunnel* ipTun = IpTunnel_new(logger, eventBase, alloc, rand, hermes); struct Ducttape* dt = Ducttape_register(privateKey, registry, router, switchCore, eventBase, alloc, logger, admin, ipTun, rand); struct SwitchPinger* sp = SwitchPinger_new(&dt->switchPingerIf, eventBase, logger, alloc); // Interfaces. struct InterfaceController* ifController = DefaultInterfaceController_new(cryptoAuth, switchCore, router, logger, eventBase, sp, rand, alloc); // ------------------- Register RPC functions ----------------------- // SwitchPinger_admin_register(sp, admin, alloc); UDPInterface_admin_register(eventBase, alloc, logger, admin, ifController); #ifdef HAS_ETH_INTERFACE ETHInterface_admin_register(eventBase, alloc, logger, admin, ifController); #endif RouterModule_admin_register(router, admin, alloc); AuthorizedPasswords_init(admin, cryptoAuth, alloc); Admin_registerFunction("ping", adminPing, admin, false, NULL, admin); Core_admin_register(myAddr, dt, logger, ipTun, alloc, admin, eventBase); Security_admin_register(alloc, logger, admin); IpTunnel_admin_register(ipTun, admin, alloc); struct Context* ctx = Allocator_clone(alloc, (&(struct Context) { .allocator = alloc, .admin = admin, .logger = logger, .hermes = hermes }));
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, "Dropped runt packet"); 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)) { Bits_memcpyConst(wrapper->herPerminentPubKey, header->handshake.publicKey, 32); } Message_shift(message, -Headers_CryptoAuth_SIZE); message->length = 0; wrapper->nextNonce = 0; 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); return Error_NONE; } void* user = NULL; uint8_t passwordHashStore[32]; uint8_t* passwordHash = tryAuth(header, passwordHashStore, wrapper, &user); if (wrapper->requireAuth && !user) { cryptoAuthDebug0(wrapper, "Dropping message because auth was not given"); return Error_AUTHENTICATION; } if (passwordHash == NULL && header->handshake.auth.challenge.type != 0) { cryptoAuthDebug0(wrapper, "Dropping message because it contans an authenticator which is unrecognized"); 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, "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, "Packet contains different perminent key"); 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); #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); cryptoAuthDebug0(wrapper, "Dropped message because authenticated decryption failed"); return Error_AUTHENTICATION; } wrapper->user = user; Bits_memcpyConst(wrapper->tempKey, header->handshake.encryptedTempKey, 32); #ifdef Log_DEBUG Assert_true(!Bits_isZero(header->handshake.encryptedTempKey, 32)); #endif #ifdef Log_KEYS uint8_t tempKeyHex[65]; Hex_encode(tempKeyHex, 65, wrapper->tempKey, 32); Log_keys(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) { 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->hasBufferedMessage && message->length == 0) { cryptoAuthDebug0(wrapper, "Sending buffered message"); sendMessage(wrapper->bufferedMessage, &wrapper->externalInterface); wrapper->hasBufferedMessage = false; return Error_NONE; } else if (wrapper->hasBufferedMessage) { cryptoAuthDebug0(wrapper, "There is a buffered message"); } Bits_memset(&wrapper->replayProtector, 0, sizeof(struct ReplayProtector)); setRequiredPadding(wrapper); return callReceivedMessage(wrapper, message); }
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); }
/** * Input: * { * "admin": { * "core": "/path/to/core/binary", * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * for example: * d5:admind4:core30:./build/admin/angel/cjdns-core4:bind15:127.0.0.1:123454:pass4:abcdee * * Pre-existing core mode: * { * "admin": { * "core": { * "fromCore": 12, * "toCore": 14 * }, * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * * If "core" is a dictionary, the angel will behave as though the core is already spawned and * it will read from the core on the file descriptor given by "fromCore" and write to the file * given by "toCore". * * "user" is optional, if set the angel will setuid() that user's uid. */ int AngelInit_main(int argc, char** argv) { struct Except* eh = NULL; struct Allocator* alloc = MallocAllocator_new(1<<21); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Random* rand = Random_new(alloc, logger, eh); MallocAllocator_setCanary(alloc, (long)Random_int64(rand)); struct Allocator* tempAlloc = Allocator_child(alloc); struct EventBase* eventBase = EventBase_new(alloc); struct Pipe* clientPipe = getClientPipe(argc, argv, eventBase, eh, alloc); clientPipe->logger = logger; Log_debug(logger, "Getting pre-configuration from client"); struct Message* preConf = InterfaceWaiter_waitForData(&clientPipe->iface, eventBase, alloc, eh); Log_debug(logger, "Finished getting pre-configuration from client"); struct Reader* reader = ArrayReader_new(preConf->bytes, preConf->length, tempAlloc); Dict config; if (StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, &config)) { Except_raise(eh, -1, "Failed to parse configuration."); } Dict* admin = Dict_getDict(&config, String_CONST("admin")); String* core = Dict_getString(admin, String_CONST("core")); String* bind = Dict_getString(admin, String_CONST("bind")); String* pass = Dict_getString(admin, String_CONST("pass")); String* user = Dict_getString(admin, String_CONST("user")); String* corePipeName = Dict_getString(admin, String_CONST("corePipeName")); if (!bind || !pass || (!core && !corePipeName)) { Except_raise(eh, -1, "missing configuration params in preconfig. [%s]", preConf->bytes); } if (!corePipeName) { char name[32] = {0}; Random_base32(rand, (uint8_t*)name, 31); corePipeName = String_new(name, tempAlloc); } struct Pipe* corePipe = Pipe_named(corePipeName->bytes, eventBase, eh, alloc); corePipe->logger = logger; corePipe->onClose = coreDied; struct Interface* coreIface = FramingInterface_new(65535, &corePipe->iface, alloc); if (core) { Log_info(logger, "Initializing core [%s]", core->bytes); initCore(core->bytes, corePipeName, eventBase, alloc, eh); } Log_debug(logger, "Sending pre-configuration to core."); sendConfToCore(coreIface, tempAlloc, &config, eh, logger); struct Message* coreResponse = InterfaceWaiter_waitForData(coreIface, eventBase, tempAlloc, eh); Interface_sendMessage(&clientPipe->iface, coreResponse); #ifdef Log_KEYS uint8_t lastChar = coreResponse->bytes[coreResponse->length-1]; coreResponse->bytes[coreResponse->length-1] = 0; Log_keys(logger, "Sent [%s%c] to client.", coreResponse->bytes, lastChar); coreResponse->bytes[coreResponse->length-1] = lastChar; #endif if (user) { setUser(user->bytes, logger, eh); } Allocator_free(tempAlloc); Angel_start(coreIface, eventBase, logger, alloc); return 0; }
static uint8_t encryptHandshake(struct Message* message, struct CryptoAuth_Wrapper* wrapper) { 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) Random_bytes(wrapper->context->rand, (uint8_t*) &header->handshake.auth, sizeof(union Headers_AuthChallenge) + 24); Bits_memcpyConst(&header->handshake.publicKey, wrapper->context->pub.publicKey, 32); if (!knowHerKey(wrapper)) { return genReverseHandshake(message, wrapper, header); } // 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); // 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 uint8_t sharedSecret[32]; if (wrapper->nextNonce < 2) { if (wrapper->nextNonce == 0) { cryptoAuthDebug0(wrapper, "Sending hello packet"); } else { cryptoAuthDebug0(wrapper, "Sending repeat hello packet"); } getSharedSecret(sharedSecret, wrapper->context->privateKey, wrapper->herPerminentPubKey, passwordHash, wrapper->context->logger); wrapper->isInitiator = true; wrapper->nextNonce = 1; } else { if (wrapper->nextNonce == 2) { cryptoAuthDebug0(wrapper, "Sending key packet"); } else { cryptoAuthDebug0(wrapper, "Sending repeat key packet"); } // 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 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; }
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); }
static void sendConfToCore(struct Interface* toCoreInterface, struct Allocator* alloc, Dict* config, struct Except* eh, struct Log* logger) { #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE + 32] = {0}; uint8_t* start = buff + 32; struct Writer* writer = ArrayWriter_new(start, CONFIG_BUFF_SIZE - 33, alloc); if (StandardBencSerializer_get()->serializeDictionary(writer, config)) { Except_raise(eh, -1, "Failed to serialize pre-configuration for core."); } struct Message m = { .bytes = start, .length = writer->bytesWritten(writer), .padding = 32 }; Log_keys(logger, "Sent [%d] bytes to core [%s].", m.length, m.bytes); toCoreInterface->sendMessage(&m, toCoreInterface); } static void setUser(char* user, struct Log* logger, struct Except* eh) { struct Jmp jmp; Jmp_try(jmp) { Security_setUser(user, logger, &jmp.handler); } Jmp_catch { if (jmp.code == Security_setUser_PERMISSION) { return; } Except_raise(eh, jmp.code, "%s", jmp.message); } } /** * Input: * { * "admin": { * "core": "/path/to/core/binary", * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * for example: * d5:admind4:core30:./build/admin/angel/cjdns-core4:bind15:127.0.0.1:123454:pass4:abcdee * * Pre-existing core mode: * { * "admin": { * "core": { * "fromCore": 12, * "toCore": 14 * }, * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * * If "core" is a dictionary, the angel will behave as though the core is already spawned and * it will read from the core on the file descriptor given by "fromCore" and write to the file * given by "toCore". * * "user" is optional, if set the angel will setuid() that user's uid. */ int AngelInit_main(int argc, char** argv) { struct Except* eh = NULL; int inFromClientNo; int outToClientNo; if (argc < 3 || (inFromClientNo = atoi(argv[2])) == 0) { inFromClientNo = STDIN_FILENO; } if (argc < 4 || (outToClientNo = atoi(argv[3])) == 0) { outToClientNo = STDOUT_FILENO; } struct Allocator* alloc = MallocAllocator_new(1<<21); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Random* rand = Random_new(alloc, logger, eh); alloc = CanaryAllocator_new(alloc, rand); struct Allocator* tempAlloc = Allocator_child(alloc); struct EventBase* eventBase = EventBase_new(alloc); Log_debug(logger, "Initializing angel with input [%d] and output [%d]", inFromClientNo, outToClientNo); Log_debug(logger, "Getting pre-configuration from client"); #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; Waiter_getData(buff, CONFIG_BUFF_SIZE, inFromClientNo, eventBase, eh); Log_debug(logger, "Finished getting pre-configuration from client"); struct Reader* reader = ArrayReader_new(buff, CONFIG_BUFF_SIZE, tempAlloc); Dict config; if (StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, &config)) { Except_raise(eh, -1, "Failed to parse configuration."); } Dict* admin = Dict_getDict(&config, String_CONST("admin")); String* core = Dict_getString(admin, String_CONST("core")); String* bind = Dict_getString(admin, String_CONST("bind")); String* pass = Dict_getString(admin, String_CONST("pass")); String* user = Dict_getString(admin, String_CONST("user")); int toCore = -1; int fromCore = -1; if (!core) { Dict* coreDict = Dict_getDict(admin, String_CONST("core")); int64_t* toCorePtr = Dict_getInt(coreDict, String_CONST("toCore")); int64_t* fromCorePtr = Dict_getInt(coreDict, String_CONST("fromCore")); toCore = (toCorePtr) ? *toCorePtr : -1; fromCore = (fromCorePtr) ? *fromCorePtr : -1; } if (!bind || !pass || (!core && (toCore == -1 || fromCore == -1))) { Except_raise(eh, -1, "missing configuration params in preconfig. [%s]", buff); } if (core) { Log_info(logger, "Initializing core [%s]", core->bytes); initCore(core->bytes, &toCore, &fromCore, eh); } Log_debug(logger, "Sending pre-configuration to core."); struct PipeInterface* pif = PipeInterface_new(fromCore, toCore, eventBase, logger, alloc, rand); struct Interface* coreIface = &pif->generic; PipeInterface_waitUntilReady(pif); sendConfToCore(coreIface, tempAlloc, &config, eh, logger); struct Message* coreResponse = InterfaceWaiter_waitForData(coreIface, eventBase, tempAlloc, eh); if (write(outToClientNo, coreResponse->bytes, coreResponse->length)) { // Ignore the result of write() without the compiler complaining. } #ifdef Log_KEYS uint8_t lastChar = coreResponse->bytes[coreResponse->length-1]; coreResponse->bytes[coreResponse->length-1] = 0; Log_keys(logger, "Sent [%s%c] to client.", coreResponse->bytes, lastChar); coreResponse->bytes[coreResponse->length-1] = lastChar; #endif if (user) { setUser(user->bytes, logger, eh); } Allocator_free(tempAlloc); Angel_start(coreIface, eventBase, logger, alloc); return 0; }
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } rpcCall(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. int port = atoi(lastColon+1); if (!port) { Log_critical(ctx->logger, "Couldn't get port number from [%s]", key->bytes); exit(-1); } *lastColon = '\0'; struct Sockaddr* adr = Sockaddr_fromName(key->bytes, perCallAlloc); if (adr != NULL) { Sockaddr_setPort(adr, port); key = String_new(Sockaddr_print(adr, perCallAlloc), perCallAlloc); } else { Log_warn(ctx->logger, "Failed to lookup hostname [%s]", key->bytes); entry = entry->next; continue; } } Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
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); }
/* * This process is started with 2 parameters, they must all be numeric in base 10. * toAngel the pipe which is used to send data back to the angel process. * fromAngel the pipe which is used to read incoming data from the angel. * * Upon initialization, this process will wait for an initial configuration to be sent to * it and then it will send an initial response. */ int Core_main(int argc, char** argv) { struct Except* eh = NULL; int toAngel; int fromAngel; if (argc != 4 || !(toAngel = atoi(argv[2])) || !(fromAngel = atoi(argv[3]))) { Except_raise(eh, -1, "This is internal to cjdns and shouldn't started manually."); } struct Allocator* alloc = MallocAllocator_new(ALLOCATOR_FAILSAFE); struct EventBase* eventBase = EventBase_new(alloc); struct Random* rand = Random_new(alloc, eh); // -------------------- Setup the Pre-Logger ---------------------- // struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* preLogger = WriterLog_new(logWriter, alloc); struct IndirectLog* indirectLogger = IndirectLog_new(alloc); indirectLogger->wrappedLog = preLogger; struct Log* logger = &indirectLogger->pub; // The first read inside of getInitialConfig() will begin it waiting. struct PipeInterface* pi = PipeInterface_new(fromAngel, toAngel, eventBase, logger, alloc, rand); Dict* config = getInitialConfig(&pi->generic, eventBase, alloc, eh); String* privateKeyHex = Dict_getString(config, String_CONST("privateKey")); Dict* adminConf = Dict_getDict(config, String_CONST("admin")); String* pass = Dict_getString(adminConf, String_CONST("pass")); if (!pass || !privateKeyHex) { Except_raise(eh, -1, "Expected 'pass' and 'privateKey' in configuration."); } Log_keys(logger, "Starting core with admin password [%s]", pass->bytes); uint8_t privateKey[32]; if (privateKeyHex->len != 64 || Hex_decode(privateKey, 32, (uint8_t*) privateKeyHex->bytes, 64) != 32) { Except_raise(eh, -1, "privateKey must be 64 bytes of hex."); } struct Admin* admin = Admin_new(&pi->generic, alloc, logger, eventBase, pass); Dict adminResponse = Dict_CONST(String_CONST("error"), String_OBJ(String_CONST("none")), NULL); Admin_sendMessageToAngel(&adminResponse, admin); // --------------------- Setup the Logger --------------------- // // the prelogger will nolonger be used. struct Log* adminLogger = AdminLog_registerNew(admin, alloc, rand); indirectLogger->wrappedLog = adminLogger; logger = adminLogger; // CryptoAuth struct Address addr; parsePrivateKey(privateKey, &addr, eh); struct CryptoAuth* cryptoAuth = CryptoAuth_new(alloc, privateKey, eventBase, logger, rand); struct SwitchCore* switchCore = SwitchCore_new(logger, alloc); struct DHTModuleRegistry* registry = DHTModuleRegistry_new(alloc); ReplyModule_register(registry, alloc); // Router struct RouterModule* router = RouterModule_register(registry, alloc, addr.key, eventBase, logger, admin, rand); SerializationModule_register(registry, logger, alloc); struct IpTunnel* ipTun = IpTunnel_new(logger, eventBase, alloc, rand); struct Ducttape* dt = Ducttape_register(privateKey, registry, router, switchCore, eventBase, alloc, logger, admin, ipTun, rand); struct SwitchPinger* sp = SwitchPinger_new(&dt->switchPingerIf, eventBase, logger, alloc); // Interfaces. struct InterfaceController* ifController = DefaultInterfaceController_new(cryptoAuth, switchCore, router, logger, eventBase, sp, alloc); // ------------------- Register RPC functions ----------------------- // SwitchPinger_admin_register(sp, admin, alloc); UDPInterface_admin_register(eventBase, alloc, logger, admin, ifController); #ifdef HAS_ETH_INTERFACE ETHInterface_admin_register(eventBase, alloc, logger, admin, ifController); #endif RouterModule_admin_register(router, admin, alloc); AuthorizedPasswords_init(admin, cryptoAuth, alloc); Admin_registerFunction("ping", adminPing, admin, false, NULL, admin); Admin_registerFunction("Core_exit", adminExit, logger, true, NULL, admin); Core_admin_register(addr.ip6.bytes, dt, logger, alloc, admin, eventBase); Security_admin_register(alloc, logger, admin); IpTunnel_admin_register(ipTun, admin, alloc); struct MemoryContext* mc = alloc->clone(sizeof(struct MemoryContext), alloc, &(struct MemoryContext) { .allocator = alloc, .admin = admin });
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif if (isatty(STDIN_FILENO) || argc < 2) { // Fall through. } else if (!strcmp("angel", argv[1])) { return AngelInit_main(argc, argv); } else if (!strcmp("core", argv[1])) { return Core_main(argc, argv); } Assert_true(argc > 0); struct Except* eh = NULL; // Allow it to allocate 4MB struct Allocator* allocator = MallocAllocator_new(1<<22); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if ((strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0)) { return usage(argv[0]); } else if (strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (strcmp(argv[1], "--pidfile") == 0) { // deprecated fprintf(stderr, "'--pidfile' option is deprecated.\n"); return 0; } else if (strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if ((strcmp(argv[1], "--version") == 0) || (strcmp(argv[1], "-v") == 0)) { printf("Cjdns Git Version ID: %s\n", Version_gitVersion()); return 0; } else if (strcmp(argv[1], "--cleanconf") == 0) { // Performed after reading configuration } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments\n", argv[0]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); // because of '--pidfile $filename'? if (strcmp(argv[1], "--pidfile") == 0) { fprintf(stderr, "\n'--pidfile' option is deprecated.\n"); } return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } if (argc == 2 && strcmp(argv[1], "--cleanconf") == 0) { struct Writer* stdoutWriter = FileWriter_new(stdout, allocator); JsonBencSerializer_get()->serializeDictionary(stdoutWriter, &config); printf("\n"); return 0; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = strlen(adminPass->bytes); } if (!adminBind) { Except_raise(eh, -1, "You must specify admin.bind in the cjdroute.conf file."); } // --------------------- Check for running instance --------------------- // Log_info(logger, "Checking for running instance..."); checkRunningInstance(allocator, eventBase, adminBind, adminPass, logger, eh); // --------------------- Setup Pipes to Angel --------------------- // char angelPipeName[64] = "client-angel-"; Random_base32(rand, (uint8_t*)angelPipeName+13, 31); Assert_true(EventBase_eventCount(eventBase) == 0); struct Pipe* angelPipe = Pipe_named(angelPipeName, eventBase, eh, allocator); Assert_true(EventBase_eventCount(eventBase) == 2); angelPipe->logger = logger; char* args[] = { "angel", angelPipeName, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); char* corePath = Process_getPath(allocator); if (!corePath) { Except_raise(eh, -1, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_raise(eh, -1, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath, args, eventBase, allocator); // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), String_new(corePath, allocator), allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } Dict* logging = Dict_getDict(&config, String_CONST("logging")); if (logging) { Dict_putDict(preConf, String_CONST("logging"), logging, allocator); } #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; struct Writer* toAngelWriter = ArrayWriter_new(buff, CONFIG_BUFF_SIZE - 1, allocator); if (StandardBencSerializer_get()->serializeDictionary(toAngelWriter, preConf)) { Except_raise(eh, -1, "Failed to serialize pre-configuration"); } struct Message* toAngelMsg = &(struct Message) { .bytes = buff, .length = toAngelWriter->bytesWritten }; toAngelMsg = Message_clone(toAngelMsg, allocator); Interface_sendMessage(&angelPipe->iface, toAngelMsg); Log_keys(logger, "Sent [%s] to angel process.", buff); // --------------------- Get Response from Angel --------------------- // struct Message* fromAngelMsg = InterfaceWaiter_waitForData(&angelPipe->iface, eventBase, allocator, eh); Dict responseFromAngel; struct Reader* responseFromAngelReader = ArrayReader_new(fromAngelMsg->bytes, fromAngelMsg->length, allocator); if (StandardBencSerializer_get()->parseDictionary(responseFromAngelReader, allocator, &responseFromAngel)) { Except_raise(eh, -1, "Failed to parse pre-configuration response [%s]", buff); } // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(&responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_raise(eh, -1, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_raise(eh, -1, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check, Pipe_named() creates 2 events, see above. Assert_true(EventBase_eventCount(eventBase) == 2); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); // --------------------- noBackground ------------------------ // int64_t* noBackground = Dict_getInt(&config, String_CONST("noBackground")); if (noBackground && *noBackground) { EventBase_beginLoop(eventBase); } //Allocator_free(allocator); return 0; }