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 14static 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 */ 23static 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[] */ 50static 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 */ 67bool 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 90int 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 164