File indexing completed on 2024-05-05 12:13:38
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