File indexing completed on 2024-05-05 16:08:30

0001 //krazy:excludeall=license (program, not a library)
0002 /*
0003 **  cert_extract.c -- Extract CA Certs out of Netscape certN.db files
0004 **
0005 **  Copyright      Ariel Glenn <ariel@columbia.edu>
0006 **  Copyright 1998 Ralf S. Engelschall <rse@engelschall.com>
0007 **
0008 **  This program is free software; you can redistribute it and/or modify
0009 **  it under the terms of the GNU General Public License as published by
0010 **  the Free Software Foundation; either version 2 of the License, or
0011 **  (at your option) any later version.
0012 **
0013 **  This program is distributed in the hope that it will be useful,
0014 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
0015 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016 **  GNU General Public License for more details.
0017 **
0018 **  You should have received a copy of the GNU General Public License
0019 **  along with this program; if not, write to the Free Software
0020 **  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0021 **
0022 **
0023 **  Originally written and released under the GPL by
0024 **  Ariel Glenn from the AcIS R&D group at Columbia
0025 **  as the two sources findoffset.c and dblist.c. See under
0026 **  http://www.columbia.edu/~ariel/good-certs/ for more details.
0027 **
0028 **  Merged into one single program in August 1998
0029 **  by Ralf S. Engelschall for use in the mod_ssl project.
0030 **  See under http://www.engelschall.com/sw/mod_ssl/ for more details.
0031 **
0032 */
0033 
0034 #include <stdlib.h>
0035 #include <stdio.h>
0036 #include <string.h>
0037 #include <fcntl.h>
0038 #include <ctype.h>
0039 #include <errno.h>
0040 #include <unistd.h>
0041 #include <sys/types.h>
0042 #include <sys/time.h>
0043 
0044 #include <db1/db.h>
0045 
0046 #include "openssl/asn1.h"
0047 #include "openssl/x509.h"
0048 
0049 int findoffset(char *dbname);
0050 
0051 int findoffset(char *dbname)
0052 {
0053     DB *db;
0054     DBT dkey, dvalue;
0055     int result;
0056     int offset = 0;
0057     char *p;
0058     int ptag = 0, pclass, plen;
0059     X509 *mycert;
0060 
0061     if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL) {
0062         fprintf(stderr, "Failed to open DB file '%s': %s\n", dbname, strerror(errno));
0063         exit(1);
0064     }
0065     while ((result = (db->seq(db, &dkey, &dvalue, R_NEXT))) == 0) {
0066         if ((dvalue.size) > 520) {
0067             while (offset < dvalue.size) {
0068                 p = (char *)dvalue.data + offset - 1;
0069                 ASN1_get_object((unsigned char **)&p, (long *)&plen, &ptag, &pclass, dvalue.size);
0070                 if (ptag == V_ASN1_SEQUENCE) {  /* ok, it might be a cert then. */
0071                     /* include length of object header junk */
0072                     plen += p - ((char *) dvalue.data + offset - 1);
0073                     mycert = NULL;
0074                     p = (char *) dvalue.data + offset - 1;
0075                     d2i_X509(&mycert, (unsigned char **) &p, plen);
0076                     if (mycert == NULL) {       /* must be garbage after all */
0077                         offset++;
0078                         continue;
0079                     }
0080                     break;
0081                 } else {
0082                     offset++;
0083                 }
0084             }
0085             if (offset > 0) {
0086                 break;    /* found it, let's quit */
0087             }
0088         }
0089     }
0090     db->close(db);
0091     return (offset);
0092 }
0093 
0094 int main(int argc, char **argv)
0095 {
0096     char *dbname;
0097     DB *db;
0098     int j;
0099     int offset;
0100     DBT dkey, dvalue;
0101     int result;
0102     char oname[40];
0103     int fout;
0104     int find;
0105     char *p;
0106     int ptag = 0, pclass, plen;
0107     X509 *mycert;
0108     char *shortname;
0109     char byte1, byte2;
0110 
0111     if (argc != 2) {
0112         fprintf(stderr, "usage: %s /path/to/netscape/cert.db\n", argv[0]);
0113         exit(1);
0114     }
0115 
0116     dbname = argv[1];
0117     offset = findoffset(dbname);
0118     if (offset == 0) {
0119         fprintf(stderr, "Could not determine cert offset in DB file '%s'\n", dbname);
0120         exit(1);
0121     } else {
0122         fprintf(stderr, "Ok: certificates are at offset %d\n", offset);
0123     }
0124 
0125     if ((db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL) {
0126         fprintf(stderr, "Failed to open DB file '%s': %s\n", dbname, strerror(errno));
0127         exit(1);
0128     }
0129     if ((find = open("cert.index", O_WRONLY | O_CREAT | O_TRUNC, 0755)) == -1) {
0130         fprintf(stderr, "Failed to open Index file '%s': %s\n", "cert-index", strerror(errno));
0131         exit(1);
0132     }
0133     j = 0;
0134     byte1 = -1;
0135     byte2 = -1;
0136     while ((result = (db->seq(db, &dkey, &dvalue, R_NEXT))) == 0) {
0137         if (dvalue.size > offset && ((dvalue.size) - offset) > 500) {
0138             p = (char *)dvalue.data + offset - 1;
0139             if (byte1 != -1 && byte2 != -1)
0140                 if (byte1 != p[0] || byte2 != p[1]) {
0141                     continue;
0142                 }
0143             ASN1_get_object((unsigned char **)&p, (long *)&plen, &ptag, &pclass, dvalue.size);
0144             if (ptag == V_ASN1_SEQUENCE) {      /* ok, it might be a cert then. */
0145                 if (byte1 == -1 && byte2 == -1) {
0146                     byte1 = p[0];
0147                     byte2 = p[1];
0148                 }
0149                 /* include length of object header junk */
0150                 plen += p - ((char *) dvalue.data + offset - 1);
0151                 mycert = NULL;
0152                 p = (char *) dvalue.data + offset - 1;
0153                 d2i_X509(&mycert, (unsigned char **) &p, plen);
0154                 if (mycert == NULL) {   /* must be garbage after all */
0155                     continue;
0156                 }
0157                 j++;
0158                 sprintf(oname, "cert.%02d.der", j);
0159                 if ((fout = open(oname, O_WRONLY | O_CREAT | O_TRUNC, 0755)) == -1) {
0160                     fprintf(stderr, "could not open %s\n", oname);
0161                     continue;
0162                 }
0163                 write(fout, (char *) dvalue.data + offset - 1, plen);
0164                 close(fout);
0165                 write(find, oname, strlen(oname));
0166                 write(find, ": ", 2);
0167                 shortname = (char *) dvalue.data + offset - 1 + plen;
0168                 write(find, shortname, dvalue.size - plen - offset);
0169                 write(find, "\n", 1);
0170                 fprintf(stderr, "Extracted: %s (", oname);
0171                 write(fileno(stderr), shortname, dvalue.size - plen - offset);
0172                 fprintf(stderr, ")\n");
0173             } else {
0174                 /* fprintf(stderr, "Hmmm... ptag is %d, plen is %d\n", ptag, plen); */
0175             }
0176         }
0177     }
0178     close(find);
0179     db->close(db);
0180 
0181     return (0);
0182 }
0183