libqaeda

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

cert.c (8021B)


      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 static char zeros[65];
     15 static LQPubKey nokey = {
     16 	.pk = 0,
     17 	.impl = zeros,
     18 };
     19 
     20 static LQMsg nomsg = {
     21 	.data = "",
     22 	.len = 0,
     23 	.time.tv_sec = 0,
     24 	.time.tv_nsec = 0,
     25 };
     26 static LQSig nosig = {
     27 	.pubkey = &nokey,
     28 	.impl = zeros,
     29 };
     30 
     31 LQCert* lq_certificate_new(LQCert *parent) { //, LQMsg *req, LQMsg *rsp) {
     32 	LQCert *cert;
     33 
     34 	cert = lq_alloc(sizeof(LQCert));
     35 	lq_zero(cert, sizeof(LQCert));
     36 	cert->parent = parent;
     37 
     38 	return cert;
     39 }
     40 
     41 int lq_certificate_request(LQCert *cert, LQMsg *req, LQPrivKey *pk) {
     42 	int r;
     43 
     44 	r = ERR_OK;
     45 	if (cert->request != NULL) {
     46 		return ERR_DUP;
     47 	}
     48 	cert->request = req;
     49 	if (pk != NULL) {
     50 		r = lq_certificate_sign(cert, pk);
     51 	}
     52 	return r;
     53 }
     54 
     55 int lq_certificate_respond(LQCert *cert, LQMsg *res, LQPrivKey *pk) {
     56 	int r;
     57 
     58 	if (cert->request_sig == NULL) {
     59 		return ERR_SEQ;
     60 	}
     61 	if (cert->response != NULL) {
     62 		return ERR_DUP;
     63 	}
     64 	cert->response = res;
     65 	if (pk != NULL) {
     66 		r = lq_certificate_sign(cert, pk);
     67 	}
     68 	return r;
     69 }
     70 
     71 void lq_certificate_set_domain(LQCert *cert, const char *domain) {
     72 	lq_cpy(cert->domain, domain, LQ_CERT_DOMAIN_LEN);
     73 }
     74 
     75 // generates a prefix to include with the message for the signature
     76 // domain (required)
     77 // parent (optional)
     78 // request signature (optional)
     79 // response signature (optional)
     80 static int state_digest(LQCert *cert, char *out, int final) {
     81 	int r;
     82 	int c;
     83 	char data[1024];
     84 	char *p;
     85 	char *sigdata;
     86 	size_t siglen;
     87 
     88 	c = LQ_CERT_DOMAIN_LEN;
     89 	p = data;
     90 	lq_cpy(p, cert->domain, c);
     91 	p += c;
     92 
     93 	if (cert->parent != NULL && !final) {
     94 		r = state_digest(cert->parent, cert->parent_hash, 1);
     95 		if (r != ERR_OK) {
     96 			return r;
     97 		}
     98 		lq_cpy(p, cert->parent_hash, LQ_DIGEST_LEN);
     99 		c += LQ_DIGEST_LEN;
    100 		p += LQ_DIGEST_LEN;
    101 	}
    102 
    103 	if (cert->request_sig != NULL) {
    104 		siglen = lq_signature_bytes(cert->request_sig, &sigdata);
    105 		lq_cpy(p, sigdata, siglen);
    106 		c += siglen;
    107 		p += siglen;
    108 	}
    109 
    110 	if (cert->response_sig != NULL) {
    111 		siglen = lq_signature_bytes(cert->response_sig, &sigdata);
    112 		lq_cpy(p, sigdata, siglen);
    113 		c += siglen;
    114 		p += siglen;
    115 	} else if (final) {
    116 		return ERR_RESPONSE;
    117 	}
    118 
    119 	return lq_digest(data, c, out);
    120 }
    121 
    122 int lq_certificate_sign(LQCert *cert, LQPrivKey *pk) {
    123 	int r;
    124 	char out[LQ_DIGEST_LEN];
    125 
    126 	r = state_digest(cert, out, 0);
    127 	if (r != ERR_OK) {
    128 		return r;
    129 	}
    130 	if (cert->response != NULL) {
    131 		if (cert->response_sig != NULL) {
    132 			return ERR_RESPONSE;
    133 		}
    134 		if (cert->request == NULL) {
    135 			return ERR_INIT;	
    136 		}
    137 		cert->response_sig = lq_msg_sign_extra(cert->response, pk, NULL, out, LQ_DIGEST_LEN);
    138 		if (cert->response_sig == NULL) {
    139 			return ERR_ENCODING;
    140 		}
    141 		
    142 		debug(LLOG_INFO, "cert", "signed response");
    143 		return ERR_OK;
    144 	}
    145 	if (cert->request == NULL) {
    146 		return ERR_INIT;
    147 	}
    148 	if (cert->request_sig != NULL) {
    149 		return ERR_REQUEST;
    150 	}
    151 	cert->request_sig = lq_msg_sign_extra(cert->request, pk, NULL, out, LQ_DIGEST_LEN);
    152 	if (cert->request_sig == NULL) {
    153 		return ERR_ENCODING;
    154 	}
    155 	debug(LLOG_INFO, "cert", "signed request");
    156 	return ERR_OK;
    157 }
    158 
    159 int lq_certificate_verify(LQCert *cert, LQPubKey *req_key, LQPubKey *res_key) {
    160 	return ERR_SUPPORT;
    161 }
    162 
    163 int lq_certificate_serialize(LQCert *cert, char *out, size_t *out_len, LQResolve *resolve) {
    164 	size_t c;
    165 	int r;
    166 	size_t mx;
    167 	char err[1024];
    168 	char buf[4096];
    169 	LQMsg *msg;
    170 	LQSig *sig;
    171 	asn1_node node;
    172 	char *sigdata;
    173 
    174 	mx = *out_len;
    175 	*out_len = 0;
    176 	lq_set(&node, 0, sizeof(node));
    177 	r = asn1_array2tree(defs_asn1_tab, &node, err);
    178 	if (r != ASN1_SUCCESS) {
    179 		return ERR_INIT;
    180 	}
    181 
    182 	c = LQ_CERT_DOMAIN_LEN;
    183 	*out_len += c;
    184 	if (*out_len > mx) {
    185 		return ERR_OVERFLOW;
    186 	}
    187 	r = asn1_write_value(node, "Qaeda.Cert.domain", cert->domain, c);
    188 	if (r != ASN1_SUCCESS) {
    189 		return ERR_WRITE;
    190 	}
    191 
    192 	// Set request message if exists
    193 	msg = cert->request;
    194 	if (msg == NULL) {
    195 		msg = &nomsg;
    196 	}
    197 	c = mx - LQ_CERT_DOMAIN_LEN; 
    198 	r = lq_msg_serialize(msg, buf, &c, resolve);
    199 	if (r != ERR_OK) {
    200 		return r;
    201 	}
    202 	*out_len += c;
    203 	if (*out_len > mx) {
    204 		return ERR_OVERFLOW;
    205 	}
    206 	r = asn1_write_value(node, "Qaeda.Cert.request", buf, c);
    207 	if (r != ASN1_SUCCESS) {
    208 		return ERR_WRITE;
    209 	}
    210 
    211 	// Set request signature if exists
    212 	sig = cert->request_sig;
    213 	if (cert->request == NULL || sig == NULL) {
    214 		sig = &nosig;
    215 	}
    216 	// \todo proper sig serialize
    217 	c = lq_signature_bytes(sig, &sigdata);
    218 	*out_len += c;
    219 	if (*out_len > mx) {
    220 		return ERR_OVERFLOW;
    221 	}
    222 	r = asn1_write_value(node, "Qaeda.Cert.request_sig", sigdata, c);
    223 	if (r != ASN1_SUCCESS) {
    224 		return ERR_WRITE;
    225 	}
    226 	
    227 	msg = cert->response;
    228 	if (msg == NULL) {
    229 		msg = &nomsg;
    230 	}
    231 	c = mx - LQ_CERT_DOMAIN_LEN; 
    232 	r = lq_msg_serialize(msg, buf, &c, resolve);
    233 	if (r != ERR_OK) {
    234 		return r;
    235 	}
    236 	*out_len += c;
    237 	if (*out_len > mx) {
    238 		return ERR_OVERFLOW;
    239 	}
    240 	r = asn1_write_value(node, "Qaeda.Cert.response", buf, c);
    241 	if (r != ASN1_SUCCESS) {
    242 		return ERR_WRITE;
    243 	}
    244 
    245 	// Set response signature if exists
    246 	sig = cert->response_sig;
    247 	if (cert->response == NULL || sig == NULL) {
    248 		sig = &nosig;
    249 	}
    250 	// \todo proper sig serialize
    251 	c = lq_signature_bytes(sig, &sigdata);
    252 	*out_len += c;
    253 	if (*out_len > mx) {
    254 		return ERR_OVERFLOW;
    255 	}
    256 	r = asn1_write_value(node, "Qaeda.Cert.response_sig", sigdata, c);
    257 	if (r != ASN1_SUCCESS) {
    258 		return ERR_WRITE;
    259 	}
    260 
    261 	if (cert->parent == NULL) {
    262 		c = 0;
    263 		r = asn1_write_value(node, "Qaeda.Cert.parent", &c, 1);
    264 		if (r != ASN1_SUCCESS) {
    265 			return ERR_WRITE;
    266 		}
    267 	} else {
    268 		r = state_digest(cert, cert->parent_hash, 1);
    269 		if (r != ERR_OK) {
    270 			return r;
    271 		}
    272 		c = LQ_DIGEST_LEN;
    273 		r = asn1_write_value(node, "Qaeda.Cert.parent", cert->parent_hash, c);
    274 		if (r != ASN1_SUCCESS) {
    275 			return ERR_WRITE;
    276 		}
    277 	}
    278 
    279 	*out_len = mx;
    280 	r = asn1_der_coding(node, "Qaeda.Cert", out, (int*)out_len, err);
    281 	if (r != ASN1_SUCCESS) {
    282 		return ERR_ENCODING;
    283 	}
    284 
    285 	return ERR_OK;
    286 }
    287 
    288 int lq_certificate_deserialize(LQCert **cert, char *in, size_t in_len, LQResolve *resolve) {
    289 	int r;
    290 	int c;
    291 	char err[1024];
    292 	char tmp[4096];
    293 	asn1_node node;
    294 	asn1_node item;
    295 	LQCert *p;
    296 
    297 	lq_set(&node, 0, sizeof(node));
    298 	lq_set(&item, 0, sizeof(item));
    299 	r = asn1_array2tree(defs_asn1_tab, &node, err);
    300 	if (r != ASN1_SUCCESS) {
    301 		return ERR_INIT;
    302 	}
    303 
    304 	r = asn1_create_element(node, "Qaeda.Cert", &item);
    305 	if (r != ASN1_SUCCESS) {
    306 		return ERR_READ;
    307 	}
    308 
    309 	r = asn1_der_decoding(&item, in, in_len, err);
    310 	if (r != ASN1_SUCCESS) {
    311 		return ERR_ENCODING;
    312 	}
    313 
    314 	c = LQ_CERT_DOMAIN_LEN;
    315 	r = asn1_read_value(item, "domain", tmp, &c);
    316 	if (r != ASN1_SUCCESS) {
    317 		return ERR_READ;
    318 	}
    319 
    320 	p = lq_certificate_new(NULL);
    321 	lq_certificate_set_domain(p, tmp);
    322 
    323 	c = 4096;
    324 	r = asn1_read_value(item, "request", tmp, &c);
    325 	if (r != ASN1_SUCCESS) {
    326 		return ERR_READ;
    327 	}
    328 	r = lq_msg_deserialize(&p->request, tmp, c, resolve);
    329 	if (r != ERR_OK) {
    330 		return r;
    331 	}
    332 
    333 	c = 4096;
    334 	r = asn1_read_value(item, "request_sig", tmp, &c);
    335 	if (r != ASN1_SUCCESS) {
    336 		return ERR_READ;
    337 	}
    338 	if (c > 0) {
    339 		p->request_sig = lq_signature_from_bytes(tmp, c, NULL);
    340 	}
    341 
    342 	c = 4096;
    343 	r = asn1_read_value(item, "response", tmp, &c);
    344 	if (r != ASN1_SUCCESS) {
    345 		return ERR_READ;
    346 	}
    347 	r = lq_msg_deserialize(&p->response, tmp, c, resolve);
    348 	if (r != ERR_OK) {
    349 		return r;
    350 	}
    351 
    352 	c = 4096;
    353 	r = asn1_read_value(item, "response_sig", tmp, &c);
    354 	if (r != ASN1_SUCCESS) {
    355 		return ERR_READ;
    356 	}
    357 	if (c > 0) {
    358 		p->response_sig = lq_signature_from_bytes(tmp, c, NULL);
    359 	}
    360 
    361 	c = 4096;
    362 	r = asn1_read_value(item, "parent", tmp, &c);
    363 	if (r != ASN1_SUCCESS) {
    364 		return ERR_READ;
    365 	}
    366 	p->parent = NULL;
    367 	if (c == 1) {
    368 		lq_set(p->parent_hash, 0, LQ_DIGEST_LEN);
    369 	} else {
    370 		lq_cpy(p->parent_hash, tmp, LQ_DIGEST_LEN);
    371 	}
    372 	// \todo render parent if set
    373 
    374 	*cert = p;
    375 
    376 	return ERR_OK;
    377 }
    378 
    379 void lq_certificate_free(LQCert *cert) {
    380 	if (cert->request != NULL) {
    381 		lq_msg_free(cert->request);
    382 	}
    383 	if (cert->request_sig != NULL) {
    384 		lq_signature_free(cert->request_sig);
    385 	}
    386 	if (cert->response != NULL) {
    387 		lq_msg_free(cert->response);
    388 	}
    389 	if (cert->response_sig != NULL) {
    390 		lq_signature_free(cert->response_sig);
    391 	}
    392 	lq_free(cert);
    393 }