/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "crypto/test/TestCa.h"
#include "crypto/CryptoAuth.h"
#include "rust/cjdns_sys/Rffi.h"
#include "util/Hex.h"
struct TestCa_s {
RTypes_CryptoAuth2_t* ca2;
struct CryptoAuth* ca;
bool noise;
};
typedef struct TestCa_Session_pvt_s {
TestCa_Session_t pub;
RTypes_CryptoAuth2_Session_t* s2;
struct CryptoAuth_Session* s;
struct Iface sPlain;
struct Iface sCipher;
struct Iface s2Plain;
struct Iface s2Cipher;
Identity
} TestCa_Session_pvt_t;
TestCa_t* TestCa_new(
Allocator_t *allocator,
const uint8_t *privateKey,
struct EventBase* eventBase,
struct Log* logger,
struct Random* rand0,
struct Random* rand1,
enum TestCa_Config cfg)
{
TestCa_t* out = Allocator_calloc(allocator, sizeof(TestCa_t), 1);
if (cfg == TestCa_Config_OLD || cfg == TestCa_Config_OLD_NEW) {
out->ca = CryptoAuth_new(allocator, privateKey, eventBase, logger, rand0);
}
if (cfg == TestCa_Config_OLD_NEW || cfg == TestCa_Config_NOISE) {
out->ca2 = Rffi_CryptoAuth2_new(allocator, privateKey, rand1);
}
if (cfg == TestCa_Config_NOISE) {
out->noise = true;
}
return out;
}
int TestCa_addUser_ipv6(
String_t *password,
String_t *login,
uint8_t *ipv6,
TestCa_t *ca)
{
int ret = 0;
if (ca->ca) {
ret = CryptoAuth_addUser_ipv6(password, login, ipv6, ca->ca);
}
if (ca->ca2) {
int ret2 = Rffi_CryptoAuth2_addUser_ipv6(password, login, ipv6, ca->ca2);
if (ca->ca) {
Assert_true(ret == ret2);
}
return ret2;
}
return ret;
}
int TestCa_removeUsers(TestCa_t* ca, String_t* user)
{
int i1 = 0;
if (ca->ca) {
i1 = CryptoAuth_removeUsers(ca->ca, user);
}
if (ca->ca2) {
int i2 = Rffi_CryptoAuth2_removeUsers(ca->ca2, user);
if (ca->ca) {
Assert_true(i1 == i2);
}
return i2;
}
return i1;
}
RTypes_StrList_t* TestCa_getUsers(const TestCa_t *ca, Allocator_t *alloc)
{
RTypes_StrList_t* l1 = NULL;
if (ca->ca) {
l1 = CryptoAuth_getUsers(ca->ca, alloc);
}
if (ca->ca2) {
RTypes_StrList_t* l2 = Rffi_CryptoAuth2_getUsers(ca->ca2, alloc);
Assert_true(l1->len == l2->len);
for (uintptr_t i = 0; i < l1->len; i++) {
Assert_true(String_equals(l1->items[i], l2->items[i]));
}
return l2;
}
return l1;
}
#define PASS 1
#define STOP 2
#define VERIFY 3
#include
static Iface_DEFUN messagePlaintext(Message_t *msg, struct Iface* iface)
{
TestCa_Session_pvt_t* sess = Identity_containerOf(iface, TestCa_Session_pvt_t, pub.plaintext);
Message_t* m2 = NULL;
if (sess->s2) {
if (sess->s) {
m2 = Message_clone(msg, Message_getAlloc(msg));
} else {
m2 = msg;
msg = NULL;
}
}
struct RTypes_Error_t* i1 = NULL;
if (sess->s) {
int flag = sess->s2 ? STOP : PASS;
Er_assert(Message_epushAd(msg, &flag, sizeof flag));
printf("Send [%d]\n", flag);
i1 = Iface_send(&sess->sPlain, msg);
}
if (sess->s2) {
if (sess->s) {
Er_assert(Message_epushAd(m2, &msg, sizeof &msg));
}
int flag = sess->s ? VERIFY : PASS;
Er_assert(Message_epushAd(m2, &flag, sizeof flag));
printf("Send2 [%d]\n", flag);
struct RTypes_Error_t* i2 = Iface_send(&sess->s2Plain, m2);
if (sess->s) {
Assert_true((i2 == NULL) == (i1 == NULL));
}
printf("Send2 done\n");
return i2;
}
return i1;
}
static Iface_DEFUN messageCiphertext(Message_t *msg, struct Iface* iface)
{
TestCa_Session_pvt_t* sess = Identity_containerOf(iface, TestCa_Session_pvt_t, pub.ciphertext);
Message_t* m2 = NULL;
if (sess->s2) {
if (sess->s) {
m2 = Message_clone(msg, Message_getAlloc(msg));
} else {
m2 = msg;
msg = NULL;
}
}
struct RTypes_Error_t* i1 = NULL;
if (sess->s) {
int flag = sess->s2 ? STOP : PASS;
Er_assert(Message_epushAd(msg, &flag, sizeof flag));
i1 = Iface_send(&sess->sCipher, msg);
}
if (sess->s2) {
int flag = PASS;
if (sess->s) {
uintptr_t mp = (uintptr_t)msg;
Er_assert(Message_epushAd(m2, &mp, sizeof &mp));
flag = VERIFY;
}
Er_assert(Message_epushAd(m2, &flag, sizeof flag));
struct RTypes_Error_t* i2 = Iface_send(&sess->s2Cipher, m2);
if (sess->s) {
Assert_true((i2 == NULL) == (i1 == NULL));
}
return i2;
}
return i1;
}
static bool check(Message_t *msg, TestCa_Session_pvt_t* sess)
{
int flag = 0;
Er_assert(Message_epopAd(msg, &flag, sizeof flag));
if (flag == PASS) {
printf("Passing message\n");
} else if (flag == STOP) {
// do nothing, wait for the next message to come through....
printf("Stopping message\n");
return true;
} else if (flag == VERIFY) {
uintptr_t m2p = 0;
Er_assert(Message_epopAd(msg, &m2p, sizeof m2p));
printf("Verifying message %lx\n", m2p);
struct Message* m2 = (struct Message*) m2p;
if (Message_getLength(msg) != Message_getLength(m2)) {
Assert_failure("Message_getLength(msg) != m2->length: %d != %d",
Message_getLength(msg), Message_getLength(m2));
}
if (Bits_memcmp(msg->msgbytes, m2->msgbytes, Message_getLength(msg))) {
const char* msgH = Hex_print(msg->msgbytes, Message_getLength(msg), Message_getAlloc(msg));
const char* m2H = Hex_print(m2->msgbytes, Message_getLength(m2), Message_getAlloc(m2));
Assert_failure("msg->bytes != m2->bytes:\n%s\n%s\n", msgH, m2H);
}
Assert_true(!Bits_memcmp(msg->msgbytes, m2->msgbytes, Message_getLength(msg)));
} else {
Assert_failure("unexpected flag [%d]", flag);
}
return false;
}
static Iface_DEFUN sPlainRecv(Message_t *msg, struct Iface* iface)
{
TestCa_Session_pvt_t* sess = Identity_containerOf(iface, TestCa_Session_pvt_t, sPlain);
if (check(msg, sess)) { return NULL; }
return Iface_next(&sess->pub.plaintext, msg);
}
static Iface_DEFUN s2PlainRecv(Message_t *msg, struct Iface* iface)
{
TestCa_Session_pvt_t* sess = Identity_containerOf(iface, TestCa_Session_pvt_t, s2Plain);
if (check(msg, sess)) { return NULL; }
return Iface_next(&sess->pub.plaintext, msg);
}
static Iface_DEFUN sCipherRecv(Message_t *msg, struct Iface* iface)
{
TestCa_Session_pvt_t* sess = Identity_containerOf(iface, TestCa_Session_pvt_t, sCipher);
if (check(msg, sess)) { return NULL; }
return Iface_next(&sess->pub.ciphertext, msg);
}
static Iface_DEFUN s2CipherRecv(Message_t *msg, struct Iface* iface)
{
TestCa_Session_pvt_t* sess = Identity_containerOf(iface, TestCa_Session_pvt_t, s2Cipher);
if (check(msg, sess)) { return NULL; }
return Iface_next(&sess->pub.ciphertext, msg);
}
TestCa_Session_t* TestCa_newSession(
TestCa_t *ca,
Allocator_t *alloc,
const uint8_t *herPublicKey,
bool requireAuth,
char *name,
bool useNoise)
{
TestCa_Session_pvt_t* out = Allocator_calloc(alloc, sizeof(TestCa_Session_pvt_t), 1);
Identity_set(out);
out->sCipher.send = sCipherRecv;
out->sPlain.send = sPlainRecv;
out->s2Cipher.send = s2CipherRecv;
out->s2Plain.send = s2PlainRecv;
if (ca->ca) {
out->s = CryptoAuth_newSession(ca->ca, alloc, herPublicKey, requireAuth, name, false);
Iface_plumb(&out->sCipher, &out->s->ciphertext);
Iface_plumb(&out->sPlain, &out->s->plaintext);
}
if (ca->ca2) {
out->s2 = Rffi_CryptoAuth2_newSession(
ca->ca2, alloc, herPublicKey, requireAuth, name, ca->noise && useNoise);
Iface_plumb(&out->s2Cipher, out->s2->ciphertext);
Iface_plumb(&out->s2Plain, out->s2->plaintext);
}
out->pub.plaintext.send = messagePlaintext;
out->pub.ciphertext.send = messageCiphertext;
return &out->pub;
}
void TestCa_setAuth(const String_t* password, const String_t* login, TestCa_Session_t* session)
{
TestCa_Session_pvt_t* sess = Identity_check((TestCa_Session_pvt_t*) session);
if (sess->s) {
CryptoAuth_setAuth(password, login, sess->s);
}
if (sess->s2) {
Rffi_CryptoAuth2_setAuth(password, login, sess->s2);
}
}
void TestCa_resetIfTimeout(TestCa_Session_t* session)
{
TestCa_Session_pvt_t* sess = Identity_check((TestCa_Session_pvt_t*) session);
if (sess->s) {
CryptoAuth_resetIfTimeout(sess->s);
}
if (sess->s2) {
Rffi_CryptoAuth2_resetIfTimeout(sess->s2);
}
}
void TestCa_reset(TestCa_Session_t* session)
{
TestCa_Session_pvt_t* sess = Identity_check((TestCa_Session_pvt_t*) session);
if (sess->s) {
CryptoAuth_reset(sess->s);
}
if (sess->s2) {
Rffi_CryptoAuth2_reset(sess->s2);
}
}
RTypes_CryptoAuth_State_t TestCa_getState(TestCa_Session_t* session)
{
TestCa_Session_pvt_t* sess = Identity_check((TestCa_Session_pvt_t*) session);
RTypes_CryptoAuth_State_t st = 0;
if (sess->s) {
st = CryptoAuth_getState(sess->s);
}
if (sess->s2) {
RTypes_CryptoAuth_State_t st2 = Rffi_CryptoAuth2_getState(sess->s2);
if (sess->s) {
Assert_true(st2 == st);
}
return st2;
}
return st;
}
void TestCa_getHerPubKey(TestCa_Session_t* session, uint8_t* buf)
{
TestCa_Session_pvt_t* sess = Identity_check((TestCa_Session_pvt_t*) session);
uint8_t hpk1[32];
if (sess->s) {
CryptoAuth_getHerPubKey(sess->s, hpk1);
}
if (sess->s2) {
Rffi_CryptoAuth2_getHerPubKey(sess->s2, buf);
if (sess->s) {
Assert_true(!Bits_memcmp(hpk1, buf, 32));
}
return;
}
Bits_memcpy(buf, hpk1, 32);
}
void TestCa_getPubKey(TestCa_t *ca, uint8_t* buf)
{
uint8_t pk1[32];
if (ca->ca) {
CryptoAuth_getPubKey(ca->ca, pk1);
}
if (ca->ca2) {
Rffi_CryptoAuth2_getPubKey(ca->ca2, buf);
if (ca->ca) {
Assert_true(!Bits_memcmp(pk1, buf, 32));
}
return;
}
Bits_memcpy(buf, pk1, 32);
}