]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Attempt to decode either one file, or every file in cwd, | |
3 | * as a cert. Used to study vulnerability to NISCC cert DOS attacks. | |
4 | */ | |
5 | #include <Security/SecAsn1Coder.h> | |
6 | #include <Security/X509Templates.h> | |
7 | #include <security_cdsa_utils/cuFileIo.h> | |
8 | #include <sys/types.h> | |
9 | #include <dirent.h> | |
10 | #include <stdio.h> | |
11 | #include <stdlib.h> | |
12 | #include <strings.h> | |
13 | ||
14 | static void usage(char **argv) | |
15 | { | |
16 | printf("usage: %s [-l(oop))] [certFile]\n", argv[0]); | |
17 | exit(1); | |
18 | } | |
19 | ||
20 | /* | |
21 | * Known file names to NOT parse | |
22 | */ | |
23 | static const char *skipTheseFiles[] = | |
24 | { | |
25 | /* standard entries */ | |
26 | ".", | |
27 | "..", | |
28 | "CVS", | |
29 | ".cvsignore", | |
30 | /* the certs we know crash */ | |
31 | #if 0 | |
32 | "00000668", | |
33 | "00000681", | |
34 | "00001980", | |
35 | "00002040", | |
36 | "00002892", | |
37 | "00007472", | |
38 | "00008064", | |
39 | "00008656", | |
40 | "00009840", | |
41 | "00010432", | |
42 | "00011614", // trouble somewhere in this neighborhood | |
43 | "00011615", | |
44 | "00011616", | |
45 | #endif | |
46 | NULL | |
47 | }; | |
48 | ||
49 | /* returns false if specified fileName is in skipTheseFiles[] */ | |
50 | static bool shouldWeParse( | |
51 | const char *fileName) // C string | |
52 | { | |
53 | for(const char **stf=skipTheseFiles; *stf!=NULL; stf++) { | |
54 | const char *tf = *stf; | |
55 | if(!strcmp(fileName, *stf)) { | |
56 | return false; | |
57 | } | |
58 | } | |
59 | return true; | |
60 | } | |
61 | ||
62 | /* | |
63 | * Just try to decode - if SecAsn1Decode returns, good 'nuff. | |
64 | * Returns true if it does (i.e. ignore decode error; we're trying | |
65 | * to detect a crash when the decoder should return an error). | |
66 | */ | |
67 | bool decodeCert( | |
68 | const void *certData, | |
69 | size_t certDataLen) | |
70 | { | |
71 | SecAsn1CoderRef coder = NULL; | |
72 | NSS_Certificate nssCert; | |
73 | NSS_SignedCertOrCRL certOrCrl; | |
74 | ||
75 | SecAsn1CoderCreate(&coder); | |
76 | ||
77 | /* first the full decode */ | |
78 | memset(&nssCert, 0, sizeof(nssCert)); | |
79 | SecAsn1Decode(coder, certData, certDataLen, kSecAsn1SignedCertTemplate, &nssCert); | |
80 | ||
81 | /* now the "just TBS and sig" decode - this is actually harder | |
82 | * due to nested SEC_ASN1_SAVE ops */ | |
83 | memset(&certOrCrl, 0, sizeof(NSS_SignedCertOrCRL)); | |
84 | SecAsn1Decode(coder, certData, certDataLen, kSecAsn1SignedCertOrCRLTemplate, &certOrCrl); | |
85 | ||
86 | SecAsn1CoderRelease(coder); | |
87 | return true; | |
88 | } | |
89 | ||
90 | int main(int argc, char **argv) | |
91 | { | |
92 | bool quiet = false; | |
93 | unsigned char *certData; | |
94 | unsigned certDataLen; | |
95 | bool loop = false; | |
96 | int filearg = 1; | |
97 | ||
98 | if(argc > 3 ) { | |
99 | usage(argv); | |
100 | } | |
101 | if((argc > 1) && (argv[1][0] == '-')) { | |
102 | switch(argv[1][1]) { | |
103 | case 'l': | |
104 | loop = true; | |
105 | break; | |
106 | default: | |
107 | usage(argv); | |
108 | } | |
109 | filearg++; | |
110 | argc--; | |
111 | } | |
112 | if(argc == 2) { | |
113 | /* read & parse one file */ | |
114 | char *oneFile = argv[filearg]; | |
115 | if(readFile(oneFile, &certData, &certDataLen)) { | |
116 | printf("\n***Error reading file %s. Aborting.\n", oneFile); | |
117 | exit(1); | |
118 | } | |
119 | do { | |
120 | if(!quiet) { | |
121 | printf("...%s", oneFile); | |
122 | fflush(stdout); | |
123 | } | |
124 | if(!decodeCert(certData, certDataLen)) { | |
125 | printf("\n***GOT AN EXCEPTION ON %s\n", oneFile); | |
126 | exit(1); | |
127 | } | |
128 | } while(loop); | |
129 | free(certData); | |
130 | exit(0); | |
131 | } | |
132 | DIR *dir = opendir("."); | |
133 | if(dir == NULL) { | |
134 | printf("Huh? Can't open . as a directory.\n"); | |
135 | exit(1); | |
136 | } | |
137 | struct dirent *de = readdir(dir); | |
138 | while(de != NULL) { | |
139 | char filename[MAXNAMLEN + 1]; | |
140 | memmove(filename, de->d_name, de->d_namlen); | |
141 | filename[de->d_namlen] = '\0'; | |
142 | if(shouldWeParse(filename)) { | |
143 | if(!quiet) { | |
144 | printf("...%s", filename); | |
145 | fflush(stdout); | |
146 | } | |
147 | if(readFile(filename, &certData, &certDataLen)) { | |
148 | printf("\n***Error reading file %s. Aborting.\n", filename); | |
149 | exit(1); | |
150 | } | |
151 | if(!decodeCert(certData, certDataLen)) { | |
152 | printf("\n***GOT AN EXCEPTION ON %s\n", filename); | |
153 | exit(1); | |
154 | } | |
155 | free(certData); | |
156 | } | |
157 | de = readdir(dir); | |
158 | } | |
159 | closedir(dir); | |
160 | printf("\ncertDecode did not crash.\n"); | |
161 | return 0; | |
162 | } | |
163 |