1/* 2 * rootUtils.cpp - utility routines for rootStoreTool 3 */ 4 5#include <stdlib.h> 6#include <strings.h> 7#include <stdio.h> 8#include <unistd.h> 9#include "rootUtils.h" 10#include <Security/SecCertificatePriv.h> 11#include <Security/SecBasePriv.h> 12#include <Security/SecTrustSettings.h> 13#include <Security/TrustSettingsSchema.h> /* private header */ 14#include <Security/SecAsn1Coder.h> 15#include <Security/nameTemplates.h> /* oh frabjous day */ 16 17#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 18 19static int indentSize = 0; 20void indentIncr(void) { indentSize += 3; } 21void indentDecr(void) { indentSize -= 3; } 22 23void indent(void) 24{ 25 if(indentSize < 0) { 26 printf("***indent screwup\n"); 27 indentSize = 0; 28 } 29 for (int dex=0; dex<indentSize; dex++) { 30 putchar(' '); 31 } 32} 33 34void printAscii( 35 const char *buf, 36 unsigned len, 37 unsigned maxLen) 38{ 39 bool doEllipsis = false; 40 if(len > maxLen) { 41 len = maxLen; 42 doEllipsis = true; 43 } 44 for(unsigned dex=0; dex<len; dex++) { 45 char c = *buf++; 46 if(isalnum(c) || (c == ' ')) { 47 putchar(c); 48 } 49 else { 50 putchar('.'); 51 } 52 fflush(stdout); 53 } 54 if(doEllipsis) { 55 printf("...etc."); 56 } 57} 58 59void printHex( 60 const unsigned char *buf, 61 unsigned len, 62 unsigned maxLen) 63{ 64 bool doEllipsis = false; 65 if(len > maxLen) { 66 len = maxLen; 67 doEllipsis = true; 68 } 69 for(unsigned dex=0; dex<len; dex++) { 70 printf("%02X ", *buf++); 71 } 72 if(doEllipsis) { 73 printf("...etc."); 74 } 75} 76 77void printOid( 78 const void *buf, 79 unsigned len, 80 OidParser &parser) 81{ 82 char outstr[OID_PARSER_STRING_SIZE]; 83 parser.oidParse((const unsigned char *)buf, len, outstr); 84 printf("%s", outstr); 85} 86 87void printData( 88 const char *label, 89 CFDataRef data, 90 PrintDataType whichType, 91 OidParser &parser) 92{ 93 const unsigned char *buf = CFDataGetBytePtr(data); 94 unsigned len = CFDataGetLength(data); 95 96 printf("%s: ", label); 97 switch(whichType) { 98 case PD_Hex: 99 printHex(buf, len, 16); 100 break; 101 case PD_ASCII: 102 printAscii((const char *)buf, len, 50); 103 break; 104 case PD_OID: 105 printOid(buf, len, parser); 106 } 107 putchar('\n'); 108} 109 110/* print the contents of a CFString */ 111void printCfStr( 112 CFStringRef cfstr) 113{ 114 CFDataRef strData = CFStringCreateExternalRepresentation(NULL, cfstr, 115 kCFStringEncodingUTF8, true); 116 if(strData == NULL) { 117 printf("<<string decode error>>"); 118 return; 119 } 120 const char *cp = (const char *)CFDataGetBytePtr(strData); 121 CFIndex len = CFDataGetLength(strData); 122 for(CFIndex dex=0; dex<len; dex++) { 123 putchar(*cp++); 124 } 125 CFRelease(strData); 126} 127 128/* print a CFDateRef */ 129static const char *months[12] = { 130 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 131 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 132}; 133 134void printCFDate( 135 CFDateRef dateRef) 136{ 137 CFAbsoluteTime absTime = CFDateGetAbsoluteTime(dateRef); 138 if(absTime == 0.0) { 139 printf("<<Malformed CFDateeRef>>\n"); 140 return; 141 } 142 CFGregorianDate gregDate = CFAbsoluteTimeGetGregorianDate(absTime, NULL); 143 const char *month = "Unknown"; 144 if((gregDate.month > 12) || (gregDate.month <= 0)) { 145 printf("Huh? GregDate.month > 11. These amps only GO to 11.\n"); 146 } 147 else { 148 month = months[gregDate.month - 1]; 149 } 150 printf("%s %d, %ld %02d:%02d", 151 month, gregDate.day, gregDate.year, gregDate.hour, gregDate.minute); 152} 153 154/* print a CFNumber */ 155void printCfNumber( 156 CFNumberRef cfNum) 157{ 158 SInt32 s; 159 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) { 160 printf("***CFNumber overflow***"); 161 return; 162 } 163 printf("%ld", s); 164} 165 166/* print a CFNumber as a SecTrustSettingsResult */ 167void printResult( 168 CFNumberRef cfNum) 169{ 170 SInt32 n; 171 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &n)) { 172 printf("***CFNumber overflow***"); 173 return; 174 } 175 const char *s; 176 char bogus[100]; 177 switch(n) { 178 case kSecTrustSettingsResultInvalid: s = "kSecTrustSettingsResultInvalid"; break; 179 case kSecTrustSettingsResultTrustRoot: s = "kSecTrustSettingsResultTrustRoot"; break; 180 case kSecTrustSettingsResultTrustAsRoot: s = "kSecTrustSettingsResultTrustAsRoot"; break; 181 case kSecTrustSettingsResultDeny: s = "kSecTrustSettingsResultDeny"; break; 182 case kSecTrustSettingsResultUnspecified: s = "kSecTrustSettingsResultUnspecified"; break; 183 default: 184 sprintf(bogus, "Unknown SecTrustSettingsResult (%ld)", n); 185 s = bogus; 186 break; 187 } 188 printf("%s", s); 189} 190 191/* print a CFNumber as SecTrustSettingsKeyUsage */ 192void printKeyUsage( 193 CFNumberRef cfNum) 194{ 195 SInt32 s; 196 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) { 197 printf("***CFNumber overflow***"); 198 return; 199 } 200 uint32 n = (uint32)s; 201 if(n == kSecTrustSettingsKeyUseAny) { 202 printf("<any>"); 203 return; 204 } 205 else if(n == 0) { 206 printf("<none>"); 207 return; 208 } 209 printf("< "); 210 if(n & kSecTrustSettingsKeyUseSignature) { 211 printf("Signature "); 212 } 213 if(n & kSecTrustSettingsKeyUseEnDecryptData) { 214 printf("EnDecryptData "); 215 } 216 if(n & kSecTrustSettingsKeyUseEnDecryptKey) { 217 printf("EnDecryptKey "); 218 } 219 if(n & kSecTrustSettingsKeyUseSignCert) { 220 printf("SignCert "); 221 } 222 if(n & kSecTrustSettingsKeyUseSignRevocation) { 223 printf("SignRevocation "); 224 } 225 if(n & kSecTrustSettingsKeyUseKeyExchange) { 226 printf("KeyExchange "); 227 } 228 printf(" >"); 229} 230 231/* print a CFNumber as CSSM_RETURN string */ 232void printCssmErr( 233 CFNumberRef cfNum) 234{ 235 SInt32 s; 236 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) { 237 printf("***CFNumber overflow***"); 238 return; 239 } 240 printf("%s", cssmErrorString((CSSM_RETURN)s)); 241} 242 243/* print cert's label (the one SecCertificate infers) */ 244OSStatus printCertLabel( 245 SecCertificateRef certRef) 246{ 247 OSStatus ortn; 248 CFStringRef label; 249 250 ortn = SecCertificateInferLabel(certRef, &label); 251 if(ortn) { 252 cssmPerror("SecCertificateInferLabel", ortn); 253 return ortn; 254 } 255 printCfStr(label); 256 CFRelease(label); 257 return noErr; 258} 259 260/* 261 * How many items in a NULL-terminated array of pointers? 262 */ 263static unsigned nssArraySize( 264 const void **array) 265{ 266 unsigned count = 0; 267 if (array) { 268 while (*array++) { 269 count++; 270 } 271 } 272 return count; 273} 274 275static int compareOids( 276 const CSSM_OID *data1, 277 const CSSM_OID *data2) 278{ 279 if((data1 == NULL) || (data1->Data == NULL) || 280 (data2 == NULL) || (data2->Data == NULL) || 281 (data1->Length != data2->Length)) { 282 return 0; 283 } 284 if(data1->Length != data2->Length) { 285 return 0; 286 } 287 return memcmp(data1->Data, data2->Data, data1->Length) == 0; 288} 289 290static void printRdn(const NSS_RDN *rdn, OidParser &parser) 291{ 292 unsigned numAtvs = nssArraySize((const void **)rdn->atvs); 293 char *fieldName; 294 295 for(unsigned dex=0; dex<numAtvs; dex++) { 296 const NSS_ATV *atv = rdn->atvs[dex]; 297 if(compareOids(&atv->type, &CSSMOID_CountryName)) { 298 fieldName = "Country "; 299 } 300 else if(compareOids(&atv->type, &CSSMOID_OrganizationName)) { 301 fieldName = "Org "; 302 } 303 else if(compareOids(&atv->type, &CSSMOID_LocalityName)) { 304 fieldName = "Locality "; 305 } 306 else if(compareOids(&atv->type, &CSSMOID_OrganizationalUnitName)) { 307 fieldName = "OrgUnit "; 308 } 309 else if(compareOids(&atv->type, &CSSMOID_CommonName)) { 310 fieldName = "Common Name "; 311 } 312 else if(compareOids(&atv->type, &CSSMOID_Surname)) { 313 fieldName = "Surname "; 314 } 315 else if(compareOids(&atv->type, &CSSMOID_Title)) { 316 fieldName = "Title "; 317 } 318 else if(compareOids(&atv->type, &CSSMOID_Surname)) { 319 fieldName = "Surname "; 320 } 321 else if(compareOids(&atv->type, &CSSMOID_StateProvinceName)) { 322 fieldName = "State "; 323 } 324 else if(compareOids(&atv->type, &CSSMOID_CollectiveStateProvinceName)) { 325 fieldName = "Coll. State "; 326 } 327 else if(compareOids(&atv->type, &CSSMOID_EmailAddress)) { 328 /* deprecated, used by Thawte */ 329 fieldName = "Email addrs "; 330 } 331 else { 332 fieldName = "Other name "; 333 } 334 indent(); printf("%s : ", fieldName); 335 /* Not strictly true here, but we'll just assume we can print everything */ 336 printAscii((char *)atv->value.item.Data, atv->value.item.Length, 337 atv->value.item.Length); 338 putchar('\n'); 339 } 340} 341 342/* print a CFData as an X509 Name (i.e., subject or issuer) */ 343void printCfName( 344 CFDataRef nameData, 345 OidParser &parser) 346{ 347 SecAsn1CoderRef coder = NULL; 348 OSStatus ortn; 349 350 ortn = SecAsn1CoderCreate(&coder); 351 if(ortn) { 352 cssmPerror("SecAsn1CoderCreate", ortn); 353 return; 354 } 355 /* subsequent errors to errOut: */ 356 357 NSS_Name nssName = {NULL}; 358 unsigned numRdns; 359 360 ortn = SecAsn1Decode(coder, 361 CFDataGetBytePtr(nameData), CFDataGetLength(nameData), 362 kSecAsn1NameTemplate, 363 &nssName); 364 if(ortn) { 365 printf("***Error decoding NSS_Name\n"); 366 goto errOut; 367 } 368 numRdns = nssArraySize((const void **)nssName.rdns); 369 for(unsigned dex=0; dex<numRdns; dex++) { 370 printRdn(nssName.rdns[dex], parser); 371 } 372 373errOut: 374 if(coder) { 375 SecAsn1CoderRelease(coder); 376 } 377} 378 379