]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2003-2008,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
d8f41ccd | 5 | * |
b1ab9ed8 A |
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. | |
d8f41ccd | 12 | * |
b1ab9ed8 A |
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. | |
d8f41ccd | 20 | * |
b1ab9ed8 A |
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 | ||
33 | void 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 | ||
46 | void print_line(CFStringRef line) { | |
47 | fprint_string(line, stdout); | |
48 | fputc('\n', stdout); | |
49 | } | |
50 | ||
51 | static 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 | ||
151 | static 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 | ||
179 | void print_plist(CFArrayRef plist) { | |
180 | if (plist) | |
181 | printPlist(plist, 0, maxLabelWidth(plist, 0)); | |
182 | else | |
183 | printf("NULL plist\n"); | |
184 | } | |
185 | ||
186 | void 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 | } |