libqaeda

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

msg.c (8318B)


      1 #include <stddef.h>
      2 #include <string.h>
      3 #include <time.h>
      4 #include <libtasn1.h>
      5 #include <endian.h>
      6 #include <llog.h>
      7 
      8 #include "lq/msg.h"
      9 #include "lq/mem.h"
     10 #include "lq/err.h"
     11 #include "lq/crypto.h"
     12 #include "lq/wire.h"
     13 #include "lq/store.h"
     14 #include "debug.h"
     15 
     16 
     17 extern asn1_node asn;
     18 
     19 extern char zeros[65];
     20 static LQPubKey nokey = {
     21 	.pk = NULL,
     22 	.impl = zeros,
     23 };
     24 
     25 LQMsg* lq_msg_new(const char *msg_data, size_t msg_len) {
     26 	LQMsg *msg;
     27 
     28 	msg = lq_alloc(sizeof(LQMsg));
     29 	lq_zero(msg, sizeof(LQMsg));
     30 	clock_gettime(CLOCK_REALTIME, &msg->time);
     31 
     32 	msg->data = lq_alloc(msg_len);
     33 	lq_cpy(msg->data, msg_data, msg_len);
     34 	msg->len = msg_len;
     35 	msg->state = LQ_MSG_INIT;
     36 
     37 	return msg;
     38 }
     39 
     40 int lq_msg_literal(LQMsg *msg) {
     41 	if (msg->state & LQ_MSG_LITERAL) {
     42 		return ERR_NOOP;
     43 	}
     44 	msg->state |= LQ_MSG_LITERAL;
     45 	return ERR_OK;
     46 }
     47 
     48 LQSig* lq_msg_sign(LQMsg *msg, LQPrivKey *pk, const char *salt) {
     49 	return lq_msg_sign_extra(msg, pk, salt, NULL, 0);
     50 }
     51 
     52 static int msg_to_sign(LQMsg *msg, char *out, const char *extra, size_t extra_len) {
     53 	int l;
     54 	char data[LQ_BLOCKSIZE];
     55 
     56 	l = msg->len;
     57 	if (extra_len > 0) {
     58 		l += extra_len;
     59 		lq_cpy(data, extra, extra_len);
     60 	}
     61 	lq_cpy(data + extra_len, msg->data, msg->len);
     62 
     63 	return lq_digest(data, l, out);
     64 }	
     65 
     66 LQSig* lq_msg_sign_extra(LQMsg *msg, LQPrivKey *pk, const char *salt, const char *extra, size_t extra_len) {
     67 	int r;
     68 	char digest[LQ_DIGEST_LEN];
     69 	LQSig *sig;
     70 
     71 	if (extra == NULL) {
     72 		extra_len = 0;
     73 	}
     74 	if (msg->pubkey == NULL) {
     75 		msg->pubkey = lq_publickey_from_privatekey(pk);
     76 		if (msg->pubkey == NULL) {
     77 			debug_logerr(LLOG_DEBUG, ERR_NOKEY, "public key");
     78 			return NULL;
     79 		}
     80 	}
     81 	r = msg_to_sign(msg, digest, extra, extra_len);
     82 	if (r) {
     83 		debug_logerr(LLOG_DEBUG, r, "prepare message for sign");
     84 		return NULL;
     85 	}
     86 	sig = lq_privatekey_sign(pk, digest, LQ_DIGEST_LEN, salt);
     87 	if (sig == NULL) {
     88 		debug_logerr(LLOG_DEBUG, r, "sign message");
     89 		return NULL;
     90 	}
     91 	return sig;
     92 }
     93 
     94 int lq_msg_verify_extra(LQMsg *msg, LQSig *sig, const char *salt, const char *extra, size_t extra_len) {
     95 	int r;
     96 	char digest[LQ_DIGEST_LEN];
     97 
     98 	if (msg->pubkey == NULL) {
     99 		return debug_logerr(LLOG_DEBUG, ERR_NONSENSE, "missing pubkey");
    100 	}
    101 	if (extra == NULL) {
    102 		extra_len = 0;
    103 	}
    104 	r = msg_to_sign(msg, digest, extra, extra_len);
    105 	if (r) {
    106 		return debug_logerr(LLOG_DEBUG, r, "prepare message for verify");
    107 	}
    108 	r = lq_signature_verify(sig, digest, LQ_DIGEST_LEN);
    109 	if (r) {
    110 		return debug_logerr(LLOG_DEBUG, r, "verify message");
    111 	}
    112 	return ERR_OK;
    113 }
    114 
    115 void lq_msg_free(LQMsg *msg) {
    116 	if (msg->pubkey != NULL) {
    117 		lq_publickey_free(msg->pubkey);
    118 	}
    119 	lq_free(msg->data);
    120 	lq_free(msg);
    121 }
    122 
    123 static int asn_except(asn1_node *node, int err) {
    124 	int r;
    125 
    126 	r = asn1_delete_structure(node);
    127 	if (r != ASN1_SUCCESS) {
    128 		debug_logerr(LLOG_ERROR, ERR_FAIL, "free msg asn");
    129 	}
    130 
    131 	return err;
    132 }
    133 
    134 /// TODO check upper bound of data contents
    135 int lq_msg_serialize(LQMsg *msg, LQResolve *resolve, char *out, size_t *out_len) {
    136 	size_t c;
    137 	int r;
    138 	size_t mx;
    139 	char tmp[LQ_CRYPTO_BUFLEN];
    140 	char timedata[8];
    141 	char err[1024];
    142 	LQPubKey *pubkey;
    143 	LQResolve *resolve_active;
    144 	asn1_node item;
    145 	char *keydata;
    146 	char v[6];
    147 
    148 	mx = *out_len;
    149 	*out_len = 0;
    150 	lq_set(&item, 0, sizeof(item));
    151 
    152 	msg->state &= ~((char)LQ_MSG_RESOLVED);
    153 	r = asn1_create_element(asn, "Qaeda", &item);
    154 	if (r != ASN1_SUCCESS) {
    155 		return ERR_READ;
    156 	}
    157 
    158 	lq_cpy(v, "FALSE", 5);
    159 	v[5] = 0;
    160 	if (msg->state & LQ_MSG_LITERAL) {
    161 		lq_cpy(v, "TRUE", 5);
    162 		v[4] = 0;
    163 	}
    164 	r = asn1_write_value(item, "Msg.literal", v, strlen(v) + 1);
    165 	if (r != ASN1_SUCCESS) {
    166 		return asn_except(&item, ERR_WRITE);
    167 	}
    168 
    169 	*out_len = 1;
    170 
    171 	if (msg->state & LQ_MSG_INIT) {
    172 		if (msg->state & LQ_MSG_LITERAL) {
    173 			lq_cpy(tmp, msg->data, msg->len);
    174 			c = msg->len;
    175 			*out_len += c;
    176 			if (*out_len > mx) {
    177 				return asn_except(&item, ERR_OVERFLOW);
    178 			}
    179 		} else {
    180 			c = LQ_DIGEST_LEN;
    181 			*out_len += c;
    182 			if (*out_len > mx) {
    183 				return asn_except(&item, ERR_OVERFLOW);
    184 			}
    185 			r = lq_digest(msg->data, msg->len, tmp);
    186 			if (r != ERR_OK) {
    187 				return asn_except(&item, r);
    188 			}
    189 
    190 			resolve_active = resolve;
    191 			while (resolve_active != NULL) {
    192 				r = resolve_active->store->put(LQ_CONTENT_MSG, resolve_active->store, tmp, &c, msg->data, msg->len);
    193 				if (r != ERR_OK) {
    194 					return asn_except(&item, r);
    195 				}
    196 				resolve_active = resolve_active->next;
    197 				msg->state |= LQ_MSG_RESOLVED;
    198 			}
    199 			if (!(msg->state & LQ_MSG_RESOLVED)) {
    200 				debug(LLOG_DEBUG, "msg", "no resolver");	
    201 			}
    202 		}
    203 	} else {
    204 		tmp[0] = 0;
    205 		c = 1;
    206 	}
    207 
    208 	r = asn1_write_value(item, "Msg.data", tmp, c);
    209 	if (r != ASN1_SUCCESS) {
    210 		return asn_except(&item, ERR_WRITE);
    211 	}
    212 
    213 
    214 	lq_cpy(timedata, &msg->time.tv_sec, 4);
    215 	lq_cpy(((char*)timedata)+4, &msg->time.tv_nsec, 4);
    216 	r = to_endian(TO_ENDIAN_BIG, 4, timedata);
    217 	if (r) {
    218 		return asn_except(&item, ERR_BYTEORDER);
    219 	}
    220 	r = to_endian(TO_ENDIAN_BIG, 4, ((char*)timedata)+4);
    221 	if (r) {
    222 		return asn_except(&item, ERR_BYTEORDER);
    223 	}
    224 
    225 	c = sizeof(int);
    226 	*out_len += c;
    227 	if (*out_len > mx) {
    228 		return asn_except(&item, ERR_OVERFLOW);
    229 	}
    230 	r = asn1_write_value(item, "Msg.timestamp", &timedata, c);
    231 	if (r != ASN1_SUCCESS) {
    232 		return asn_except(&item, ERR_WRITE);
    233 	}
    234 
    235 	pubkey = msg->pubkey;
    236 	if (pubkey == NULL) {
    237 		pubkey = &nokey;
    238 	}
    239 	c = lq_publickey_bytes(pubkey, &keydata);
    240 	*out_len += c;
    241 	if (*out_len > mx) {
    242 		return asn_except(&item, ERR_OVERFLOW);
    243 	}
    244 	r = asn1_write_value(item, "Msg.pubkey", keydata, c);
    245 	if (r != ASN1_SUCCESS) {
    246 		return asn_except(&item, ERR_WRITE);
    247 	}
    248 
    249 	*out_len = mx;
    250 	r = asn1_der_coding(item, "Msg", out, (int*)out_len, err);
    251 	if (r != ASN1_SUCCESS) {
    252 		debug_logerr(LLOG_WARNING, ERR_ENCODING, (char*)asn1_strerror(r));
    253 		return asn_except(&item, ERR_ENCODING);
    254 	}
    255 
    256 	r = asn1_delete_structure(&item);
    257 	if (r != ASN1_SUCCESS) {
    258 		return r;
    259 	}
    260 
    261 	return ERR_OK;
    262 }
    263 
    264 /**
    265  * \todo allow for 1 byte message
    266  */
    267 int lq_msg_deserialize(LQMsg **msg, LQResolve *resolve, const char *in, size_t in_len) {
    268 	int r;
    269 	size_t c;
    270 	size_t l;
    271 	char resolved;
    272 	char err[LQ_ERRSIZE];
    273 	char tmp[LQ_BLOCKSIZE];
    274 	char z[LQ_DIGEST_LEN];
    275 	char msg_state;
    276 	asn1_node item;
    277 	LQResolve *resolve_active;
    278 
    279 	resolved = 0;
    280 	msg_state = 0;
    281 
    282 	lq_zero(&item, sizeof(item));
    283 
    284 	r = asn1_create_element(asn, "Qaeda.Msg", &item);
    285 	if (r != ASN1_SUCCESS) {
    286 		return ERR_READ;
    287 	}
    288 
    289 	r = asn1_der_decoding(&item, in, in_len, err);
    290 	if (r != ASN1_SUCCESS) {
    291 		return asn_except(&item, ERR_ENCODING);
    292 	}
    293 
    294 	c = 6;
    295 	r = asn1_read_value(item, "literal", tmp, (int*)&c);
    296 	if (r != ASN1_SUCCESS) {
    297 		debug_logerr(LLOG_WARNING, ERR_READ, (char*)asn1_strerror(r));
    298 		return asn_except(&item, ERR_READ);
    299 	}
    300 	if (lq_cmp(tmp, "F", 1)) {
    301 		msg_state |= LQ_MSG_LITERAL;
    302 	}
    303 
    304 	c = LQ_BLOCKSIZE;
    305 	r = asn1_read_value(item, "data", tmp, (int*)&c);
    306 	if (r != ASN1_SUCCESS) {
    307 		debug_logerr(LLOG_WARNING, ERR_READ, (char*)asn1_strerror(r));
    308 		return asn_except(&item, ERR_READ);
    309 	}
    310 
    311 	if (c == 1) {
    312 		debug(LLOG_DEBUG, "msg", "empty message");
    313 		*msg = NULL;
    314 		return ERR_OK;
    315 	}
    316 
    317 	if (!(msg_state & LQ_MSG_LITERAL)) {
    318 		resolve_active = resolve;
    319 		l = c;
    320 		c = LQ_BLOCKSIZE;
    321 		lq_cpy(z, tmp, LQ_DIGEST_LEN);
    322 		while (resolve_active != NULL) {
    323 			r = resolve_active->store->get(LQ_CONTENT_MSG, resolve_active->store, z, LQ_DIGEST_LEN, tmp, &c);
    324 			if (r != ERR_OK) {
    325 				return asn_except(&item, r);
    326 			}
    327 			resolve_active = resolve_active->next;
    328 			resolved = LQ_MSG_RESOLVED;
    329 		}
    330 
    331 		if (!(resolved & LQ_MSG_RESOLVED)) {
    332 			debug(LLOG_DEBUG, "msg", "no resolver");
    333 			c = l;
    334 		}
    335 	}
    336 
    337 	*msg = lq_msg_new((const char*)tmp, c);
    338 	if (*msg == NULL) {
    339 		return asn_except(&item, ERR_MEM);
    340 	}
    341 	(*msg)->state = msg_state | resolved;
    342 
    343 	/// \todo document timestamp size
    344 	c = 8;
    345 	r = asn1_read_value(item, "timestamp", tmp, (int*)&c);
    346 	if (r != ASN1_SUCCESS) {
    347 		return asn_except(&item, ERR_READ);
    348 	}
    349 	if (is_le()) {
    350 		flip_endian(4, (char*)tmp);
    351 		flip_endian(4, ((char*)tmp)+4);
    352 	}
    353 	lq_cpy(&((*msg)->time.tv_sec), tmp, 4);
    354 	lq_cpy(&((*msg)->time.tv_nsec), ((char*)tmp)+4, 4);
    355 
    356 	c = LQ_PUBKEY_LEN;
    357 	r = asn1_read_value(item, "pubkey", tmp, (int*)&c);
    358 	if (r != ASN1_SUCCESS) {
    359 		return asn_except(&item, ERR_READ);
    360 	}
    361 
    362 	(*msg)->pubkey = lq_publickey_new(tmp);
    363 	if ((*msg)->pubkey == NULL) {
    364 		return asn_except(&item, ERR_NOKEY);
    365 	}
    366 
    367 	r = asn1_delete_structure(&item);
    368 	if (r != ASN1_SUCCESS) {
    369 		debug(LLOG_WARNING, "msg", "delete msg asn item");
    370 		return ERR_FAIL;
    371 	}
    372 
    373 	return ERR_OK;
    374 }