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 }