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 }