1/* 2 * Copyright (c) 2003-2008,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * printCert.c - utility functions for printing certificate info 26 */ 27 28#include "printCert.h" 29#include <CoreFoundation/CoreFoundation.h> 30#include <Security/SecCertificatePriv.h> 31#include <Security/SecTrustPriv.h> 32 33void fprint_string(CFStringRef string, FILE *file) { 34 UInt8 buf[256]; 35 CFRange range = { .location = 0 }; 36 range.length = CFStringGetLength(string); 37 while (range.length > 0) { 38 CFIndex bytesUsed = 0; 39 CFIndex converted = CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, false, buf, sizeof(buf), &bytesUsed); 40 fwrite(buf, 1, bytesUsed, file); 41 range.length -= converted; 42 range.location += converted; 43 } 44} 45 46void print_line(CFStringRef line) { 47 fprint_string(line, stdout); 48 fputc('\n', stdout); 49} 50 51static void printPlist(CFArrayRef plist, CFIndex indent, CFIndex maxWidth) { 52 CFIndex count = CFArrayGetCount(plist); 53 CFIndex ix; 54 for (ix = 0; ix < count ; ++ix) { 55 CFDictionaryRef prop = (CFDictionaryRef)CFArrayGetValueAtIndex(plist, 56 ix); 57 CFStringRef pType = (CFStringRef)CFDictionaryGetValue(prop, 58 kSecPropertyKeyType); 59 CFStringRef label = (CFStringRef)CFDictionaryGetValue(prop, 60 kSecPropertyKeyLabel); 61 CFStringRef llabel = (CFStringRef)CFDictionaryGetValue(prop, 62 kSecPropertyKeyLocalizedLabel); 63 CFTypeRef value = (CFTypeRef)CFDictionaryGetValue(prop, 64 kSecPropertyKeyValue); 65 66 bool isSection = CFEqual(pType, kSecPropertyTypeSection); 67 CFMutableStringRef line = CFStringCreateMutable(NULL, 0); 68 CFIndex jx = 0; 69 for (jx = 0; jx < indent; ++jx) { 70 CFStringAppend(line, CFSTR(" ")); 71 } 72 if (llabel) { 73 CFStringAppend(line, llabel); 74 if (!isSection) { 75 for (jx = CFStringGetLength(llabel) + indent * 4; 76 jx < maxWidth; ++jx) { 77 CFStringAppend(line, CFSTR(" ")); 78 } 79 CFStringAppend(line, CFSTR(" : ")); 80 } 81 } 82 if (CFEqual(pType, kSecPropertyTypeWarning)) { 83 CFStringAppend(line, CFSTR("*WARNING* ")); 84 CFStringAppend(line, (CFStringRef)value); 85 } else if (CFEqual(pType, kSecPropertyTypeError)) { 86 CFStringAppend(line, CFSTR("*ERROR* ")); 87 CFStringAppend(line, (CFStringRef)value); 88 } else if (CFEqual(pType, kSecPropertyTypeSuccess)) { 89 CFStringAppend(line, CFSTR("*OK* ")); 90 CFStringAppend(line, (CFStringRef)value); 91 } else if (CFEqual(pType, kSecPropertyTypeTitle)) { 92 CFStringAppend(line, CFSTR("*")); 93 CFStringAppend(line, (CFStringRef)value); 94 CFStringAppend(line, CFSTR("*")); 95 } else if (CFEqual(pType, kSecPropertyTypeSection)) { 96 } else if (CFEqual(pType, kSecPropertyTypeData)) { 97 CFDataRef data = (CFDataRef)value; 98 CFIndex length = CFDataGetLength(data); 99 if (length > 20) 100 CFStringAppendFormat(line, NULL, CFSTR("[%d bytes] "), length); 101 const UInt8 *bytes = CFDataGetBytePtr(data); 102 for (jx = 0; jx < length; ++jx) { 103 if (jx == 0) 104 CFStringAppendFormat(line, NULL, CFSTR("%02X"), bytes[jx]); 105 else if (jx < 15 || length <= 20) 106 CFStringAppendFormat(line, NULL, CFSTR(" %02X"), 107 bytes[jx]); 108 else { 109 CFStringAppend(line, CFSTR(" ...")); 110 break; 111 } 112 } 113 } else if (CFEqual(pType, kSecPropertyTypeString)) { 114 CFStringAppend(line, (CFStringRef)value); 115 } else if (CFEqual(pType, kSecPropertyTypeDate)) { 116 CFDateRef date = (CFDateRef)value; 117 CFLocaleRef lc = CFLocaleCopyCurrent(); 118 CFDateFormatterRef df = CFDateFormatterCreate(NULL, lc, kCFDateFormatterMediumStyle, kCFDateFormatterLongStyle); 119 CFStringRef ds; 120 if (df) { 121 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0); 122 CFDateFormatterSetProperty(df, kCFDateFormatterTimeZone, tz); 123 CFRelease(tz); 124 ds = CFDateFormatterCreateStringWithDate(NULL, df, date); 125 CFRelease(df); 126 } else { 127 ds = CFStringCreateWithFormat(NULL, NULL, CFSTR("%g"), CFDateGetAbsoluteTime(date)); 128 } 129 CFStringAppend(line, ds); 130 CFRelease(ds); 131 CFRelease(lc); 132 } else if (CFEqual(pType, kSecPropertyTypeURL)) { 133 CFURLRef url = (CFURLRef)value; 134 CFStringAppend(line, CFSTR("<")); 135 CFStringAppend(line, CFURLGetString(url)); 136 CFStringAppend(line, CFSTR(">")); 137 } else { 138 CFStringAppendFormat(line, NULL, CFSTR("*unknown type %@* = %@"), 139 pType, value); 140 } 141 142 if (!isSection || label) 143 print_line(line); 144 CFRelease(line); 145 if (isSection) { 146 printPlist((CFArrayRef)value, indent + 1, maxWidth); 147 } 148 } 149} 150 151static CFIndex maxLabelWidth(CFArrayRef plist, CFIndex indent) { 152 CFIndex count = CFArrayGetCount(plist); 153 CFIndex ix; 154 CFIndex maxWidth = 0; 155 for (ix = 0; ix < count ; ++ix) { 156 CFDictionaryRef prop = (CFDictionaryRef)CFArrayGetValueAtIndex(plist, 157 ix); 158 CFStringRef pType = (CFStringRef)CFDictionaryGetValue(prop, 159 kSecPropertyKeyType); 160 CFStringRef llabel = (CFStringRef)CFDictionaryGetValue(prop, 161 kSecPropertyKeyLocalizedLabel); 162 CFTypeRef value = (CFTypeRef)CFDictionaryGetValue(prop, 163 kSecPropertyKeyValue); 164 165 if (CFEqual(pType, kSecPropertyTypeSection)) { 166 CFIndex width = maxLabelWidth((CFArrayRef)value, indent + 1); 167 if (width > maxWidth) 168 maxWidth = width; 169 } else if (llabel) { 170 CFIndex width = indent * 4 + CFStringGetLength(llabel); 171 if (width > maxWidth) 172 maxWidth = width; 173 } 174 } 175 176 return maxWidth; 177} 178 179void print_plist(CFArrayRef plist) { 180 if (plist) 181 printPlist(plist, 0, maxLabelWidth(plist, 0)); 182 else 183 printf("NULL plist\n"); 184} 185 186void print_cert(SecCertificateRef cert, bool verbose) { 187// TODO: merge these when all SecCertificate APIs are present on both iOS and OS X 188#if TARGET_OS_IOS 189 CFArrayRef plist; 190 if (verbose) 191 plist = SecCertificateCopyProperties(cert); 192 else { 193 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); 194 plist = SecCertificateCopySummaryProperties(cert, now); 195 } 196 197 CFStringRef subject = SecCertificateCopySubjectString(cert); 198 if (subject) { 199 print_line(subject); 200 CFRelease(subject); 201 } else { 202 print_line(CFSTR("no subject")); 203 } 204 205 print_plist(plist); 206 CFRelease(plist); 207#else 208 CFStringRef certName = NULL; 209 OSStatus status = SecCertificateInferLabel(cert, &certName); 210 if (certName) { 211 print_line(certName); 212 CFRelease(certName); 213 } 214 else { 215 fprintf(stdout, "ERROR: unable to read certificate name\n"); 216 } 217#endif 218} 219