libqaeda

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

cert.c (10719B)


      1 #include <stddef.h>
      2 
      3 #include <libtasn1.h>
      4 #include <llog.h>
      5 
      6 #include "lq/cert.h"
      7 #include "lq/mem.h"
      8 #include "lq/wire.h"
      9 #include "lq/err.h"
     10 #include "lq/store.h"
     11 #include "debug.h"
     12 
     13 
     14 extern asn1_node asn;
     15 
     16 extern char zeros[65];
     17 static LQPubKey nokey = {
     18 	.pk = 0,
     19 	.impl = zeros,
     20 };
     21 
     22 static LQMsg nomsg = {
     23 	.state = 0,
     24 	.data = "",
     25 	.len = 0,
     26 	.time.tv_sec = 0,
     27 	.time.tv_nsec = 0,
     28 };
     29 static LQSig nosig = {
     30 	.pubkey = &nokey,
     31 	.impl = zeros,
     32 };
     33 
     34 LQCert* lq_certificate_new(LQCert *parent) {
     35 	LQCert *cert;
     36 
     37 	cert = lq_alloc(sizeof(LQCert));
     38 	lq_zero(cert, sizeof(LQCert));
     39 	cert->parent = parent;
     40 
     41 	return cert;
     42 }
     43 
     44 int lq_certificate_request(LQCert *cert, LQMsg *req, LQPrivKey *pk) {
     45 	int r;
     46 
     47 	r = ERR_OK;
     48 	if (cert->request != NULL) {
     49 		return ERR_DUP;
     50 	}
     51 	cert->request = req;
     52 	if (pk != NULL) {
     53 		r = lq_certificate_sign(cert, pk);
     54 	}
     55 	return r;
     56 }
     57 
     58 int lq_certificate_respond(LQCert *cert, LQMsg *res, LQPrivKey *pk) {
     59 	int r;
     60 
     61 	if (cert->request_sig == NULL) {
     62 		return ERR_SEQ;
     63 	}
     64 	if (cert->response != NULL) {
     65 		return ERR_DUP;
     66 	}
     67 	cert->response = res;
     68 	if (pk != NULL) {
     69 		r = lq_certificate_sign(cert, pk);
     70 	}
     71 	return r;
     72 }
     73 
     74 void lq_certificate_set_domain(LQCert *cert, const char *domain) {
     75 	lq_cpy(cert->domain, domain, LQ_CERT_DOMAIN_LEN);
     76 }
     77 
     78 // generates a prefix to include with the message for the signature
     79 // domain (required)
     80 // parent (optional)
     81 // request signature (optional)
     82 // response signature (optional)
     83 static int state_digest(LQCert *cert, char *out, int final) {
     84 	int r;
     85 	int c;
     86 	char data[LQ_BLOCKSIZE];
     87 	char *p;
     88 	char *sigdata;
     89 	size_t siglen;
     90 
     91 	c = LQ_CERT_DOMAIN_LEN;
     92 	p = data;
     93 	lq_cpy(p, cert->domain, c);
     94 	p += c;
     95 
     96 	if (cert->parent != NULL && !final) {
     97 		r = state_digest(cert->parent, cert->parent_hash, 1);
     98 		if (r != ERR_OK) {
     99 			return r;
    100 		}
    101 		lq_cpy(p, cert->parent_hash, LQ_DIGEST_LEN);
    102 		c += LQ_DIGEST_LEN;
    103 		p += LQ_DIGEST_LEN;
    104 	}
    105 
    106 	if (cert->request_sig != NULL) {
    107 		siglen = lq_signature_bytes(cert->request_sig, &sigdata);
    108 		lq_cpy(p, sigdata, siglen);
    109 		c += siglen;
    110 		p += siglen;
    111 	}
    112 
    113 	if (cert->response_sig != NULL) {
    114 		siglen = lq_signature_bytes(cert->response_sig, &sigdata);
    115 		lq_cpy(p, sigdata, siglen);
    116 		c += siglen;
    117 		p += siglen;
    118 	} else if (final) {
    119 		return ERR_RESPONSE;
    120 	}
    121 
    122 	return lq_digest(data, c, out);
    123 }
    124 
    125 int lq_certificate_sign(LQCert *cert, LQPrivKey *pk) {
    126 	int r;
    127 	char out[LQ_DIGEST_LEN];
    128 
    129 	r = state_digest(cert, out, 0);
    130 	if (r != ERR_OK) {
    131 		return r;
    132 	}
    133 	if (cert->response != NULL) {
    134 		if (cert->response_sig != NULL) {
    135 			return ERR_RESPONSE;
    136 		}
    137 		if (cert->request == NULL) {
    138 			return ERR_INIT;	
    139 		}
    140 		cert->response_sig = lq_msg_sign_extra(cert->response, pk, NULL, out, LQ_DIGEST_LEN);
    141 		if (cert->response_sig == NULL) {
    142 			return ERR_ENCODING;
    143 		}
    144 		
    145 		debug(LLOG_INFO, "cert", "signed response");
    146 		return ERR_OK;
    147 	}
    148 	if (cert->request == NULL) {
    149 		return ERR_INIT;
    150 	}
    151 	if (cert->request_sig != NULL) {
    152 		return ERR_REQUEST;
    153 	}
    154 	cert->request_sig = lq_msg_sign_extra(cert->request, pk, NULL, out, LQ_DIGEST_LEN);
    155 	if (cert->request_sig == NULL) {
    156 		return ERR_ENCODING;
    157 	}
    158 	debug(LLOG_INFO, "cert", "signed request");
    159 	return ERR_OK;
    160 }
    161 
    162 int lq_certificate_verify(LQCert *cert, LQPubKey **request_pubkey, LQPubKey **response_pubkey) {
    163 	int r;
    164 	char out[LQ_BLOCKSIZE];
    165 	LQCert cert_valid;
    166 
    167 	if (cert->request_sig == NULL) {
    168 		return debug_logerr(LLOG_DEBUG, ERR_NOOP, "no signatures");
    169 	}
    170 
    171 	lq_cpy(&cert_valid, cert, sizeof(LQCert));
    172 	cert_valid.request_sig = NULL;
    173 	cert_valid.response = NULL;
    174 	cert_valid.response_sig = NULL;
    175 	r = state_digest(&cert_valid, out, 0);
    176 	if (r != ERR_OK) {
    177 		return debug_logerr(LLOG_DEBUG, r, "cert state request");
    178 	}
    179 
    180 	r = lq_msg_verify_extra(cert->request, cert->request_sig, NULL, out, LQ_DIGEST_LEN);
    181 	if (r != ERR_OK) {
    182 		return debug_logerr(LLOG_DEBUG, r, "cert verify request");
    183 	}
    184 
    185 	if (cert->response_sig == NULL) {
    186 		debug(LLOG_DEBUG, "cert", "skip empty response signature");
    187 		return ERR_OK;
    188 	}
    189 
    190 	cert_valid.request_sig = cert->request_sig;
    191 	cert_valid.response = cert->response;
    192 	r = state_digest(&cert_valid, out, 0);
    193 	if (r != ERR_OK) {
    194 		return debug_logerr(LLOG_DEBUG, r, "cert state response");
    195 	}
    196 	cert_valid.response_sig = cert->response_sig;
    197 
    198 	r = lq_msg_verify_extra(cert_valid.response, cert_valid.response_sig, NULL, out, LQ_DIGEST_LEN);
    199 	if (r != ERR_OK) {
    200 		return debug_logerr(LLOG_DEBUG, r, "cert verify response");
    201 	}
    202 
    203 	if (request_pubkey != NULL) {
    204 		*request_pubkey = cert->request_sig->pubkey;
    205 	}
    206 
    207 	if (response_pubkey != NULL) {
    208 		if (cert_valid.response_sig != NULL) {
    209 			*response_pubkey = cert->response_sig->pubkey;
    210 		}
    211 	}
    212 
    213 	return ERR_OK;
    214 }
    215 
    216 // TODO: DRY
    217 static int asn_except(asn1_node *node, int err) {
    218 	int r;
    219 
    220 	r = asn1_delete_structure(node);
    221 	if (r != ASN1_SUCCESS) {
    222 		debug_logerr(LLOG_ERROR, ERR_FAIL, "free cert asn");
    223 	}
    224 
    225 	return err;
    226 }
    227 
    228 int lq_certificate_serialize(LQCert *cert, LQResolve *resolve, char *out, size_t *out_len) {
    229 	size_t c;
    230 	int r;
    231 	size_t mx;
    232 	char err[LQ_ERRSIZE];
    233 	char buf[LQ_BLOCKSIZE];
    234 	LQMsg *msg;
    235 	LQSig *sig;
    236 	asn1_node item;
    237 	char *sigdata;
    238 
    239 	mx = *out_len;
    240 	*out_len = 0;
    241 	lq_zero(&item, sizeof(item));
    242 
    243 	r = asn1_create_element(asn, "Qaeda", &item);
    244 	if (r != ASN1_SUCCESS) {
    245 		return ERR_READ;
    246 	}
    247 
    248 	c = LQ_CERT_DOMAIN_LEN;
    249 	*out_len += c;
    250 	if (*out_len > mx) {
    251 		return asn_except(&item, ERR_OVERFLOW);
    252 	}
    253 	r = asn1_write_value(item, "Cert.domain", cert->domain, c);
    254 	if (r != ASN1_SUCCESS) {
    255 		return asn_except(&item, ERR_WRITE);
    256 	}
    257 
    258 	// Set request message if exists
    259 	msg = cert->request;
    260 	if (msg == NULL) {
    261 		msg = &nomsg;
    262 	}
    263 	c = mx - LQ_CERT_DOMAIN_LEN; 
    264 	r = lq_msg_serialize(msg, resolve, buf, &c);
    265 	if (r != ERR_OK) {
    266 		return asn_except(&item, r);
    267 	}	
    268 	*out_len += c;
    269 	if (*out_len > mx) {
    270 		return asn_except(&item, ERR_OVERFLOW);
    271 	}
    272 	r = asn1_write_value(item, "Cert.request", buf, c);
    273 	if (r != ASN1_SUCCESS) {
    274 		return asn_except(&item, ERR_WRITE);
    275 	}
    276 
    277 	// Set request signature if exists
    278 	sig = cert->request_sig;
    279 	if (cert->request == NULL || sig == NULL) {
    280 		sig = &nosig;
    281 	}
    282 	// \todo proper sig serialize
    283 	c = lq_signature_bytes(sig, &sigdata);
    284 	*out_len += c;
    285 	if (*out_len > mx) {
    286 		return asn_except(&item, ERR_OVERFLOW);
    287 	}
    288 	r = asn1_write_value(item, "Cert.request_sig", sigdata, c);
    289 	if (r != ASN1_SUCCESS) {
    290 		return asn_except(&item, ERR_WRITE);
    291 	}
    292 	
    293 	msg = cert->response;
    294 	if (msg == NULL) {
    295 		msg = &nomsg;
    296 	}
    297 	c = mx - LQ_CERT_DOMAIN_LEN; 
    298 	r = lq_msg_serialize(msg, resolve, buf, &c);
    299 	if (r != ERR_OK) {
    300 		return asn_except(&item, r);
    301 	}
    302 	*out_len += c;
    303 	if (*out_len > mx) {
    304 		return asn_except(&item, ERR_OVERFLOW);
    305 	}
    306 	r = asn1_write_value(item, "Cert.response", buf, c);
    307 	if (r != ASN1_SUCCESS) {
    308 		return asn_except(&item, ERR_WRITE);
    309 	}
    310 
    311 	// Set response signature if exists
    312 	sig = cert->response_sig;
    313 	if (cert->response == NULL || sig == NULL) {
    314 		sig = &nosig;
    315 	}
    316 	// \todo proper sig serialize
    317 	c = lq_signature_bytes(sig, &sigdata);
    318 	*out_len += c;
    319 	if (*out_len > mx) {
    320 		return asn_except(&item, ERR_OVERFLOW);
    321 	}
    322 	r = asn1_write_value(item, "Cert.response_sig", sigdata, c);
    323 	if (r != ASN1_SUCCESS) {
    324 		return asn_except(&item, ERR_WRITE);
    325 	}
    326 
    327 	if (cert->parent == NULL) {
    328 		c = 0;
    329 		r = asn1_write_value(item, "Cert.parent", &c, 1);
    330 		if (r != ASN1_SUCCESS) {
    331 			return asn_except(&item, ERR_WRITE);
    332 		}
    333 	} else {
    334 		r = state_digest(cert, cert->parent_hash, 1);
    335 		if (r != ERR_OK) {
    336 			return asn_except(&item, r);
    337 		}
    338 		c = LQ_DIGEST_LEN;
    339 		r = asn1_write_value(item, "Cert.parent", cert->parent_hash, c);
    340 		if (r != ASN1_SUCCESS) {
    341 			return asn_except(&item, ERR_WRITE);
    342 		}
    343 	}
    344 
    345 	*out_len = mx;
    346 	r = asn1_der_coding(item, "Cert", out, (int*)out_len, err);
    347 	if (r != ASN1_SUCCESS) {
    348 		return asn_except(&item, ERR_ENCODING);
    349 	}
    350 
    351 	r = asn1_delete_structure(&item);
    352 	if (r != ASN1_SUCCESS) {
    353 		return ERR_FAIL;
    354 	}
    355 
    356 	return ERR_OK;
    357 }
    358 
    359 /**
    360  * \todo pubkey is copied to signature from message, to prevent a double-free. Wastes up to 2x sig bytes.
    361  *
    362  */
    363 int lq_certificate_deserialize(LQCert **cert, LQResolve *resolve, char *in, size_t in_len) {
    364 	int r;
    365 	int c;
    366 	char err[LQ_ERRSIZE];
    367 	char tmp[LQ_BLOCKSIZE];
    368 	asn1_node item;
    369 	LQCert *p;
    370 
    371 	lq_zero(&item, sizeof(item));
    372 	
    373 	r = asn1_create_element(asn, "Qaeda.Cert", &item);
    374 	if (r != ASN1_SUCCESS) {
    375 		return ERR_READ;
    376 	}
    377 
    378 	r = asn1_der_decoding(&item, in, in_len, err);
    379 	if (r != ASN1_SUCCESS) {
    380 		return asn_except(&item, ERR_ENCODING);
    381 	}
    382 
    383 	c = LQ_CERT_DOMAIN_LEN;
    384 	r = asn1_read_value(item, "domain", tmp, &c);
    385 	if (r != ASN1_SUCCESS) {
    386 		return asn_except(&item, ERR_READ);
    387 	}
    388 
    389 	*cert = lq_certificate_new(NULL);
    390 	p = *cert;
    391 	lq_certificate_set_domain(p, tmp);
    392 
    393 	c = LQ_BLOCKSIZE;
    394 	r = asn1_read_value(item, "request", tmp, &c);
    395 	if (r != ASN1_SUCCESS) {
    396 		return asn_except(&item, ERR_READ);
    397 	}
    398 	r = lq_msg_deserialize(&p->request, resolve, tmp, c);
    399 	if (r != ERR_OK) {
    400 		return asn_except(&item, r);
    401 	}
    402 	if (p->request != NULL) {
    403 		c = LQ_BLOCKSIZE;
    404 		r = asn1_read_value(item, "request_sig", tmp, &c);
    405 		if (r != ASN1_SUCCESS) {
    406 			lq_msg_free(p->request);
    407 			return asn_except(&item, ERR_READ);
    408 		}
    409 		if (c > 0) {
    410 			p->request_sig = lq_signature_from_bytes(tmp, c, p->request->pubkey);
    411 		}
    412 	}
    413 
    414 	c = LQ_BLOCKSIZE;
    415 	r = asn1_read_value(item, "response", tmp, &c);
    416 	if (r != ASN1_SUCCESS) {
    417 		lq_signature_free(p->request_sig);
    418 		lq_msg_free(p->request);
    419 		return asn_except(&item, ERR_READ);
    420 	}
    421 	r = lq_msg_deserialize(&p->response, resolve, tmp, c);
    422 	if (r != ERR_OK) {
    423 		lq_signature_free(p->request_sig);
    424 		lq_msg_free(p->request);
    425 		return asn_except(&item, r);
    426 	}
    427 	if (p->response != NULL) {
    428 		c = LQ_BLOCKSIZE;
    429 		r = asn1_read_value(item, "response_sig", tmp, &c);
    430 		if (r != ASN1_SUCCESS) {
    431 			lq_msg_free(p->response);
    432 			lq_signature_free(p->request_sig);
    433 			lq_msg_free(p->request);
    434 			return asn_except(&item, ERR_READ);
    435 		}
    436 		if (c > 0) {
    437 			p->response_sig = lq_signature_from_bytes(tmp, c, p->response->pubkey);
    438 		}
    439 	}
    440 
    441 	c = 4096;
    442 	r = asn1_read_value(item, "parent", tmp, &c);
    443 	if (r != ASN1_SUCCESS) {
    444 		lq_signature_free(p->response_sig);
    445 		lq_msg_free(p->response);
    446 		lq_signature_free(p->request_sig);
    447 		lq_msg_free(p->request);
    448 		return asn_except(&item, ERR_READ);
    449 	}
    450 	p->parent = NULL;
    451 	if (c == 1) {
    452 		lq_zero(p->parent_hash, LQ_DIGEST_LEN);
    453 	} else {
    454 		lq_cpy(p->parent_hash, tmp, LQ_DIGEST_LEN);
    455 	}
    456 	// \todo render parent if set
    457 
    458 	r = asn1_delete_structure(&item);
    459 	if (r != ASN1_SUCCESS) {
    460 		return ERR_FAIL;
    461 	}
    462 
    463 	return ERR_OK;
    464 }
    465 
    466 void lq_certificate_free(LQCert *cert) {
    467 	if (cert->request != NULL) {
    468 		lq_msg_free(cert->request);
    469 	}
    470 	if (cert->request_sig != NULL) {
    471 		lq_signature_free(cert->request_sig);
    472 	}
    473 	if (cert->response != NULL) {
    474 		lq_msg_free(cert->response);
    475 	}
    476 	if (cert->response_sig != NULL) {
    477 		lq_signature_free(cert->response_sig);
    478 	}
    479 	lq_free(cert);
    480 }