libqaeda

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | README | LICENSE

msg.c (4692B)


      1 #include <stddef.h>
      2 #include <time.h>
      3 #include <libtasn1.h>
      4 
      5 #include "lq/msg.h"
      6 #include "lq/mem.h"
      7 #include "lq/err.h"
      8 #include "lq/crypto.h"
      9 #include "lq/wire.h"
     10 #include "lq/store.h"
     11 #include "endian.h"
     12 
     13 static char zeros[LQ_PUBKEY_LEN];
     14 static LQPubKey nokey = {
     15 	.pk = NULL,
     16 	.impl = zeros,
     17 };
     18 
     19 LQMsg* lq_msg_new(const char *msg_data, size_t msg_len) {
     20 	LQMsg *msg;
     21 
     22 	msg = lq_alloc(sizeof(LQMsg));
     23 	lq_zero(msg, sizeof(LQMsg));
     24 	clock_gettime(CLOCK_REALTIME, &msg->time);
     25 
     26 	msg->data = lq_alloc(msg_len);
     27 	lq_cpy(msg->data, msg_data, msg_len);
     28 	msg->len = msg_len;
     29 
     30 	return msg;
     31 }
     32 
     33 LQSig* lq_msg_sign(LQMsg *msg, LQPrivKey *pk, const char *salt) {
     34 	return lq_msg_sign_extra(msg, pk, salt, NULL, 0);
     35 }
     36 
     37 LQSig* lq_msg_sign_extra(LQMsg *msg, LQPrivKey *pk, const char *salt, const char *extra, size_t extra_len) {
     38 	int l;
     39 	int r;
     40 	char *data;
     41 	char digest[LQ_DIGEST_LEN];
     42 
     43 	if (extra == NULL) {
     44 		extra_len = 0;
     45 	}
     46 	l = msg->len + extra_len;
     47 	data = lq_alloc(l);
     48 	if (extra_len > 0) {
     49 		lq_cpy(data, extra, extra_len);
     50 	}
     51 	lq_cpy(data + extra_len, msg->data, msg->len);
     52 	msg->pubkey = lq_publickey_from_privatekey(pk);
     53 
     54 	r = lq_digest(data, l, (char*)digest);
     55 	if (r != ERR_OK) {
     56 		return NULL;
     57 	}
     58 	return lq_privatekey_sign(pk, digest, LQ_DIGEST_LEN, salt);
     59 }
     60 
     61 void lq_msg_free(LQMsg *msg) {
     62 	if (msg->pubkey->pk = NULL) {
     63 		lq_free(msg->pubkey);
     64 	}
     65 	lq_free(msg->data);
     66 	lq_free(msg);
     67 }
     68 
     69 int lq_msg_serialize(LQMsg *msg, char *out, size_t *out_len, LQResolve *resolve) {
     70 	size_t c;
     71 	int r;
     72 	size_t mx;
     73 	char tmp[LQ_DIGEST_LEN];
     74 	char timedata[8];
     75 	char err[1024];
     76 	LQPubKey *pubkey;
     77 	LQResolve *resolve_active;
     78 	asn1_node node;
     79 	char *keydata;
     80 
     81 	mx = *out_len;
     82 	*out_len = 0;
     83 	lq_set(&node, 0, sizeof(node));
     84 	r = asn1_array2tree(defs_asn1_tab, &node, err);
     85 	if (r != ASN1_SUCCESS) {
     86 		return ERR_INIT;
     87 	}
     88 
     89 	c = LQ_DIGEST_LEN;
     90 	*out_len += c;
     91 	if (*out_len > mx) {
     92 		return ERR_OVERFLOW;
     93 	}
     94 	r = lq_digest(msg->data, msg->len, tmp);
     95 	if (r != ERR_OK) {
     96 		return r;
     97 	}
     98 
     99 	resolve_active = resolve;
    100 	while (resolve_active != NULL) {
    101 		r = resolve_active->store->put(LQ_CONTENT_MSG, resolve_active->store, tmp, &c, msg->data, msg->len);
    102 		if (r != ERR_OK) {
    103 			return r;
    104 		}
    105 		resolve_active = resolve_active->next;
    106 	}
    107 
    108 	r = asn1_write_value(node, "Qaeda.Msg.data", tmp, c);
    109 	if (r != ASN1_SUCCESS) {
    110 		return ERR_WRITE;
    111 	}
    112 
    113 	lq_cpy(timedata, &msg->time.tv_sec, 4);
    114 	lq_cpy(((char*)timedata)+4, &msg->time.tv_nsec, 4);
    115 	r = to_endian(TO_ENDIAN_BIG, 4, timedata);
    116 	if (r) {
    117 		return ERR_BYTEORDER;
    118 	}
    119 	r = to_endian(TO_ENDIAN_BIG, 4, ((char*)timedata)+4);
    120 	if (r) {
    121 		return ERR_BYTEORDER;
    122 	}
    123 
    124 	c = sizeof(int);
    125 	*out_len += c;
    126 	if (*out_len > mx) {
    127 		return ERR_OVERFLOW;
    128 	}
    129 	r = asn1_write_value(node, "Qaeda.Msg.timestamp", &timedata, c);
    130 	if (r != ASN1_SUCCESS) {
    131 		return ERR_WRITE;
    132 	}
    133 
    134 	pubkey = msg->pubkey;
    135 	if (pubkey == NULL) {
    136 		pubkey = &nokey;
    137 	}
    138 	c = lq_publickey_bytes(pubkey, &keydata);
    139 	*out_len += c;
    140 	if (*out_len > mx) {
    141 		return ERR_OVERFLOW;
    142 	}
    143 	r = asn1_write_value(node, "Qaeda.Msg.pubkey", keydata, c);
    144 	if (r != ASN1_SUCCESS) {
    145 		return ERR_WRITE;
    146 	}
    147 
    148 	*out_len = mx;
    149 	r = asn1_der_coding(node, "Qaeda.Msg", out, (int*)out_len, err);
    150 	if (r != ASN1_SUCCESS) {
    151 		return ERR_ENCODING;
    152 	}
    153 
    154 	return ERR_OK;
    155 }
    156 
    157 int lq_msg_deserialize(LQMsg **msg, const char *in, size_t in_len, LQResolve *resolve) {
    158 	int r;
    159 	size_t c;
    160 	char err[1024];
    161 	char z[LQ_DIGEST_LEN];
    162 	char tmp[1024];
    163 	asn1_node node;
    164 	asn1_node item;
    165 	LQResolve *resolve_active;
    166 
    167 	lq_zero(&node, sizeof(node));
    168 	lq_zero(&item, sizeof(item));
    169 	r = asn1_array2tree(defs_asn1_tab, &node, err);
    170 	if (r != ASN1_SUCCESS) {
    171 		return ERR_INIT;
    172 	}
    173 
    174 	r = asn1_create_element(node, "Qaeda.Msg", &item);
    175 	if (r != ASN1_SUCCESS) {
    176 		return ERR_READ;
    177 	}
    178 
    179 	r = asn1_der_decoding(&item, in, in_len, err);
    180 	if (r != ASN1_SUCCESS) {
    181 		return ERR_ENCODING;
    182 	}
    183 
    184 	c = LQ_DIGEST_LEN;
    185 	r = asn1_read_value(item, "data", z, (int*)&c);
    186 	if (r != ASN1_SUCCESS) {
    187 		return ERR_READ;
    188 	}
    189 	c = 1024;
    190 	resolve_active = resolve;
    191 	while (resolve_active != NULL) {
    192 		r = resolve_active->store->get(LQ_CONTENT_MSG, resolve_active->store, z, LQ_DIGEST_LEN, tmp, &c);
    193 		if (r != ERR_OK) {
    194 			return r;
    195 		}
    196 		resolve_active = resolve_active->next;
    197 	}
    198 
    199 	*msg = lq_msg_new((const char*)tmp, c);
    200 
    201 	/// \todo document timestamp size
    202 	c = 8;
    203 	r = asn1_read_value(item, "timestamp", tmp, (int*)&c);
    204 	if (r != ASN1_SUCCESS) {
    205 		return ERR_READ;
    206 	}
    207 	if (is_le()) {
    208 		flip_endian(4, (char*)tmp);
    209 		flip_endian(4, ((char*)tmp)+4);
    210 	}
    211 	lq_cpy(&((*msg)->time.tv_sec), tmp, 4);
    212 	lq_cpy(&((*msg)->time.tv_nsec), ((char*)tmp)+4, 4);
    213 
    214 	c = 65;
    215 	r = asn1_read_value(item, "pubkey", tmp, (int*)&c);
    216 	if (r != ASN1_SUCCESS) {
    217 		return ERR_READ;
    218 	}
    219 
    220 	return ERR_OK;
    221 }