void crtmgr_del(crtmgr *m, cli_crt *x509) { cli_crt *i; for(i = m->crts; i; i = i->next) { if(i==x509) { if(i->prev) i->prev->next = i->next; else m->crts = i->next; if(i->next) i->next->prev = i->prev; cli_crt_clear(x509); free(x509); m->items--; return; } } }
static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, crtmgr *master, crtmgr *other) { struct cli_asn1 crt, tbs, obj; unsigned int avail, tbssize, issuersize; cli_crt_hashtype hashtype1, hashtype2; cli_crt x509; const uint8_t *tbsdata; const void *next, *issuer; if(cli_crt_init(&x509)) return 1; do { if(asn1_expect_objtype(map, *asn1data, size, &crt, 0x30)) /* SEQUENCE */ break; *asn1data = crt.next; tbsdata = crt.content; if(asn1_expect_objtype(map, crt.content, &crt.size, &tbs, 0x30)) /* SEQUENCE - TBSCertificate */ break; tbssize = (uint8_t *)tbs.next - tbsdata; if(asn1_expect_objtype(map, tbs.content, &tbs.size, &obj, 0xa0)) /* [0] */ break; avail = obj.size; next = obj.next; if(asn1_expect_obj(map, &obj.content, &avail, 0x02, 1, "\x02")) /* version 3 only */ break; if(avail) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in version\n"); break; } if(asn1_expect_objtype(map, next, &tbs.size, &obj, 0x02)) /* serialNumber */ break; if(map_sha1(map, obj.content, obj.size, x509.serial)) break; if(asn1_expect_rsa(map, &obj.next, &tbs.size, &hashtype1)) /* algo = sha1WithRSAEncryption | md5WithRSAEncryption */ break; if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, 0x30)) /* issuer */ break; issuer = obj.content; issuersize = obj.size; if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, 0x30)) /* validity */ break; avail = obj.size; next = obj.content; if(asn1_get_time(map, &next, &avail, &x509.not_before)) /* notBefore */ break; if(asn1_get_time(map, &next, &avail, &x509.not_after)) /* notAfter */ break; if(x509.not_before >= x509.not_after) { cli_dbgmsg("asn1_get_x509: bad validity\n"); break; } if(avail) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in validity\n"); break; } if(asn1_expect_objtype(map, obj.next, &tbs.size, &obj, 0x30)) /* subject */ break; if(map_sha1(map, obj.content, obj.size, x509.subject)) break; if(asn1_get_rsa_pubkey(map, &obj.next, &tbs.size, &x509)) break; avail = 0; while(tbs.size) { if(asn1_get_obj(map, obj.next, &tbs.size, &obj)) { tbs.size = 1; break; } if(obj.type <= 0xa0 + avail || obj.type > 0xa3) { cli_dbgmsg("asn1_get_x509: found type %02x in extensions, expecting a1, a2 or a3\n", obj.type); tbs.size = 1; break; } avail = obj.type - 0xa0; if(obj.type == 0xa3) { struct cli_asn1 exts; int have_ext_key = 0; if(asn1_expect_objtype(map, obj.content, &obj.size, &exts, 0x30)) { tbs.size = 1; break; } if(obj.size) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in extensions\n"); break; } while(exts.size) { struct cli_asn1 ext, id, value; if(asn1_expect_objtype(map, exts.content, &exts.size, &ext, 0x30)) { exts.size = 1; break; } exts.content = ext.next; if(asn1_expect_objtype(map, ext.content, &ext.size, &id, 0x06)) { exts.size = 1; break; } if(asn1_get_obj(map, id.next, &ext.size, &value)) { exts.size = 1; break; } if(value.type == 0x01) { /* critical flag */ if(value.size != 1) { cli_dbgmsg("asn1_get_x509: found boolean with wrong length\n"); exts.size = 1; break; } if(asn1_get_obj(map, value.next, &ext.size, &value)) { exts.size = 1; break; } } if(value.type != 0x04) { cli_dbgmsg("asn1_get_x509: bad extension value type %u\n", value.type); exts.size = 1; break; } if(ext.size) { cli_dbgmsg("asn1_get_x509: extra data in extension\n"); exts.size = 1; break; } if(id.size != 3) continue; if(!fmap_need_ptr_once(map, id.content, 3)) { exts.size = 1; break; } if(!memcmp("\x55\x1d\x0f", id.content, 3)) { /* KeyUsage 2.5.29.15 */ const uint8_t *keyusage = value.content; uint8_t usage; if(value.size < 4 || value.size > 5) { cli_dbgmsg("asn1_get_x509: bad KeyUsage\n"); exts.size = 1; break; } if(!fmap_need_ptr_once(map, value.content, value.size)) { exts.size = 1; break; } if(keyusage[0] != 0x03 || keyusage[1] != value.size - 2 || keyusage[2] > 7) { cli_dbgmsg("asn1_get_x509: bad KeyUsage\n"); exts.size = 1; break; } usage = keyusage[3]; if(value.size == 4) usage &= ~((1 << keyusage[2])-1); x509.certSign = ((usage & 4) != 0); continue; } if(!memcmp("\x55\x1d\x25", id.content, 3)) { /* ExtKeyUsage 2.5.29.37 */ struct cli_asn1 keypurp; have_ext_key = 1; if(asn1_expect_objtype(map, value.content, &value.size, &keypurp, 0x30)) { exts.size = 1; break; } if(value.size) { cli_dbgmsg("asn1_get_x509: extra data in ExtKeyUsage\n"); exts.size = 1; break; } ext.next = keypurp.content; while(keypurp.size) { if(asn1_expect_objtype(map, ext.next, &keypurp.size, &ext, 0x06)) { exts.size = 1; break; } if(ext.size != 8) continue; if(!fmap_need_ptr_once(map, ext.content, 8)) { exts.size = 1; break; } if(!memcmp("\x2b\x06\x01\x05\x05\x07\x03\x03", ext.content, 8)) /* id_kp_codeSigning */ x509.codeSign = 1; else if(!memcmp("\x2b\x06\x01\x05\x05\x07\x03\x08", ext.content, 8)) /* id_kp_timeStamping */ x509.timeSign = 1; } continue; } if(!memcmp("\x55\x1d\x13", id.content, 3)) { /* Basic Constraints 2.5.29.19 */ struct cli_asn1 constr; if(asn1_expect_objtype(map, value.content, &value.size, &constr, 0x30)) { exts.size = 1; break; } if(!constr.size) x509.certSign = 0; else { if(asn1_expect_objtype(map, constr.content, &constr.size, &ext, 0x01)) { exts.size = 1; break; } if(ext.size != 1) { cli_dbgmsg("asn1_get_x509: wrong bool size in basic constraint %u\n", ext.size); exts.size = 1; break; } if(!fmap_need_ptr_once(map, ext.content, 1)) { exts.size = 1; break; } x509.certSign = (((uint8_t *)(ext.content))[0] != 0); } } } if(exts.size) { tbs.size = 1; break; } if(!have_ext_key) x509.codeSign = x509.timeSign = 1; } } if(tbs.size) break; if(crtmgr_lookup(master, &x509) || crtmgr_lookup(other, &x509)) { cli_dbgmsg("asn1_get_x509: certificate already exists\n"); cli_crt_clear(&x509); return 0; } if(map_sha1(map, issuer, issuersize, x509.issuer)) break; if(asn1_expect_rsa(map, &tbs.next, &crt.size, &hashtype2)) /* signature algo = sha1WithRSAEncryption | md5WithRSAEncryption */ break; if(hashtype1 != hashtype2) { cli_dbgmsg("asn1_get_x509: found conflicting rsa hash types\n"); break; } x509.hashtype = hashtype1; if(asn1_expect_objtype(map, tbs.next, &crt.size, &obj, 0x03)) /* signature */ break; if(obj.size > 513) { cli_dbgmsg("asn1_get_x509: signature too long\n"); break; } if(!fmap_need_ptr_once(map, obj.content, obj.size)) { cli_dbgmsg("asn1_get_x509: cannot read signature\n"); break; } if(mp_read_unsigned_bin(&x509.sig, obj.content, obj.size)) { cli_dbgmsg("asn1_get_x509: cannot convert signature to big number\n"); break; } if(crt.size) { cli_dbgmsg("asn1_get_x509: found unexpected extra data in signature\n"); break; } if((x509.hashtype == CLI_SHA1RSA && map_sha1(map, tbsdata, tbssize, x509.tbshash)) || (x509.hashtype == CLI_MD5RSA && (map_md5(map, tbsdata, tbssize, x509.tbshash)))) break; if(crtmgr_add(other, &x509)) break; cli_crt_clear(&x509); return 0; } while(0); cli_crt_clear(&x509); return 1; }
int crtmgr_add(crtmgr *m, cli_crt *x509) { cli_crt *i; int ret = 0; for(i = m->crts; i; i = i->next) { if(!memcmp(x509->subject, i->subject, sizeof(i->subject)) && !memcmp(x509->serial, i->subject, sizeof(i->serial)) && !mp_cmp(&x509->n, &i->n) && !mp_cmp(&x509->e, &i->e)) { if(x509->not_before >= i->not_before && x509->not_after <= i->not_after) { /* Already same or broader */ ret = 1; } if(i->not_before > x509->not_before && i->not_before <= x509->not_after) { /* Extend left */ i->not_before = x509->not_before; ret = 1; } if(i->not_after >= x509->not_before && i->not_after < x509->not_after) { /* Extend right */ i->not_after = x509->not_after; ret = 1; } if(!ret) continue; i->certSign |= x509->certSign; i->codeSign |= x509->codeSign; i->timeSign |= x509->timeSign; return 0; } /* If certs match, we're likely just revoking it */ if (!memcmp(x509->subject, i->subject, sizeof(x509->subject)) && !memcmp(x509->issuer, i->issuer, sizeof(x509->issuer)) && !memcmp(x509->serial, i->serial, sizeof(x509->serial)) && !mp_cmp(&x509->n, &i->n) && !mp_cmp(&x509->e, &i->e)) { if (i->isBlacklisted != x509->isBlacklisted) i->isBlacklisted = x509->isBlacklisted; return 0; } } i = cli_malloc(sizeof(*i)); if(!i) return 1; if((ret = mp_init_multi(&i->n, &i->e, &i->sig, NULL))) { cli_warnmsg("crtmgr_add: failed to mp_init failed with %d\n", ret); free(i); return 1; } if((ret = mp_copy(&x509->n, &i->n)) || (ret = mp_copy(&x509->e, &i->e)) || (ret = mp_copy(&x509->sig, &i->sig))) { cli_warnmsg("crtmgr_add: failed to mp_init failed with %d\n", ret); cli_crt_clear(i); free(i); return 1; } memcpy(i->subject, x509->subject, sizeof(i->subject)); memcpy(i->serial, x509->serial, sizeof(i->serial)); memcpy(i->issuer, x509->issuer, sizeof(i->issuer)); memcpy(i->tbshash, x509->tbshash, sizeof(i->tbshash)); i->not_before = x509->not_before; i->not_after = x509->not_after; i->hashtype = x509->hashtype; i->certSign = x509->certSign; i->codeSign = x509->codeSign; i->timeSign = x509->timeSign; i->isBlacklisted = x509->isBlacklisted; i->next = m->crts; i->prev = NULL; if(m->crts) m->crts->prev = i; m->crts = i; if(cli_debug_flag) { char issuer[SHA1_HASH_SIZE*2+1], subject[SHA1_HASH_SIZE*2+1]; char mod[1024], exp[1024]; int j=1024; // mod first fp_toradix_n(&i->n, mod, 16, j); // exp next fp_toradix_n(&i->e, exp, 16, j); // subject and issuer hashes for(j=0; j<SHA1_HASH_SIZE; j++) { sprintf(&issuer[j*2], "%02x", i->issuer[j]); sprintf(&subject[j*2], "%02x", i->subject[j]); } // printing lines, broken up to minimize truncation cli_dbgmsg("crtmgr_add: added cert s:%s i:%s %lu->%lu %s%s%s\n", subject, issuer, (unsigned long)i->not_before, (unsigned long)i->not_after, i->certSign ? "cert ":"", i->codeSign ? "code ":"", i->timeSign ? "time":""); cli_dbgmsg("crtmgr_add: n:%s \n", mod); cli_dbgmsg("crtmgr_add: e:%s \n", exp); } m->items++; return 0; }
int crtmgr_add(crtmgr *m, cli_crt *x509) { cli_crt *i; int ret = 0; for(i = m->crts; i; i = i->next) { if(!memcmp(x509->subject, i->subject, sizeof(i->subject)) && !memcmp(x509->serial, i->subject, sizeof(i->serial)) && !mp_cmp(&x509->n, &i->n) && !mp_cmp(&x509->e, &i->e)) { if(x509->not_before >= i->not_before && x509->not_after <= i->not_after) { /* Already same or broader */ ret = 1; } if(i->not_before > x509->not_before && i->not_before <= x509->not_after) { /* Extend left */ i->not_before = x509->not_before; ret = 1; } if(i->not_after >= x509->not_before && i->not_after < x509->not_after) { /* Extend right */ i->not_after = x509->not_after; ret = 1; } if(!ret) continue; i->certSign |= x509->certSign; i->codeSign |= x509->codeSign; i->timeSign |= x509->timeSign; return 0; } /* If certs match, we're likely just revoking it */ if (!memcmp(x509->subject, i->subject, sizeof(x509->subject)) && !memcmp(x509->issuer, i->issuer, sizeof(x509->issuer)) && !memcmp(x509->serial, i->serial, sizeof(x509->serial)) && !mp_cmp(&x509->n, &i->n) && !mp_cmp(&x509->e, &i->e)) { if (i->isBlacklisted != x509->isBlacklisted) i->isBlacklisted = x509->isBlacklisted; return 0; } } i = cli_malloc(sizeof(*i)); if(!i) return 1; if((ret = mp_init_multi(&i->n, &i->e, &i->sig, NULL))) { cli_warnmsg("crtmgr_add: failed to mp_init failed with %d\n", ret); free(i); return 1; } if((ret = mp_copy(&x509->n, &i->n)) || (ret = mp_copy(&x509->e, &i->e)) || (ret = mp_copy(&x509->sig, &i->sig))) { cli_warnmsg("crtmgr_add: failed to mp_init failed with %d\n", ret); cli_crt_clear(i); free(i); return 1; } if ((x509->name)) i->name = strdup(x509->name); else i->name = NULL; memcpy(i->subject, x509->subject, sizeof(i->subject)); memcpy(i->serial, x509->serial, sizeof(i->serial)); memcpy(i->issuer, x509->issuer, sizeof(i->issuer)); memcpy(i->tbshash, x509->tbshash, sizeof(i->tbshash)); i->not_before = x509->not_before; i->not_after = x509->not_after; i->hashtype = x509->hashtype; i->certSign = x509->certSign; i->codeSign = x509->codeSign; i->timeSign = x509->timeSign; i->isBlacklisted = x509->isBlacklisted; i->next = m->crts; i->prev = NULL; if(m->crts) m->crts->prev = i; m->crts = i; m->items++; return 0; }