//krazy:excludeall=license (program, not a library) /* ** cert_extract.c -- Extract CA Certs out of Netscape certN.db files ** ** Copyright Ariel Glenn ** Copyright 1998 Ralf S. Engelschall ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ** ** ** Originally written and released under the GPL by ** Ariel Glenn from the AcIS R&D group at Columbia ** as the two sources findoffset.c and dblist.c. See under ** http://www.columbia.edu/~ariel/good-certs/ for more details. ** ** Merged into one single program in August 1998 ** by Ralf S. Engelschall for use in the mod_ssl project. ** See under http://www.engelschall.com/sw/mod_ssl/ for more details. ** */ #include #include #include #include #include #include #include #include #include #include #include "openssl/asn1.h" #include "openssl/x509.h" int findoffset(char *dbname); int findoffset(char *dbname) { DB *db; DBT dkey, dvalue; int result; int offset = 0; char *p; int ptag = 0, pclass, plen; X509 *mycert; if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL) { fprintf(stderr, "Failed to open DB file '%s': %s\n", dbname, strerror(errno)); exit(1); } while ((result = (db->seq(db, &dkey, &dvalue, R_NEXT))) == 0) { if ((dvalue.size) > 520) { while (offset < dvalue.size) { p = (char *)dvalue.data + offset - 1; ASN1_get_object((unsigned char **)&p, (long *)&plen, &ptag, &pclass, dvalue.size); if (ptag == V_ASN1_SEQUENCE) { /* ok, it might be a cert then. */ /* include length of object header junk */ plen += p - ((char *) dvalue.data + offset - 1); mycert = NULL; p = (char *) dvalue.data + offset - 1; d2i_X509(&mycert, (unsigned char **) &p, plen); if (mycert == NULL) { /* must be garbage after all */ offset++; continue; } break; } else offset++; } if (offset > 0) break; /* found it, let's quit */ } } db->close(db); return (offset); } int main(int argc, char **argv) { char *dbname; DB *db; int j; int offset; DBT dkey, dvalue; int result; char oname[40]; int fout; int find; char *p; int ptag = 0, pclass, plen; X509 *mycert; char *shortname; char byte1, byte2; if (argc != 2) { fprintf(stderr, "usage: %s /path/to/netscape/cert.db\n", argv[0]); exit(1); } dbname = argv[1]; offset = findoffset(dbname); if (offset == 0) { fprintf(stderr, "Could not determine cert offset in DB file '%s'\n", dbname); exit(1); } else { fprintf(stderr, "Ok: certificates are at offset %d\n", offset); } if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL) { fprintf(stderr, "Failed to open DB file '%s': %s\n", dbname, strerror(errno)); exit(1); } if ((find = open("cert.index", O_WRONLY | O_CREAT | O_TRUNC, 0755)) == -1) { fprintf(stderr, "Failed to open Index file '%s': %s\n", "cert-index", strerror(errno)); exit(1); } j = 0; byte1 = -1; byte2 = -1; while ((result = (db->seq(db, &dkey, &dvalue, R_NEXT))) == 0) { if (dvalue.size > offset && ((dvalue.size) - offset) > 500) { p = (char *)dvalue.data + offset - 1; if (byte1 != -1 && byte2 != -1) if (byte1 != p[0] || byte2 != p[1]) continue; ASN1_get_object((unsigned char **)&p, (long *)&plen, &ptag, &pclass, dvalue.size); if (ptag == V_ASN1_SEQUENCE) { /* ok, it might be a cert then. */ if (byte1 == -1 && byte2 == -1) { byte1 = p[0]; byte2 = p[1]; } /* include length of object header junk */ plen += p - ((char *) dvalue.data + offset - 1); mycert = NULL; p = (char *) dvalue.data + offset - 1; d2i_X509(&mycert, (unsigned char **) &p, plen); if (mycert == NULL) { /* must be garbage after all */ continue; } j++; sprintf(oname, "cert.%02d.der", j); if ((fout = open(oname, O_WRONLY | O_CREAT | O_TRUNC, 0755)) == -1) { fprintf(stderr, "could not open %s\n", oname); continue; } write(fout, (char *) dvalue.data + offset - 1, plen); close(fout); write(find, oname, strlen(oname)); write(find, ": ", 2); shortname = (char *) dvalue.data + offset - 1 + plen; write(find, shortname, dvalue.size - plen - offset); write(find, "\n", 1); fprintf(stderr, "Extracted: %s (", oname); write(fileno(stderr), shortname, dvalue.size - plen - offset); fprintf(stderr, ")\n"); } else { /* fprintf(stderr, "Hmmm... ptag is %d, plen is %d\n", ptag, plen); */ } } } close(find); db->close(db); return (0); }