2 * anchorTest.cpp - test cert encode/decode using known good system
7 #include <Security/cssm.h>
8 #include <Security/x509defs.h>
9 #include <Security/oidsattr.h>
10 #include <Security/oidscert.h>
11 #include <Security/certextensions.h>
12 #include <Security/SecTrust.h>
13 #include <Security/SecTrustSettingsPriv.h>
14 #include <security_cdsa_utils/cuOidParser.h>
15 #include <security_cdsa_utils/cuPrintCert.h>
16 #include <utilLib/common.h>
17 #include <utilLib/cspwrap.h>
18 #include <security_cdsa_utils/cuFileIo.h>
19 #include <clAppUtils/clutils.h>
20 #include <clAppUtils/certVerify.h>
21 #include <clAppUtils/tpUtils.h>
22 #include <Security/SecAsn1Coder.h>
23 #include <Security/X509Templates.h>
25 #define ENC_TBS_BLOB "encodedTbs.der"
26 #define DEC_TBS_BLOB "decodedTbs.der"
28 static void usage(char **argv
)
30 printf("Usage: %s [options]\n", argv
[0]);
32 printf(" w -- writeBlobs\n");
33 printf(" e -- allow expired roots\n");
34 printf(" t -- use Trust Settings\n");
35 printf(" q -- quiet\n");
36 printf(" v -- verbose\n");
41 * Certs for which we skip the "compare TBS blob" test, enumerated by
42 * DER-encoded issuer name.
44 * Get this formatted data from the extractCertFields program.
46 * All of these have non-standard KeyUsage encoding (legal but it's
47 * not the same as ours or everyone else's).
52 Org : NetLock Halozatbiztonsagi Kft.
53 OrgUnit : Tanusitvanykiadok
54 Common Name : NetLock Expressz (Class C) Tanusitvanykiado
56 static const uint8 anchor_46_derIssuer_bytes
[] = {
57 0x30, 0x81, 0x9b, 0x31, 0x0b, 0x30, 0x09, 0x06,
58 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
59 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
60 0x07, 0x13, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70,
61 0x65, 0x73, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06,
62 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e, 0x4e, 0x65,
63 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x48, 0x61,
64 0x6c, 0x6f, 0x7a, 0x61, 0x74, 0x62, 0x69, 0x7a,
65 0x74, 0x6f, 0x6e, 0x73, 0x61, 0x67, 0x69, 0x20,
66 0x4b, 0x66, 0x74, 0x2e, 0x31, 0x1a, 0x30, 0x18,
67 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x11, 0x54,
68 0x61, 0x6e, 0x75, 0x73, 0x69, 0x74, 0x76, 0x61,
69 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64, 0x6f, 0x6b,
70 0x31, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55, 0x04,
71 0x03, 0x13, 0x2b, 0x4e, 0x65, 0x74, 0x4c, 0x6f,
72 0x63, 0x6b, 0x20, 0x45, 0x78, 0x70, 0x72, 0x65,
73 0x73, 0x73, 0x7a, 0x20, 0x28, 0x43, 0x6c, 0x61,
74 0x73, 0x73, 0x20, 0x43, 0x29, 0x20, 0x54, 0x61,
75 0x6e, 0x75, 0x73, 0x69, 0x74, 0x76, 0x61, 0x6e,
76 0x79, 0x6b, 0x69, 0x61, 0x64, 0x6f
78 static const CSSM_DATA anchor_46_derIssuer
= { 158, (uint8
*)anchor_46_derIssuer_bytes
};
84 Org : NetLock Halozatbiztonsagi Kft.
85 OrgUnit : Tanusitvanykiadok
86 Common Name : NetLock Kozjegyzoi (Class A) Tanusitvanykiado
88 static const uint8 anchor_53_derIssuer_bytes
[] = {
89 0x30, 0x81, 0xaf, 0x31, 0x0b, 0x30, 0x09, 0x06,
90 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
91 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
92 0x08, 0x13, 0x07, 0x48, 0x75, 0x6e, 0x67, 0x61,
93 0x72, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
94 0x55, 0x04, 0x07, 0x13, 0x08, 0x42, 0x75, 0x64,
95 0x61, 0x70, 0x65, 0x73, 0x74, 0x31, 0x27, 0x30,
96 0x25, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e,
97 0x4e, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20,
98 0x48, 0x61, 0x6c, 0x6f, 0x7a, 0x61, 0x74, 0x62,
99 0x69, 0x7a, 0x74, 0x6f, 0x6e, 0x73, 0x61, 0x67,
100 0x69, 0x20, 0x4b, 0x66, 0x74, 0x2e, 0x31, 0x1a,
101 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
102 0x11, 0x54, 0x61, 0x6e, 0x75, 0x73, 0x69, 0x74,
103 0x76, 0x61, 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64,
104 0x6f, 0x6b, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03,
105 0x55, 0x04, 0x03, 0x13, 0x2d, 0x4e, 0x65, 0x74,
106 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x4b, 0x6f, 0x7a,
107 0x6a, 0x65, 0x67, 0x79, 0x7a, 0x6f, 0x69, 0x20,
108 0x28, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x41,
109 0x29, 0x20, 0x54, 0x61, 0x6e, 0x75, 0x73, 0x69,
110 0x74, 0x76, 0x61, 0x6e, 0x79, 0x6b, 0x69, 0x61,
113 static const CSSM_DATA anchor_53_derIssuer
= { 178, (uint8
*)anchor_53_derIssuer_bytes
};
118 Org : NetLock Halozatbiztonsagi Kft.
119 OrgUnit : Tanusitvanykiadok
120 Common Name : NetLock Uzleti (Class B) Tanusitvanykiado
122 static const uint8 anchor_60_derIssuer_bytes
[] = {
123 0x30, 0x81, 0x99, 0x31, 0x0b, 0x30, 0x09, 0x06,
124 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
125 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
126 0x07, 0x13, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70,
127 0x65, 0x73, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06,
128 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e, 0x4e, 0x65,
129 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x48, 0x61,
130 0x6c, 0x6f, 0x7a, 0x61, 0x74, 0x62, 0x69, 0x7a,
131 0x74, 0x6f, 0x6e, 0x73, 0x61, 0x67, 0x69, 0x20,
132 0x4b, 0x66, 0x74, 0x2e, 0x31, 0x1a, 0x30, 0x18,
133 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x11, 0x54,
134 0x61, 0x6e, 0x75, 0x73, 0x69, 0x74, 0x76, 0x61,
135 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64, 0x6f, 0x6b,
136 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04,
137 0x03, 0x13, 0x29, 0x4e, 0x65, 0x74, 0x4c, 0x6f,
138 0x63, 0x6b, 0x20, 0x55, 0x7a, 0x6c, 0x65, 0x74,
139 0x69, 0x20, 0x28, 0x43, 0x6c, 0x61, 0x73, 0x73,
140 0x20, 0x42, 0x29, 0x20, 0x54, 0x61, 0x6e, 0x75,
141 0x73, 0x69, 0x74, 0x76, 0x61, 0x6e, 0x79, 0x6b,
142 0x69, 0x61, 0x64, 0x6f
144 static const CSSM_DATA anchor_60_derIssuer
= { 156, (uint8
*)anchor_60_derIssuer_bytes
};
149 Org : (c) 2005 TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
150 Common Name : TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
152 Not Before : 10:27:17 May 13, 2005
153 Not After : 10:27:17 Mar 22, 2015
155 static const uint8 turk1_derIssuer_bytes
[] = {
156 0x30, 0x81, 0xb7, 0x31, 0x3f, 0x30, 0x3d, 0x06,
157 0x03, 0x55, 0x04, 0x03, 0x0c, 0x36, 0x54, 0xc3,
158 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
159 0x20, 0x45, 0x6c, 0x65, 0x6b, 0x74, 0x72, 0x6f,
160 0x6e, 0x69, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74,
161 0x69, 0x66, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x69,
162 0x7a, 0x6d, 0x65, 0x74, 0x20, 0x53, 0x61, 0xc4,
163 0x9f, 0x6c, 0x61, 0x79, 0xc4, 0xb1, 0x63, 0xc4,
164 0xb1, 0x73, 0xc4, 0xb1, 0x31, 0x0b, 0x30, 0x09,
165 0x06, 0x03, 0x55, 0x04, 0x06, 0x0c, 0x02, 0x54,
166 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
167 0x04, 0x07, 0x0c, 0x06, 0x41, 0x4e, 0x4b, 0x41,
168 0x52, 0x41, 0x31, 0x56, 0x30, 0x54, 0x06, 0x03,
169 0x55, 0x04, 0x0a, 0x0c, 0x4d, 0x28, 0x63, 0x29,
170 0x20, 0x32, 0x30, 0x30, 0x35, 0x20, 0x54, 0xc3,
171 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
172 0x20, 0x42, 0x69, 0x6c, 0x67, 0x69, 0x20, 0xc4,
173 0xb0, 0x6c, 0x65, 0x74, 0x69, 0xc5, 0x9f, 0x69,
174 0x6d, 0x20, 0x76, 0x65, 0x20, 0x42, 0x69, 0x6c,
175 0x69, 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x47, 0xc3,
176 0xbc, 0x76, 0x65, 0x6e, 0x6c, 0x69, 0xc4, 0x9f,
177 0x69, 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74,
178 0x6c, 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5,
181 static const CSSM_DATA turk1_derIssuer
= { 186, (uint8
*)turk1_derIssuer_bytes
};
186 Org : TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Kasım 2005
187 Common Name : TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
189 Not Before : 10:07:57 Nov 7, 2005
190 Not After : 10:07:57 Sep 16, 2015
192 static const uint8 turk2_derIssuer_bytes
[] = {
193 0x30, 0x81, 0xbe, 0x31, 0x3f, 0x30, 0x3d, 0x06,
194 0x03, 0x55, 0x04, 0x03, 0x0c, 0x36, 0x54, 0xc3,
195 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
196 0x20, 0x45, 0x6c, 0x65, 0x6b, 0x74, 0x72, 0x6f,
197 0x6e, 0x69, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74,
198 0x69, 0x66, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x69,
199 0x7a, 0x6d, 0x65, 0x74, 0x20, 0x53, 0x61, 0xc4,
200 0x9f, 0x6c, 0x61, 0x79, 0xc4, 0xb1, 0x63, 0xc4,
201 0xb1, 0x73, 0xc4, 0xb1, 0x31, 0x0b, 0x30, 0x09,
202 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54,
203 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
204 0x04, 0x07, 0x0c, 0x06, 0x41, 0x6e, 0x6b, 0x61,
205 0x72, 0x61, 0x31, 0x5d, 0x30, 0x5b, 0x06, 0x03,
206 0x55, 0x04, 0x0a, 0x0c, 0x54, 0x54, 0xc3, 0x9c,
207 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
208 0x42, 0x69, 0x6c, 0x67, 0x69, 0x20, 0xc4, 0xb0,
209 0x6c, 0x65, 0x74, 0x69, 0xc5, 0x9f, 0x69, 0x6d,
210 0x20, 0x76, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69,
211 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x47, 0xc3, 0xbc,
212 0x76, 0x65, 0x6e, 0x6c, 0x69, 0xc4, 0x9f, 0x69,
213 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74, 0x6c,
214 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e,
215 0x2e, 0x20, 0x28, 0x63, 0x29, 0x20, 0x4b, 0x61,
216 0x73, 0xc4, 0xb1, 0x6d, 0x20, 0x32, 0x30, 0x30,
219 static const CSSM_DATA turk2_derIssuer
= { 193, (uint8
*)turk2_derIssuer_bytes
};
224 Org : TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Aralık 2007
225 Common Name : TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
227 Not Before : 18:37:19 Dec 25, 2007
228 Not After : 18:37:19 Dec 22, 2017
230 static const uint8 turk3_derIssuer_bytes
[] = {
231 0x30, 0x81, 0xbf, 0x31, 0x3f, 0x30, 0x3d, 0x06,
232 0x03, 0x55, 0x04, 0x03, 0x0c, 0x36, 0x54, 0xc3,
233 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
234 0x20, 0x45, 0x6c, 0x65, 0x6b, 0x74, 0x72, 0x6f,
235 0x6e, 0x69, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74,
236 0x69, 0x66, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x69,
237 0x7a, 0x6d, 0x65, 0x74, 0x20, 0x53, 0x61, 0xc4,
238 0x9f, 0x6c, 0x61, 0x79, 0xc4, 0xb1, 0x63, 0xc4,
239 0xb1, 0x73, 0xc4, 0xb1, 0x31, 0x0b, 0x30, 0x09,
240 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54,
241 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
242 0x04, 0x07, 0x0c, 0x06, 0x41, 0x6e, 0x6b, 0x61,
243 0x72, 0x61, 0x31, 0x5e, 0x30, 0x5c, 0x06, 0x03,
244 0x55, 0x04, 0x0a, 0x0c, 0x55, 0x54, 0xc3, 0x9c,
245 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
246 0x42, 0x69, 0x6c, 0x67, 0x69, 0x20, 0xc4, 0xb0,
247 0x6c, 0x65, 0x74, 0x69, 0xc5, 0x9f, 0x69, 0x6d,
248 0x20, 0x76, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69,
249 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x47, 0xc3, 0xbc,
250 0x76, 0x65, 0x6e, 0x6c, 0x69, 0xc4, 0x9f, 0x69,
251 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74, 0x6c,
252 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e,
253 0x2e, 0x20, 0x28, 0x63, 0x29, 0x20, 0x41, 0x72,
254 0x61, 0x6c, 0xc4, 0xb1, 0x6b, 0x20, 0x32, 0x30,
257 static const CSSM_DATA turk3_derIssuer
= { 194, (uint8
*)turk3_derIssuer_bytes
};
260 Cert File Name: globalSignRoot.cer
262 Org : GlobalSign nv-sa
264 Common Name : GlobalSign Root CA
266 static const uint8 globalSignRoot_derIssuer_bytes
[] = {
267 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
268 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31,
269 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a,
270 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
271 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d,
272 0x73, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
273 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, 0x6f,
274 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19,
275 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47,
276 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67,
277 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
280 static const CSSM_DATA globalSignRoot_derIssuer
= { 89, (uint8
*)globalSignRoot_derIssuer_bytes
};
282 /***********************
283 Cert File Name: swisssign.der
287 Common Name : SwissSign CA (RSA IK May 6 1999 18:00:58)
288 Email addrs : ca@SwissSign.com
290 This one has a bogus AuthorityKeyId, with a value of {0x30, 0} inside the octet string.
291 ***********************/
292 static const uint8 swisssign_derIssuer_bytes
[] = {
293 0x30, 0x76, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
294 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x31,
295 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
296 0x13, 0x09, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53,
297 0x69, 0x67, 0x6e, 0x31, 0x32, 0x30, 0x30, 0x06,
298 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, 0x53, 0x77,
299 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20,
300 0x43, 0x41, 0x20, 0x28, 0x52, 0x53, 0x41, 0x20,
301 0x49, 0x4b, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x36,
302 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x31, 0x38,
303 0x3a, 0x30, 0x30, 0x3a, 0x35, 0x38, 0x29, 0x31,
304 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48,
305 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10,
306 0x63, 0x61, 0x40, 0x53, 0x77, 0x69, 0x73, 0x73,
307 0x53, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d
310 static const CSSM_DATA swisssign_derIssuer
= { 120, (uint8
*)swisssign_derIssuer_bytes
};
313 * Simple class to hold arrays of fields.
318 * Create from existing field array obtained from
319 * CSSM_CL_CertGetAllFields(). We'll do the CSSM_CL_FreeFields()
325 CSSM_CL_HANDLE clHand
);
328 * Create empty array of specified size. We don't own the fields
337 * Append a field - no realloc!
339 void appendField(CSSM_FIELD
&field
);
341 /* get specified field */
342 CSSM_FIELD
&fieldAt(uint32 index
);
344 /* get nth occurence of field matching specified OID */
347 unsigned n
, // n == 0 --> first one
348 CSSM_FIELD
*&found
); // RETURNED
351 uint32 mNumFields
; // sizeof of *fields
352 uint32 mMallocdSize
; // if NULL, read-only
353 CSSM_CL_HANDLE mClHand
;
356 FieldArray::FieldArray(
359 CSSM_CL_HANDLE clHand
)
362 mNumFields
= numFields
;
367 FieldArray::FieldArray(
370 unsigned len
= sizeof(CSSM_FIELD
) * size
;
371 mFields
= (CSSM_FIELD_PTR
)malloc(len
);
372 memset(mFields
, 0, len
);
378 FieldArray::~FieldArray()
380 if(mMallocdSize
!= 0) {
382 * Just free the array of fields we mallocd, not the fields
388 /* The CL mallocd these fields, tell it to free the whole thing */
389 CSSM_RETURN crtn
= CSSM_CL_FreeFields(mClHand
,
390 mNumFields
, &mFields
);
392 printError("CSSM_CL_FreeFields", crtn
);
400 void FieldArray::appendField(
403 if(mMallocdSize
== 0) {
404 printf("***Attempt to append to a read-only FieldArray\n");
407 if(mNumFields
>= mMallocdSize
) {
408 printf("***Attempt to append past present size of FieldArray\n");
411 mFields
[mNumFields
] = field
;
415 CSSM_FIELD
&FieldArray::fieldAt(
418 if(index
>= mNumFields
) {
419 printf("***Attempt to access past present size of FieldArray\n");
422 return mFields
[index
];
425 /* get nth occurence of field matching specified OID */
426 /* returns nonzero on error */
427 int FieldArray::fieldForOid(
429 unsigned n
, // n == 0 --> first one
430 CSSM_FIELD
*&found
) // RETURNED
432 unsigned foundDex
= 0;
433 for(unsigned dex
=0; dex
<mNumFields
; dex
++) {
434 CSSM_FIELD
&field
= mFields
[dex
];
435 if(appCompareCssmData(&field
.FieldOid
, &oid
)) {
443 printf("FieldArray::fieldForOid field not found\n");
448 * How many items in a NULL-terminated array of pointers?
450 static unsigned nssArraySize(
462 static void doPrintCert(
463 const CSSM_DATA
&cert
)
465 printCert(cert
.Data
, cert
.Length
, CSSM_TRUE
);
469 * The extensions whose presence causes us to skip the "compare
470 * encoded and original TBS" test.
472 #define USE_SKIPPED_EXTENS 1
473 #if USE_SKIPPED_EXTENS
474 static const CSSM_OID
*skippedExtens
[] = { // %%% FIXME: this is a workaround for <rdar://8265523>; shouldn't need to skip!
475 &CSSMOID_PolicyMappings
,
476 &CSSMOID_PolicyConstraints
478 #define NUM_SKIPPED_EXTENS \
479 (sizeof(skippedExtens) / sizeof(skippedExtens[0]))
480 #endif /* USE_SKIPPED_EXTENS */
482 static const CSSM_DATA
*skippedCerts
[] = {
483 &anchor_46_derIssuer
,
484 &anchor_53_derIssuer
,
485 &anchor_60_derIssuer
,
489 &globalSignRoot_derIssuer
,
492 #define NUM_SKIPPED_CERTS (sizeof(skippedCerts) / sizeof(skippedCerts[0]))
494 static bool skipThisCert(
495 const NSS_TBSCertificate
&tbs
)
497 /* search by extension - currently unused */
499 #if USE_SKIPPED_EXTENS
500 unsigned numExtens
= nssArraySize((const void **)tbs
.extensions
);
501 /* skip this section if that's empty - compiler warning causes failure */
502 for(dex
=0; dex
<numExtens
; dex
++) {
503 NSS_CertExtension
*exten
= tbs
.extensions
[dex
];
504 CSSM_OID
*oid
= &exten
->extnId
;
505 for(unsigned skipDex
=0; skipDex
<NUM_SKIPPED_EXTENS
; skipDex
++) {
506 if(appCompareCssmData(skippedExtens
[skipDex
], oid
)) {
511 #endif /* USE_SKIPPED_EXTENS */
513 /* search by specific issuer */
514 for(dex
=0; dex
<NUM_SKIPPED_CERTS
; dex
++) {
515 if(appCompareCssmData(skippedCerts
[dex
], &tbs
.derIssuer
)) {
523 * Given a field OID, figure out what WE think this field is.
526 /* the field types we grok */
528 FT_Unknown
, // probably means we're out of sync with the CL
529 FT_Normal
, // standard component of TBS
530 FT_ReadOnly
, // Read only, don't use to create template
531 FT_NotTBS
, // part of top-level cert, don't use to create TBS
532 FT_ExtenParsed
, // extension the CL SHOULD HAVE parsed
533 FT_ExtenUnknown
// extension the CL should NOT have parsed
536 /* map OID --> FieldType */
543 * The CL-specific mapping table.
544 * This has to change whenever the CL is modified to add or delete
545 * an extension or field!
546 * For newbies, a tip: this basically has to stay in sync with the
547 * fieldFuncTable array in Security/AppleX509CL/CertFields.cpp.
549 FieldOidType knownFields
[] = {
550 { &CSSMOID_X509V1Version
, FT_Normal
},
551 { &CSSMOID_X509V1SerialNumber
, FT_Normal
},
552 { &CSSMOID_X509V1IssuerNameCStruct
, FT_Normal
},
553 { &CSSMOID_X509V1SubjectNameCStruct
, FT_Normal
},
554 { &CSSMOID_X509V1SignatureAlgorithmTBS
, FT_Normal
},
555 { &CSSMOID_X509V1SignatureAlgorithm
, FT_NotTBS
},
556 { &CSSMOID_X509V1ValidityNotBefore
, FT_Normal
},
557 { &CSSMOID_X509V1ValidityNotAfter
, FT_Normal
},
558 { &CSSMOID_X509V1CertificateIssuerUniqueId
, FT_Normal
},
559 { &CSSMOID_X509V1CertificateSubjectUniqueId
, FT_Normal
},
560 /* only one of these two can be set - use the SubjectPublicKeyInfo
562 { &CSSMOID_X509V1SubjectPublicKeyCStruct
, FT_Normal
},
563 { &CSSMOID_CSSMKeyStruct
, FT_ReadOnly
},
564 { &CSSMOID_X509V1Signature
, FT_NotTBS
},
565 { &CSSMOID_X509V1IssuerName
, FT_ReadOnly
}, // DER encoded
566 { &CSSMOID_X509V1SubjectName
, FT_ReadOnly
}, // DER encoded
567 { &CSSMOID_X509V1IssuerNameStd
, FT_ReadOnly
}, // DER encoded
568 { &CSSMOID_X509V1SubjectNameStd
,FT_ReadOnly
}, // DER encoded
571 { &CSSMOID_KeyUsage
, FT_ExtenParsed
},
572 { &CSSMOID_BasicConstraints
, FT_ExtenParsed
},
573 { &CSSMOID_ExtendedKeyUsage
, FT_ExtenParsed
} ,
574 { &CSSMOID_SubjectKeyIdentifier
, FT_ExtenParsed
} ,
575 { &CSSMOID_AuthorityKeyIdentifier
, FT_ExtenParsed
} ,
576 { &CSSMOID_SubjectAltName
, FT_ExtenParsed
} ,
577 { &CSSMOID_IssuerAltName
, FT_ExtenParsed
} ,
578 { &CSSMOID_CertificatePolicies
, FT_ExtenParsed
} ,
579 { &CSSMOID_NetscapeCertType
, FT_ExtenParsed
} ,
580 { &CSSMOID_CrlDistributionPoints
, FT_ExtenParsed
},
581 { &CSSMOID_AuthorityInfoAccess
, FT_ExtenParsed
},
582 { &CSSMOID_SubjectInfoAccess
, FT_ExtenParsed
},
583 { &CSSMOID_X509V3CertificateExtensionCStruct
, FT_ExtenUnknown
},
584 { &CSSMOID_QC_Statements
, FT_ExtenParsed
},
585 { &CSSMOID_NameConstraints
, FT_ExtenParsed
},
586 { &CSSMOID_PolicyMappings
, FT_ExtenParsed
},
587 { &CSSMOID_PolicyConstraints
, FT_ExtenParsed
},
588 // { &CSSMOID_InhibitAnyPolicy, FT_ExtenParsed } //%%% FIXME: CSSMOID_InhibitAnyPolicy not exported!?
590 #define NUM_KNOWN_FIELDS (sizeof(knownFields) / sizeof(knownFields[0]))
592 static FieldType
typeForOid(
595 for(unsigned dex
=0; dex
<NUM_KNOWN_FIELDS
; dex
++) {
596 FieldOidType
&ft
= knownFields
[dex
];
597 if(appCompareCssmData(&oid
, ft
.oid
)) {
605 static const char *fieldTypeStr(
609 case FT_Unknown
: return "FT_Unknown";
610 case FT_Normal
: return "FT_Normal";
611 case FT_ReadOnly
: return "FT_ReadOnly";
612 case FT_NotTBS
: return "FT_NotTBS";
613 case FT_ExtenParsed
: return "FT_ExtenParsed";
614 case FT_ExtenUnknown
: return "FT_ExtenUnknown";
616 printf("***BRRZAP!\n");
621 static const uint8 emptyAuthKeyId
[2] = {0x30, 0};
624 * Extensions come in two flavors - parsed and not. However the
625 * CL will give us an unparsed version for extensions it normally
626 * understands but failed to decode. Detect that, and basic
627 * extension formatting screwups, here.
629 static int vfyExtens(
630 FieldArray
&extenFields
,
631 const CSSM_DATA
&cert
, // for error display only
634 for(unsigned dex
=0; dex
<extenFields
.mNumFields
; dex
++) {
635 CSSM_FIELD
&extenField
= extenFields
.fieldAt(dex
);
636 FieldType type
= typeForOid(extenField
.FieldOid
);
637 FieldType expectType
;
639 /* first verify well-formed extension field */
640 CSSM_DATA
&fieldValue
= extenField
.FieldValue
;
641 CSSM_X509_EXTENSION
*exten
= (CSSM_X509_EXTENSION
*)fieldValue
.Data
;
642 if((exten
== NULL
) ||
643 (fieldValue
.Length
!= sizeof(CSSM_X509_EXTENSION
))) {
645 printf("***Malformed CSSM_X509_EXTENSION\n");
646 if(testError(quiet
)) {
649 /* well let's limp along */
653 /* currently (since Radar 3593624), these are both always valid */
654 if((exten
->BERvalue
.Data
== NULL
) ||
655 (exten
->value
.parsedValue
== NULL
)) { /* actually, one of three variants */
656 printf("***Malformed CSSM_X509_EXTENSION (1)\n");
660 switch(exten
->format
) {
661 case CSSM_X509_DATAFORMAT_ENCODED
:
662 if(type
!= FT_ExtenUnknown
) {
664 printf("***Entension format ENCODED, expected PARSED\n");
665 if(testError(quiet
)) {
671 * Now make sure that the underlying extension ID isn't
672 * one that the CL was SUPPOSED to parse
674 // %%% FIXME: need to investigate why these are not fully parsed: <rdar://8265523>
675 if(appCompareCssmData(&exten
->extnId
, &CSSMOID_PolicyConstraints
)) {
676 printf("...skipping policyConstraints extension per <rdar://8265523> (fix me!)\n");
679 if(appCompareCssmData(&exten
->extnId
, &CSSMOID_PolicyMappings
)) {
680 printf("...skipping policyMappings extension per <rdar://8265523> (fix me!)\n");
684 expectType
= typeForOid(exten
->extnId
);
685 if(expectType
!= FT_Unknown
) {
687 * Swisscom root has an authorityKeyId extension with an illegal value,
688 * data inside the octet string is <30 00>, no context-specific wrapper
690 * Instead of a hopeless complaint about that cert, let's just tolerate it
693 if(appCompareCssmData(&exten
->extnId
, &CSSMOID_AuthorityKeyIdentifier
) &&
694 (exten
->BERvalue
.Length
== 2) &&
695 !memcmp(emptyAuthKeyId
, exten
->BERvalue
.Data
, 2)) {
696 printf("...skipping bogus swisssign AuthorityKeyId\n");
700 printf("***underlying exten type %s, expect Unknown\n",
701 fieldTypeStr(expectType
));
702 if(testError(quiet
)) {
708 case CSSM_X509_DATAFORMAT_PARSED
:
709 if(type
!= FT_ExtenParsed
) {
711 printf("***Entension format PARSED, expected ENCODED\n");
712 if(testError(quiet
)) {
716 if(exten
->value
.parsedValue
== NULL
) {
718 printf("***Parsed extension with NULL parsedValue\n");
719 if(testError(quiet
)) {
727 printf("***Unknown Entension format %u\n",
729 if(testError(quiet
)) {
734 } /* switch(exten.format) */
740 * Here's the hard part.
741 * Given a raw cert and its components in two FieldArrays, crate a TBS
742 * cert from scratch from those fields and ensure that the result
743 * is the same as the raw TBS field in the original cert.
746 CSSM_CL_HANDLE clHand
,
747 const CSSM_DATA
&rawCert
,
748 FieldArray
&allFields
, // on entry, standard fields
749 FieldArray
&extenFields
, // extensions only
752 CSSM_BOOL writeBlobs
)
755 * First do raw BER-decode in two ways - one to get the
756 * extensions as they actuallly appear in the cert, and one
757 * to get the raw undecoded TBS.
759 SecAsn1CoderRef coder
;
760 OSStatus ortn
= SecAsn1CoderCreate(&coder
);
762 cssmPerror("SecAsn1CoderCreate", ortn
);
763 return testError(quiet
);
766 NSS_SignedCertOrCRL signedCert
; // with TBS as ASN_ANY
767 memset(&signedCert
, 0, sizeof(signedCert
));
768 if(SecAsn1DecodeData(coder
, &rawCert
, kSecAsn1SignedCertOrCRLTemplate
,
770 doPrintCert(rawCert
);
771 printf("***Error decoding cert to kSecAsn1SignedCertOrCRL\n");
772 return testError(quiet
);
775 NSS_Certificate fullCert
; // fully decoded
776 memset(&fullCert
, 0, sizeof(fullCert
));
777 if(SecAsn1DecodeData(coder
, &rawCert
, kSecAsn1SignedCertTemplate
,
779 doPrintCert(rawCert
);
780 printf("***Error decoding cert to kSecAsn1Certificate\n");
781 return testError(quiet
);
784 NSS_TBSCertificate
&tbs
= fullCert
.tbs
;
785 unsigned numExtens
= nssArraySize((const void **)tbs
.extensions
);
786 if(numExtens
!= extenFields
.mNumFields
) {
787 /* The CL told us the wrong number of extensions */
788 doPrintCert(rawCert
);
789 printf("***NSS says %u extens, CL says %u\n", numExtens
,
790 (unsigned)extenFields
.mNumFields
);
791 return testError(quiet
);
794 if(skipThisCert(tbs
)) {
796 printf(" ...skipping TBS blob check\n");
798 SecAsn1CoderRelease(coder
);
803 * The CL returns extension fields in an order which differs from
804 * the order of the extensions in the actual cert (because it
805 * does a table-based lookup, field by field, when doing a
806 * CSSM_CL_CertGetAllFields()). We have to add the extensions
807 * from extenFields to allFields in the order they appear in
808 * OUR decoded fullCert.
810 unsigned numUnknowns
= 0;
811 for(unsigned dex
=0; dex
<numExtens
; dex
++) {
812 NSS_CertExtension
*exten
= tbs
.extensions
[dex
];
813 CSSM_OID
&oid
= exten
->extnId
;
814 FieldType type
= typeForOid(oid
);
815 CSSM_FIELD
*found
= NULL
;
820 * look for this exact extension
821 * NOTE we're assuming that only one copy of
822 * each specific parsed extension exists. The
823 * 509 spec does't specifically require this but
824 * I've never seen a case of multiple extensions
825 * of the same type in one cert.
827 rtn
= extenFields
.fieldForOid(oid
, 0, found
);
830 /* search for nth unparsed exten field */
831 rtn
= extenFields
.fieldForOid(
832 CSSMOID_X509V3CertificateExtensionCStruct
,
837 /* caller was already supposed to check this */
838 doPrintCert(rawCert
);
839 printf("***HEY! buildTBS was given a bogus extension!\n");
843 doPrintCert(rawCert
);
844 printf("***buildTBS could not find extension in CL's fields\n");
845 return testError(quiet
);
848 allFields
.appendField(*found
);
849 } /* processing extensions */
852 * OK, the field array in allFields is ready to go down to
856 CSSM_DATA clTbs
= {0, NULL
};
857 crtn
= CSSM_CL_CertCreateTemplate(clHand
,
858 allFields
.mNumFields
,
862 doPrintCert(rawCert
);
863 printError("CSSM_CL_CertCreateTemplate", crtn
);
864 return testError(quiet
);
868 * The moment of truth. Is that template identical to the
869 * raw undecoded TBS blob we got by decoding a NSS_SignedCertOrCRL?
872 if(!appCompareCssmData(&clTbs
, &signedCert
.tbsBlob
)) {
873 doPrintCert(rawCert
);
874 printf("***Encoded TBS does not match decoded TBS.\n");
876 writeFile(ENC_TBS_BLOB
, clTbs
.Data
, clTbs
.Length
);
877 writeFile(DEC_TBS_BLOB
, signedCert
.tbsBlob
.Data
,
878 signedCert
.tbsBlob
.Length
);
879 printf("...wrote TBS blobs to %s and %s\n",
880 ENC_TBS_BLOB
, DEC_TBS_BLOB
);
882 ourRtn
= testError(quiet
);
884 CSSM_FREE(clTbs
.Data
);
885 SecAsn1CoderRelease(coder
);
889 /* verify root with itself using TP */
890 static int verifyRoot(
891 CSSM_TP_HANDLE tpHand
,
892 CSSM_CL_HANDLE clHand
,
893 CSSM_CSP_HANDLE cspHand
,
894 const CSSM_DATA
&cert
,
895 CSSM_BOOL allowExpired
,
896 CSSM_BOOL useTrustSettings
,
900 blobs
.addBlob(cert
, CSSM_TRUE
);
903 const char *certStatus
;
904 if(useTrustSettings
) {
906 * CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
907 * CSSM_CERT_STATUS_IS_ROOT
908 * CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
909 * CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
911 certStatus
= "0:0x314";
915 * CSSM_CERT_STATUS_IS_IN_INPUT_CERTS (new since radar 3855635 was fixed)
916 * CSSM_CERT_STATUS_IS_IN_ANCHORS
917 * CSSM_CERT_STATUS_IS_ROOT
919 certStatus
= "0:0x1C";
922 /* try one with allowExpiredRoot false, then true on error and if so
923 * enabled to make sure we know what's going wrong */
924 CSSM_BOOL expireEnable
= CSSM_FALSE
;
925 for(int dex
=0; dex
<2; dex
++) {
926 i
= certVerifySimple(tpHand
, clHand
, cspHand
,
929 CSSM_FALSE
, // useSystemAnchors
930 CSSM_TRUE
, // leaf is CA
934 CSSM_FALSE
, // SSL client
935 NULL
, // sender email
937 NULL
, // expected error str
938 0, NULL
, // per-cert errors
939 1, &certStatus
, // per-cert status
942 CSSM_FALSE
); // verbose
946 printf("...warning: expired root detected. Be aware.\n");
951 /* no second chance */
954 expireEnable
= CSSM_TRUE
;
955 if(useTrustSettings
) {
956 /* now expect EXPIRED, IS_ROOT, IS_IN_INPUT_CERTS, TRUST_SETTINGS_FOUND_SYSTEM,
957 * CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST */
958 certStatus
= "0:0x315";
961 /* now expect EXPIRED, IS_ROOT, IS_IN_ANCHORS, IS_IN_INPUT_CERTS */
962 certStatus
= "0:0x1d";
970 CSSM_CL_HANDLE clHand
,
971 CSSM_TP_HANDLE tpHand
,
972 CSSM_CSP_HANDLE cspHand
,
973 const CSSM_DATA
&cert
,
974 CSSM_BOOL allowExpired
,
977 CSSM_BOOL writeBlobs
,
978 CSSM_BOOL useTrustSettings
)
980 /* first see if this anchor self-verifies. */
981 if(verifyRoot(tpHand
, clHand
, cspHand
, cert
, allowExpired
,
982 useTrustSettings
, quiet
)) {
984 printf("***This anchor does not self-verify!\n");
985 return testError(quiet
);
988 /* have the CL parse it to the best of its ability */
989 CSSM_FIELD_PTR certFields
;
991 CSSM_RETURN crtn
= CSSM_CL_CertGetAllFields(clHand
, &cert
, &numFields
,
994 printError("CSSM_CL_CertGetAllFields", crtn
);
996 printf("***The CL can not parse this anchor!\n");
997 return testError(quiet
);
1000 /* save, this object does the free fields when it goes out of scope */
1001 FieldArray
parsed(certFields
, numFields
, clHand
);
1004 * We're going to build a TBSCert from these received fields.
1005 * Extensions need to be processed specially because they
1006 * come back from the CL ordered differently than they appear
1009 * First make two buckets for making copies of incoming fields.
1011 FieldArray
forCreate(numFields
); // for creating template
1012 FieldArray
extenFields(numFields
);
1014 for(unsigned dex
=0; dex
<numFields
; dex
++) {
1015 CSSM_FIELD
&parsedField
= parsed
.fieldAt(dex
);
1016 FieldType type
= typeForOid(parsedField
.FieldOid
);
1019 forCreate
.appendField(parsedField
);
1025 case FT_ExtenParsed
:
1026 case FT_ExtenUnknown
:
1027 /* extensions, save and process later */
1028 extenFields
.appendField(parsedField
);
1032 printf("***This anchor contains an unknown field!\n");
1033 if(testError(quiet
)) {
1036 /* well let's limp along */
1037 forCreate
.appendField(parsedField
);
1042 /* basic extension verification */
1043 if(vfyExtens(extenFields
, cert
, quiet
)) {
1046 return buildTbs(clHand
, cert
, forCreate
, extenFields
, quiet
,
1047 verbose
, writeBlobs
);
1050 int main(int argc
, char **argv
)
1052 CSSM_BOOL quiet
= CSSM_FALSE
;
1053 CSSM_BOOL verbose
= CSSM_FALSE
;
1054 CSSM_BOOL writeBlobs
= CSSM_FALSE
;
1055 CSSM_BOOL allowExpired
= CSSM_FALSE
;
1056 CSSM_BOOL useTrustSettings
= CSSM_FALSE
;
1058 for(int arg
=1; arg
<argc
; arg
++) {
1059 switch(argv
[arg
][0]) {
1064 verbose
= CSSM_TRUE
;
1067 writeBlobs
= CSSM_TRUE
;
1070 useTrustSettings
= CSSM_TRUE
;
1073 allowExpired
= CSSM_TRUE
;
1080 printf("Starting anchorTest; args: ");
1081 for(int i
=1; i
<argc
; i
++) {
1082 printf("%s ", argv
[i
]);
1086 /* get system anchors only; convert to CSSM */
1087 CFArrayRef cfAnchors
;
1090 unsigned numAnchors
;
1091 ortn
= getSystemAnchors(&cfAnchors
, &anchors
, &numAnchors
);
1095 if(numAnchors
< 50) {
1096 printf("***Hey! I can only find %u anchors; there should be way more than that.\n",
1101 CSSM_CL_HANDLE clHand
= clStartup();
1102 CSSM_TP_HANDLE tpHand
= tpStartup();
1103 CSSM_CSP_HANDLE cspHand
= cspStartup();
1104 if((clHand
== 0) || (tpHand
== 0) || (cspHand
== 0)) {
1109 for(unsigned dex
=0; dex
<numAnchors
; dex
++) {
1111 printf("...anchor %u\n", dex
);
1113 rtn
= doTest(clHand
, tpHand
, cspHand
, anchors
[dex
], allowExpired
,
1114 quiet
, verbose
, writeBlobs
, useTrustSettings
);
1121 printf("...%s success.\n", argv
[0]);