From: Patrick Date: Mon, 19 Jun 2023 19:21:16 +0000 (+0200) Subject: olm session management X-Git-Url: https://gitweb.ps.run/matrix_esp_thesis/commitdiff_plain/ad9d01050b7b6d592a83ce14eeef7068bd981028?ds=sidebyside olm session management --- diff --git a/Makefile b/Makefile index 82c259a..88b1941 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,12 @@ C_OPTS+=-I src/ C_OPTS+=-I ext/olm/include/ C_OPTS+=-I ext/mjson/src/ C_OPTS+=-I ext/mongoose/ +C_OPTS+=-L out/olm/ C_OPTS+=-l ws2_32 C_OPTS+=-l ssl C_OPTS+=-l crypto +C_OPTS+=-l olm C_OPTS+=-D MG_ENABLE_OPENSSL=1 -C_OPTS+=-g # C_OPTS+=-I ext/curl/include/ # C_OPTS+=-L ext/curl/build/lib/ # C_OPTS+=-l curl @@ -23,7 +24,6 @@ C_OPTS+=-g out/examples/%: examples/%.c src/* $(CC) -o out/examples/$* examples/$*.c $(C_OPTS) - .PHONY: examples examples: out/examples/Login out/examples/Send out/examples/SendEncrypted out/examples/Sync \ No newline at end of file diff --git a/examples/Decrypt.c b/examples/Decrypt.c new file mode 100644 index 0000000..b496780 --- /dev/null +++ b/examples/Decrypt.c @@ -0,0 +1,45 @@ +#include +#include + +#define SERVER "https://matrix.org" +#define ACCESS_TOKEN "syt_cHNjaG8_yBvTjVTquGCikvsAenOJ_49mBMO" +#define DEVICE_ID "MAZNCCZLBR" +#define ROOM_ID "!koVStwyiiKcBVbXZYz:matrix.org" +#define EVENT_ID "" + +int +main(void) +{ + MatrixClient client; + MatrixClientInit(&client, + SERVER); + + MatrixHttpInit(&client); + + MatrixClientSetAccessToken(&client, + ACCESS_TOKEN); + + static char eventBuffer[1024]; + MatrixClientGetRoomEvent(&client, + ROOM_ID, + EVENT_ID, + eventBuffer, 1024); + + MatrixMegolmInSession megolmSession; + + MatrixClientRequestMegolmSession(&client, + ROOM_ID, + EVENT_ID, + &megolmSession); + + static char decryptedBuffer[1024]; + MatrixMegolmSessionDecrypt(&megolmSession, + eventBuffer, + decryptedBuffer, 1024); + + printf("%s\n", decryptedBuffer); + + MatrixHttpDeinit(&client); + + return 0; +} \ No newline at end of file diff --git a/examples/Login.c b/examples/Login.c index 45204fc..1ffbbc0 100644 --- a/examples/Login.c +++ b/examples/Login.c @@ -8,7 +8,7 @@ int -main() +main(void) { MatrixClient client; MatrixClientInit(&client, @@ -21,10 +21,10 @@ main() PASSWORD, DISPLAYNAME); - printf("Access Token: %s\n", client.accessTokenBuffer); - printf("Device ID: %s\n", client.deviceIdBuffer); - printf("Expires in (ms): %s\n", client.expireMsBuffer); - printf("Refresh Token: %s\n", client.refreshTokenBuffer); + printf("Access Token: %s\n", client.accessToken); + printf("Device ID: %s\n", client.deviceId); + printf("Expires in (ms): %s\n", client.expireMs); + printf("Refresh Token: %s\n", client.refreshToken); MatrixHttpDeinit(&client); diff --git a/examples/Send.c b/examples/Send.c index e595ba7..cddb966 100644 --- a/examples/Send.c +++ b/examples/Send.c @@ -6,7 +6,7 @@ #define ROOM_ID "!koVStwyiiKcBVbXZYz:matrix.org" int -main() +main(void) { MatrixClient client; MatrixClientInit(&client, diff --git a/examples/SendEncrypted.c b/examples/SendEncrypted.c index 2d3bd74..db2f83c 100644 --- a/examples/SendEncrypted.c +++ b/examples/SendEncrypted.c @@ -1,32 +1,36 @@ #include +#include -#define SERVER FixedBuf("matrix.org") -#define ACCESS_TOKEN FixedBuf("abc") -#define ROOM_ID FixedBuf("!jhpZBTbckszblMYjMK:matrix.org") +#define SERVER "https://matrix.org" +#define ACCESS_TOKEN "syt_cHNjaG8_yBvTjVTquGCikvsAenOJ_49mBMO" +#define DEVICE_ID "MAZNCCZLBR" +#define ROOM_ID "!koVStwyiiKcBVbXZYz:matrix.org" int -main( - int argc, - char **argv) +main(void) { MatrixClient client; - MatrixClientCreate(&client, + MatrixClientInit(&client, SERVER); + + MatrixHttpInit(&client); MatrixClientSetAccessToken(&client, ACCESS_TOKEN); - MatrixMegolmSession megolm; - MatrixMegolmSessionInit(&megolm); - - MatrixRoomShareMegolmSession(&client, - ROOM_ID, - megolm); - - MatrixClientSendGroupEncrypted(&client, + // MatrixMegolmOutSession megolmOutSession; + // MatrixMegolmOutSessionInit(&megolmOutSession); + + // MatrixClientSetMegolmOutSession(&client, + // ROOM_ID, + // megolmOutSession); + + MatrixClientSendEventEncrypted(&client, ROOM_ID, - FixedBuf("m.room.message"), - FixedBuf("{\"body\":\"Hello\",\"msgtype\":\"m.text\"}")); + "m.room.message", + "{\"body\":\"Hello\",\"msgtype\":\"m.text\"}"); + + MatrixHttpDeinit(&client); return 0; -} \ No newline at end of file +} diff --git a/examples/Sync.c b/examples/Sync.c index 5043884..a49cf65 100644 --- a/examples/Sync.c +++ b/examples/Sync.c @@ -1,31 +1,28 @@ #include +#include -#define SERVER "matrix.org" -#define ACCESS_TOKEN "abc" -#define ROOM_ID "!jhpZBTbckszblMYjMK:matrix.org" +#define SERVER "https://matrix.org" +#define ACCESS_TOKEN "syt_cHNjaG8_yBvTjVTquGCikvsAenOJ_49mBMO" +#define DEVICE_ID "MAZNCCZLBR" int -main( - int argc, - char **argv) +main(void) { MatrixClient client; - MatrixClientCreate(&client, + MatrixClientInit(&client, SERVER); + + MatrixHttpInit(&client); MatrixClientSetAccessToken(&client, ACCESS_TOKEN); - static char syncCharBuffer[1024]; - FixedBuffer syncBuffer = { syncCharBuffer, 1024, 0 }; - int syncN = 1; - - while (syncN > 0) - { - MatrixClientSyncN(&client, &syncBuffer, &syncN); - printf("%.*s", syncBuffer.len, (char *)syncBuffer.ptr); - } - printf("\n"); + static char syncBuffer[20000]; + MatrixClientSync(&client, + syncBuffer, 20000); + printf("%s", syncBuffer); + + MatrixHttpDeinit(&client); return 0; } \ No newline at end of file diff --git a/src/fixedbuffer.c b/src/fixedbuffer.c deleted file mode 100644 index ad99897..0000000 --- a/src/fixedbuffer.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "fixedbuffer.h" - -#include - -FixedBuffer -FixedBuf(const char * str) -{ - int len = strlen(str); - FixedBuffer result; - result.ptr = (char *)str; - result.cap = len; - result.len = len; - return result; -} - -bool -FixedBufferToInt(FixedBuffer fb, int * outInt) -{ - bool valid = false; - int result = 0; - - bool negative = false; - - for (int i = 0; i < fb.len; i++) - { - if (i == 0 && fb.ptr[i] == '-') - { - negative = true; - continue; - } - - int val = fb.ptr[i] - '0'; - if (val < 0 || val > 9) - return false; - - result *= 10; - result += val; - valid = true; - } - - *outInt = result; - return valid; -} \ No newline at end of file diff --git a/src/fixedbuffer.h b/src/fixedbuffer.h deleted file mode 100644 index d8055cb..0000000 --- a/src/fixedbuffer.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FIXEDBUFFER__H -#define FIXEDBUFFER__H - -#include - -typedef struct FixedBuffer { - char * ptr; - int cap; - int len; -} FixedBuffer; - -FixedBuffer -FixedBuf(const char * str); - -bool -FixedBufferToInt(FixedBuffer fb, int * outInt); - - -#endif \ No newline at end of file diff --git a/src/matrix.c b/src/matrix.c index 7cc4de9..28e7634 100644 --- a/src/matrix.c +++ b/src/matrix.c @@ -9,21 +9,153 @@ #define LOGIN_RESPONSE_SIZE 1024 #define LOGIN_URL "/_matrix/client/v3/login" -#define ROOMEVENT_REQUEST_SIZE 1024 +#define ENCRYPTED_REQUEST_SIZE 512 +#define ENCRYPTED_EVENT_SIZE 1024 +#define ROOMEVENT_REQUEST_SIZE 256 #define ROOMEVENT_RESPONSE_SIZE 1024 #define ROOMEVENT_URL "/_matrix/client/v3/rooms/%s/send/%s/%d" +#define TODEVICE_EVENT_SIZE 512 +#define TODEVICE_URL "/_matrix/client/v3/sendToDevice/%s/%d" + +#define KEYS_QUERY_URL "/_matrix/client/v3/keys/query" +#define KEYS_QUERY_REQUEST_SIZE 256 +#define KEYS_QUERY_RESPONSE_SIZE 1024 + +#define JSON_QUERY_SIZE 128 + + + +void +Randomize(uint8_t * random, int randomLen) +{ + static bool first = false; + if (first) { srand(time(0)); first = false; } + + for (int i = 0; i < randomLen; i++) + { + random[i] = rand() % 256; + } +} + +bool +JsonEscape( + char * sIn, int sInLen, + char * sOut, int sOutCap) +{ + int sOutIndex = 0; + + for (int i = 0; i < sInLen; i++) + { + if (i >= sOutCap) + return false; + + if (sIn[i] == '.' || + sIn[i] == '[' || + sIn[i] == ']' + ) { + sOut[sOutIndex++] = '\\'; + } + sOut[sOutIndex++] = sIn[i]; + } + + if (sOutIndex < sOutCap) + sOut[sOutIndex] = '\0'; + + return true; +} + +// TODO: in/outbound sessions +bool +MatrixOlmSessionInit( + MatrixOlmSession * session, + const char * deviceId) +{ + memset(session, 0, sizeof(MatrixOlmSession)); + + static uint8_t random[MEGOLM_INIT_RANDOM_SIZE]; + Randomize(random, MEGOLM_INIT_RANDOM_SIZE); + + session->deviceId = deviceId; + + session->session = + olm_session(session->memory); + + return session->session != NULL; +} + +bool +MatrixOlmSessionEncrypt( + MatrixOlmSession * session, + const char * plaintext, + char * outBuffer, int outBufferCap) +{ + static uint8_t random[OLM_ENCRYPT_RANDOM_SIZE]; + Randomize(random, OLM_ENCRYPT_RANDOM_SIZE); + + size_t res = olm_encrypt(session->session, + plaintext, strlen(plaintext), + random, OLM_ENCRYPT_RANDOM_SIZE, + outBuffer, outBufferCap); + + return res != olm_error(); +} + +// https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#starting-a-megolm-session +bool +MatrixMegolmOutSessionInit( + MatrixMegolmOutSession * session, + const char * roomId) +{ + memset(session, 0, sizeof(MatrixMegolmOutSession)); + + static uint8_t random[MEGOLM_INIT_RANDOM_SIZE]; + Randomize(random, MEGOLM_INIT_RANDOM_SIZE); + + session->roomId = roomId; + + session->session = + olm_outbound_group_session(session->memory); + + olm_init_outbound_group_session( + session->session, + random, + MEGOLM_INIT_RANDOM_SIZE); + + olm_outbound_group_session_id(session->session, + (uint8_t *)session->id, + MEGOLM_SESSION_ID_SIZE); + + olm_outbound_group_session_key(session->session, + (uint8_t *)session->key, + MEGOLM_SESSION_KEY_SIZE); + + return true; +} + +bool +MatrixMegolmOutSessionEncrypt( + MatrixMegolmOutSession * session, + const char * plaintext, + char * outBuffer, int outBufferCap) +{ + size_t res = olm_group_encrypt(session->session, + (uint8_t *)plaintext, strlen(plaintext), + (uint8_t *)outBuffer, outBufferCap); + + return res != olm_error(); +} + + bool MatrixClientInit( MatrixClient * client, const char * server) { - strcpy_s( - client->server, - SERVER_SIZE, - server - ); + memset(client, 0, sizeof(MatrixClient)); + + strcpy(client->server, server); return true; } @@ -39,7 +171,7 @@ MatrixClientSetAccessToken( return false; for (int i = 0; i < accessTokenLen; i++) - client->accessTokenBuffer[i] = accessToken[i]; + client->accessToken[i] = accessToken[i]; return true; } @@ -83,20 +215,21 @@ MatrixClientLoginPassword( mjson_get_string(responseBuffer, responseLen, "$.access_token", - client->accessTokenBuffer, ACCESS_TOKEN_SIZE); + client->accessToken, ACCESS_TOKEN_SIZE); mjson_get_string(responseBuffer, responseLen, "$.device_id", - client->deviceIdBuffer, DEVICE_ID_SIZE); + client->deviceId, DEVICE_ID_SIZE); mjson_get_string(responseBuffer, responseLen, "$.expires_in_ms", - client->expireMsBuffer, EXPIRE_MS_SIZE); + client->expireMs, EXPIRE_MS_SIZE); mjson_get_string(responseBuffer, responseLen, "$.refresh_token", - client->refreshTokenBuffer, REFRESH_TOKEN_SIZE); + client->refreshToken, REFRESH_TOKEN_SIZE); return true; } - + +// https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid bool MatrixClientSendEvent( MatrixClient * client, @@ -105,8 +238,8 @@ MatrixClientSendEvent( const char * msgBody) { static char requestUrl[MAX_URL_LEN]; - sprintf_s(requestUrl, MAX_URL_LEN, - ROOMEVENT_URL, roomId, msgType, time(NULL)); + sprintf(requestUrl, + ROOMEVENT_URL, roomId, msgType, (int)time(NULL)); static char responseBuffer[ROOMEVENT_RESPONSE_SIZE]; bool result = @@ -119,3 +252,408 @@ MatrixClientSendEvent( return result; } +// https://spec.matrix.org/v1.6/client-server-api/#mroomencrypted +// https://matrix.org/docs/guides/end-to-end-encryption-implementation-guide#sending-an-encrypted-message-event +bool +MatrixClientSendEventEncrypted( + MatrixClient * client, + const char * roomId, + const char * msgType, + const char * msgBody) +{ + // event json + static char requestBuffer[ROOMEVENT_REQUEST_SIZE]; + sprintf(requestBuffer, + "{" + "\"type\":\"%s\"," + "\"content\":%s," + "\"room_id\":\"%s\"" + "}", + msgType, + msgBody, + roomId); + + // get megolm session + MatrixMegolmOutSession * outSession; + MatrixClientGetMegolmOutSession(client, roomId, &outSession); + + // encrypt + static char encryptedBuffer[ENCRYPTED_REQUEST_SIZE]; + MatrixMegolmOutSessionEncrypt(outSession, + requestBuffer, + encryptedBuffer, ENCRYPTED_REQUEST_SIZE); + + // encrypted event json + const char * senderKey = client->deviceKey; + const char * sessionId = outSession->id; + const char * deviceId = client->deviceId; + + static char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE]; + sprintf(encryptedEventBuffer, + "{" + "\"algorithm\":\"m.megolm.v1.aes-sha2\"," + "\"sender_key\":\"%s\"," + "\"ciphertext\":\"%s\"," + "\"session_id\":%s," + "\"device_id\":\"%s\"" + "}", + senderKey, + encryptedBuffer, + sessionId, + deviceId); + + // send + return MatrixClientSendEvent(client, + roomId, + "m.room.encrypted", + encryptedEventBuffer); +} + +// https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv3sync +bool +MatrixClientSync( + MatrixClient * client, + char * outSyncBuffer, int outSyncCap) +{ + return + MatrixHttpGet(client, + "/_matrix/client/v3/sync", + outSyncBuffer, outSyncCap, + true); +} + +bool +MatrixClientShareMegolmOutSession( + MatrixClient * client, + const char * deviceId, + MatrixMegolmOutSession * session) +{ + // generate room key event + char eventBuffer[KEY_SHARE_EVENT_LEN]; + sprintf(eventBuffer, + "{" + "\"algorithm\":\"m.megolm.v1.aes-sha2\"," + "\"room_id\":\"%s\"," + "\"session_id\":\"%s\"," + "\"session_key\":\"%s\"" + "}", + session->roomId, + session->id, + session->key + ); + + // get olm session + MatrixOlmSession * olmSession; + MatrixClientGetOlmSession(client, deviceId, &olmSession); + + // encrypt + char encryptedBuffer[KEY_SHARE_EVENT_LEN]; + MatrixOlmSessionEncrypt(olmSession, + eventBuffer, + encryptedBuffer, KEY_SHARE_EVENT_LEN); + + // send + MatrixClientSendToDeviceEncrypted(client, + client->userId, + deviceId, + encryptedBuffer, + "m.room_key"); + + return true; +} + +// bool +// MatrixClientSetMegolmOutSession( +// MatrixClient * client, +// const char * roomId, +// MatrixMegolmOutSession session) +// { +// if (client->numMegolmOutSessions < 10) +// { +// session.roomId = roomId; +// client->megolmOutSessions[client->numMegolmOutSessions] = session; +// client->numMegolmOutSessions++; + +// return true; +// } +// return false; +// } + +bool +MatrixClientGetMegolmOutSession( + MatrixClient * client, + const char * roomId, + MatrixMegolmOutSession ** outSession) +{ + for (int i = 0; i < client->numMegolmOutSessions; i++) + { + if (strcmp(client->megolmOutSessions[i].roomId, roomId) == 0) + { + *outSession = &client->megolmOutSessions[i]; + return true; + } + } + + if (client->numMegolmOutSessions < NUM_MEGOLM_SESSIONS) + { + MatrixMegolmOutSessionInit( + &client->megolmOutSessions[client->numMegolmOutSessions], + roomId); + + *outSession = &client->megolmOutSessions[client->numMegolmOutSessions]; + + client->numMegolmOutSessions++; + + return true; + } + + return false; +} + +bool +MatrixClientGetOlmSession( + MatrixClient * client, + const char * deviceId, + MatrixOlmSession ** outSession) +{ + for (int i = 0; i < client->numOlmSessions; i++) + { + if (strcmp(client->olmSessions[i].deviceId, deviceId) == 0) + { + *outSession = &client->olmSessions[i]; + return true; + } + } + + if (client->numOlmSessions < NUM_OLM_SESSIONS) + { + MatrixOlmSessionInit( + &client->olmSessions[client->numOlmSessions], + deviceId); + + *outSession = &client->olmSessions[client->numOlmSessions]; + + client->numOlmSessions++; + + return true; + } + + return false; +} + +// https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3sendtodeviceeventtypetxnid +bool +MatrixClientSendToDevice( + MatrixClient * client, + const char * userId, + const char * deviceId, + const char * message, + const char * msgType) +{ + static char requestUrl[MAX_URL_LEN]; + sprintf(requestUrl, + TODEVICE_URL, msgType, (int)time(NULL)); + + static char eventBuffer[TODEVICE_EVENT_SIZE]; + snprintf(eventBuffer, TODEVICE_EVENT_SIZE, + "{" + "\"messages\": {" + "\"%s\": {" + "\"%s\":%s" + "}" + "}" + "}", + userId, + deviceId, + message); + + static char responseBuffer[ROOMEVENT_RESPONSE_SIZE]; + bool result = + MatrixHttpPut(client, + requestUrl, + eventBuffer, + responseBuffer, ROOMEVENT_RESPONSE_SIZE, + true); + + return result; +} + +bool +MatrixClientSendToDeviceEncrypted( + MatrixClient * client, + const char * userId, + const char * deviceId, + const char * message, + const char * msgType) +{ + // get olm session + MatrixOlmSession * olmSession; + MatrixClientGetOlmSession(client, deviceId, &olmSession); + + // create event json + char deviceKey[DEVICE_KEY_SIZE]; + MatrixClientGetDeviceKey(client, deviceId, deviceKey, DEVICE_KEY_SIZE); + const char * senderKey = client->deviceKey; + + static char eventBuffer[TODEVICE_EVENT_SIZE]; + sprintf(eventBuffer, + "{" + "\"type\": \"%s\"," + "\"content\": \"%s\"," + "\"sender\": \"%s\"," + "\"recipient\": \"%s\"," + "\"recipient_keys\": {" + "\"ed25519\": \"%s\"" + "}," + "\"keys\": {" + "\"ed25519\": \"%s\"" + "}" + "}", + msgType, + message, + client->userId, + userId, // recipient user id + deviceKey, // recipient device key + client->deviceKey); + + // encrypt + static char encryptedBuffer[ENCRYPTED_REQUEST_SIZE]; + MatrixOlmSessionEncrypt(olmSession, + eventBuffer, + encryptedBuffer, ENCRYPTED_REQUEST_SIZE); + + static char encryptedEventBuffer[ENCRYPTED_EVENT_SIZE]; + sprintf(encryptedEventBuffer, + "{" + "\"algorithm\":\"m.megolm.v1.aes-sha2\"," + "\"sender_key\":\"%s\"," + "\"ciphertext\":{" + "\"%s\":{" + "\"body\":\"%s\"," + "\"type\":\"%d\"" + "}" + "}" + "}", + senderKey, + deviceKey, + encryptedBuffer, + olmSession->type); + + // send + return MatrixClientSendToDevice( + client, + userId, + deviceId, + encryptedEventBuffer, + "m.room.encrypted"); +} + +bool +MatrixClientFindDevice( + MatrixClient * client, + const char * deviceId, + MatrixDevice ** outDevice) +{ + MatrixClientRequestDeviceKeys(client); + + for (int i = 0; i < client->numDevices; i++) + { + if (strcmp(client->devices[i].deviceId, deviceId) == 0) + { + *outDevice = &client->devices[i]; + return true; + } + } + + *outDevice = NULL; + return false; +} + +bool +MatrixClientGetDeviceKey( + MatrixClient * client, + const char * deviceId, + char * outDeviceKey, int outDeviceKeyCap) +{ + MatrixClientRequestDeviceKeys(client); + + MatrixDevice * device; + if (MatrixClientFindDevice(client, deviceId, &device)) + { + strncpy(outDeviceKey, device->deviceKey, outDeviceKeyCap); + return true; + } + + return false; +} + +// https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3keysquery +bool +MatrixClientRequestDeviceKeys( + MatrixClient * client) +{ + char userIdEscaped[USER_ID_SIZE]; + JsonEscape(client->userId, strlen(client->userId), + userIdEscaped, USER_ID_SIZE); + + char request[KEYS_QUERY_REQUEST_SIZE]; + snprintf(request, KEYS_QUERY_REQUEST_SIZE, + "{\"device_keys\":{\"%s\":[]}}", userIdEscaped); + + char responseBuffer[KEYS_QUERY_RESPONSE_SIZE]; + bool requestResult = MatrixHttpPost(client, + KEYS_QUERY_URL, + request, + responseBuffer, KEYS_QUERY_RESPONSE_SIZE, + true); + + if (requestResult) + { + // query for retrieving device keys for user id + char query[JSON_QUERY_SIZE]; + snprintf(query, JSON_QUERY_SIZE, + "$.device_keys.%s", userIdEscaped); + + const char * s; + int slen; + mjson_find(responseBuffer, strlen(responseBuffer), + query, &s, &slen); + + // loop over keys + + int koff, klen, voff, vlen, vtype, off; + for (off = 0; (off = mjson_next(s, slen, off, &koff, &klen, + &voff, &vlen, &vtype)) != 0; ) { + const char * key = s + koff; + const char * val = s + voff; + + // set device id, "key" is the JSON key + MatrixDevice d; + strncpy(d.deviceId, key, klen); + + // look for device key in value + char deviceKeyQuery[JSON_QUERY_SIZE]; + snprintf(deviceKeyQuery, JSON_QUERY_SIZE, + "$.keys.curve25519:%.*s", klen, key); + mjson_get_string(val, vlen, + deviceKeyQuery, d.deviceKey, DEVICE_KEY_SIZE); + + // add device + if (client->numDevices < NUM_DEVICES) + { + client->devices[client->numDevices] = d; + client->numDevices++; + } + else + { + return false; + } + } + + return true; + } + else + { + return false; + } +} diff --git a/src/matrix.h b/src/matrix.h index 2e7f6e0..6538e12 100644 --- a/src/matrix.h +++ b/src/matrix.h @@ -2,13 +2,15 @@ #define MATRIX__H #include +#include #include +#include #include -// TODO: fix +#define USER_ID_SIZE 64 #define SERVER_SIZE 20 #define ACCESS_TOKEN_SIZE 40 #define DEVICE_ID_SIZE 20 @@ -16,16 +18,105 @@ #define REFRESH_TOKEN_SIZE 20 #define MAX_URL_LEN 128 +#define DEVICE_KEY_SIZE 20 + +#define KEY_SHARE_EVENT_LEN 1024 + +#define OLM_SESSION_MEMORY_SIZE 3352 +#define OLM_ENCRYPT_RANDOM_SIZE 32 + +#define MEGOLM_OUTBOUND_SESSION_MEMORY_SIZE 232 +#define MEGOLM_SESSION_ID_SIZE 44 +#define MEGOLM_SESSION_KEY_SIZE 306 +#define MEGOLM_INIT_RANDOM_SIZE (4*32 + 32) + +#define NUM_MEGOLM_SESSIONS 10 +#define NUM_OLM_SESSIONS 10 +#define NUM_DEVICES 10 + +void +Randomize(uint8_t * random, int randomLen); + +bool +JsonEscape( + char * sIn, int sInLen, + char * sOut, int sOutCap); + +typedef struct MatrixDevice { + char deviceId[DEVICE_ID_SIZE]; + char deviceKey[DEVICE_KEY_SIZE]; +} MatrixDevice; + +typedef struct MatrixOlmSession { + const char * deviceId; + + int type; + OlmSession * session; + char memory[OLM_SESSION_MEMORY_SIZE]; +} MatrixOlmSession; + +bool +MatrixOlmSessionInit( + MatrixOlmSession * session, + const char * deviceId); + +bool +MatrixOlmSessionEncrypt( + MatrixOlmSession * session, + const char * plaintext, + char * outBuffer, int outBufferCap); + + + +typedef struct MatrixMegolmInSession { + OlmInboundGroupSession * session; +} MatrixMegolmInSession; + +typedef struct MatrixMegolmOutSession { + const char * roomId; + + OlmOutboundGroupSession * session; + char memory[MEGOLM_OUTBOUND_SESSION_MEMORY_SIZE]; + + char id[MEGOLM_SESSION_ID_SIZE]; + char key[MEGOLM_SESSION_KEY_SIZE]; +} MatrixMegolmOutSession; + +bool +MatrixMegolmOutSessionInit( + MatrixMegolmOutSession * session, + const char * roomId); + +bool +MatrixMegolmOutSessionEncrypt( + MatrixMegolmOutSession * session, + const char * plaintext, + char * outBuffer, int outBufferCap); + + typedef struct MatrixClient { OlmAccount * olmAccount; OlmSession * olmSession; + + MatrixMegolmInSession megolmInSessions[NUM_MEGOLM_SESSIONS]; + int numMegolmInSessions; + MatrixMegolmOutSession megolmOutSessions[NUM_MEGOLM_SESSIONS]; + int numMegolmOutSessions; + MatrixOlmSession olmSessions[NUM_OLM_SESSIONS]; + int numOlmSessions; - char server[SERVER_SIZE+1]; - char accessTokenBuffer[ACCESS_TOKEN_SIZE]; - char deviceIdBuffer[DEVICE_ID_SIZE]; - char expireMsBuffer[EXPIRE_MS_SIZE]; - char refreshTokenBuffer[REFRESH_TOKEN_SIZE]; + MatrixDevice devices[NUM_DEVICES]; + int numDevices; + + char deviceKey[DEVICE_KEY_SIZE]; + + char userId[USER_ID_SIZE]; + char server[SERVER_SIZE]; + char accessToken[ACCESS_TOKEN_SIZE]; + char deviceId[DEVICE_ID_SIZE]; + char expireMs[EXPIRE_MS_SIZE]; + char refreshToken[REFRESH_TOKEN_SIZE]; void * httpUserData; } MatrixClient; @@ -53,6 +144,76 @@ MatrixClientSendEvent( const char * roomId, const char * msgType, const char * msgBody); + +bool +MatrixClientSendEventEncrypted( + MatrixClient * client, + const char * roomId, + const char * msgType, + const char * msgBody); + +bool +MatrixClientSync( + MatrixClient * client, + char * outSyncBuffer, int outSyncCap); + +bool +MatrixClientShareMegolmOutSession( + MatrixClient * client, + const char * deviceId, + MatrixMegolmOutSession * session); + +bool +MatrixClientGetMegolmOutSession( + MatrixClient * client, + const char * roomId, + MatrixMegolmOutSession ** outSession); + +bool +MatrixClientSetMegolmOutSession( + MatrixClient * client, + const char * roomId, + MatrixMegolmOutSession session); + +bool +MatrixClientGetOlmSession( + MatrixClient * client, + const char * deviceId, + MatrixOlmSession ** outSession); + +bool +MatrixClientSendToDevice( + MatrixClient * client, + const char * userId, + const char * deviceId, + const char * message, + const char * msgType); + +bool +MatrixClientSendToDeviceEncrypted( + MatrixClient * client, + const char * userId, + const char * deviceId, + const char * message, + const char * msgType); + +bool +MatrixClientGetDeviceKey( + MatrixClient * client, + const char * deviceId, + char * outDeviceKey, int outDeviceKeyCap); + +bool +MatrixClientGetDeviceKey( + MatrixClient * client, + const char * deviceId, + char * outDeviceKey, int outDeviceKeyCap); + +bool +MatrixClientRequestDeviceKeys( + MatrixClient * client); + + bool MatrixHttpInit( diff --git a/src/matrix_http_mongoose.c b/src/matrix_http_mongoose.c index 8d575e5..020b4c8 100644 --- a/src/matrix_http_mongoose.c +++ b/src/matrix_http_mongoose.c @@ -1,4 +1,5 @@ #include "matrix.h" + #include #include #include @@ -35,7 +36,8 @@ MatrixHttpCallback( // If s_url is https://, tell client connection to use TLS if (mg_url_is_ssl(client->server)) { - struct mg_tls_opts opts = {.srvname = host}; + struct mg_tls_opts opts; + opts.srvname = host; mg_tls_init(c, &opts); } @@ -48,10 +50,13 @@ MatrixHttpCallback( struct mg_http_message *hm = (struct mg_http_message *)ev_data; // memcpy_s(client->data, 1024, hm->message.ptr, hm->message.len); // client->dataLen = hm->message.len; - memcpy_s(conn->data, conn->dataCap, hm->body.ptr, hm->body.len); + memcpy(conn->data, hm->body.ptr, hm->body.len); + // memcpy_s(conn->data, conn->dataCap, hm->body.ptr, hm->body.len); conn->data[hm->body.len] = '\0'; conn->dataLen = hm->body.len; conn->dataReceived = true; + + printf("received[%d]:\n%.*s\n", conn->dataLen, conn->dataLen, conn->data); } } @@ -100,10 +105,14 @@ MatrixHttpGet( struct mg_str host = mg_url_host(client->server); - static char authorizationHeader[AUTHORIZATION_HEADER_LEN] = "\0"; + static char authorizationHeader[AUTHORIZATION_HEADER_LEN]; if (authenticated) - sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN, - "Authorization: Bearer %s\r\n", client->accessTokenBuffer); + sprintf(authorizationHeader, + "Authorization: Bearer %s\r\n", client->accessToken); + // sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN, + // "Authorization: Bearer %s\r\n", client->accessToken); + else + authorizationHeader[0] = '\0'; mg_printf(conn->connection, "GET %s HTTP/1.1\r\n" @@ -137,10 +146,12 @@ MatrixHttpPost( struct mg_str host = mg_url_host(client->server); - static char authorizationHeader[AUTHORIZATION_HEADER_LEN] = "\0"; + static char authorizationHeader[AUTHORIZATION_HEADER_LEN]; if (authenticated) - sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN, - "Authorization: Bearer %s\r\n", client->accessTokenBuffer); + sprintf(authorizationHeader, + "Authorization: Bearer %s\r\n", client->accessToken); + else + authorizationHeader[0] = '\0'; mg_printf(conn->connection, "POST %s HTTP/1.0\r\n" @@ -182,8 +193,8 @@ MatrixHttpPut( static char authorizationHeader[AUTHORIZATION_HEADER_LEN]; if (authenticated) - sprintf_s(authorizationHeader, AUTHORIZATION_HEADER_LEN, - "Authorization: Bearer %s\r\n", client->accessTokenBuffer); + sprintf(authorizationHeader, + "Authorization: Bearer %s\r\n", client->accessToken); else authorizationHeader[0] = '\0';