1/*
2 * anchorTest.cpp - test cert encode/decode using known good system
3 *                  anchors
4 */
5#include <stdio.h>
6#include <string.h>
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>
24
25#define ENC_TBS_BLOB	"encodedTbs.der"
26#define DEC_TBS_BLOB	"decodedTbs.der"
27
28static void usage(char **argv)
29{
30	printf("Usage: %s [options]\n", argv[0]);
31	printf("Options:\n");
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");
37	exit(1);
38}
39
40/*
41 * Certs for which we skip the "compare TBS blob" test, enumerated by
42 * DER-encoded issuer name.
43 *
44 * Get this formatted data from the extractCertFields program.
45 *
46 * All of these have non-standard KeyUsage encoding (legal but it's
47 * not the same as ours or everyone else's).
48 */
49/*
50   Country         : HU
51   Locality        : Budapest
52   Org             : NetLock Halozatbiztonsagi Kft.
53   OrgUnit         : Tanusitvanykiadok
54   Common Name     : NetLock Expressz (Class C) Tanusitvanykiado
55 */
56static 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
77};
78static const CSSM_DATA anchor_46_derIssuer = { 158, (uint8 *)anchor_46_derIssuer_bytes };
79
80/*
81   Country         : HU
82   State           : Hungary
83   Locality        : Budapest
84   Org             : NetLock Halozatbiztonsagi Kft.
85   OrgUnit         : Tanusitvanykiadok
86   Common Name     : NetLock Kozjegyzoi (Class A) Tanusitvanykiado
87*/
88static 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,
111   0x64,  0x6f
112};
113static const CSSM_DATA anchor_53_derIssuer = { 178, (uint8 *)anchor_53_derIssuer_bytes };
114
115/*
116   Country         : HU
117   Locality        : Budapest
118   Org             : NetLock Halozatbiztonsagi Kft.
119   OrgUnit         : Tanusitvanykiadok
120   Common Name     : NetLock Uzleti (Class B) Tanusitvanykiado
121*/
122static 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
143};
144static const CSSM_DATA anchor_60_derIssuer = { 156, (uint8 *)anchor_60_derIssuer_bytes };
145
146/*
147 Country         : TR
148 Locality        : Ankara
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ı
151 Serial Number   : 01
152 Not Before      : 10:27:17 May 13, 2005
153 Not After       : 10:27:17 Mar 22, 2015
154*/
155static 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,
179	0x9e,  0x2e
180};
181static const CSSM_DATA turk1_derIssuer = { 186, (uint8 *)turk1_derIssuer_bytes };
182
183/*
184 Country         : TR
185 Locality        : Ankara
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ı
188 Serial Number   : 01
189 Not Before      : 10:07:57 Nov 7, 2005
190 Not After       : 10:07:57 Sep 16, 2015
191*/
192static 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,
217	0x35
218};
219static const CSSM_DATA turk2_derIssuer = { 193, (uint8 *)turk2_derIssuer_bytes };
220
221/*
222 Country         : TR
223 Locality        : Ankara
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ı
226 Serial Number   : 01
227 Not Before      : 18:37:19 Dec 25, 2007
228 Not After       : 18:37:19 Dec 22, 2017
229*/
230static 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,
255	0x30,  0x37
256};
257static const CSSM_DATA turk3_derIssuer = { 194, (uint8 *)turk3_derIssuer_bytes };
258
259/*
260Cert File Name: globalSignRoot.cer
261   Country         : BE
262   Org             : GlobalSign nv-sa
263   OrgUnit         : Root CA
264   Common Name     : GlobalSign Root CA
265*/
266static 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,
278   0x41
279};
280static const CSSM_DATA globalSignRoot_derIssuer = { 89, (uint8 *)globalSignRoot_derIssuer_bytes };
281
282/***********************
283Cert File Name: swisssign.der
284Subject Name       :
285   Country         : CH
286   Org             : SwissSign
287   Common Name     : SwissSign CA (RSA IK May 6 1999 18:00:58)
288   Email addrs     : ca@SwissSign.com
289
290 This one has a bogus AuthorityKeyId, with a value of {0x30, 0} inside the octet string.
291 ***********************/
292static 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
308
309};
310static const CSSM_DATA swisssign_derIssuer = { 120, (uint8 *)swisssign_derIssuer_bytes };
311
312/*
313 * Simple class to hold arrays of fields.
314 */
315class FieldArray {
316public:
317	/*
318	 * Create from existing field array obtained from
319	 * CSSM_CL_CertGetAllFields(). We'll do the CSSM_CL_FreeFields()
320	 * in our destructor.
321	 */
322	FieldArray(
323		CSSM_FIELD 		*fields,
324		uint32 			numFields,
325		CSSM_CL_HANDLE 	clHand);
326
327	/*
328	 * Create empty array of specified size. We don't own the fields
329	 * themselves.
330	 */
331	FieldArray(
332		uint32 			size);
333
334	~FieldArray();
335
336	/*
337	 * Append a field - no realloc!
338	 */
339	void appendField(CSSM_FIELD &field);
340
341	/* get specified field */
342	CSSM_FIELD &fieldAt(uint32 index);
343
344	/* get nth occurence of field matching specified OID */
345	int  fieldForOid(
346		const CSSM_OID	&oid,
347		unsigned		n,			// n == 0 --> first one
348		CSSM_FIELD		*&found);	// RETURNED
349
350	CSSM_FIELD	*mFields;
351	uint32		mNumFields;		// sizeof of *fields
352	uint32		mMallocdSize;	// if NULL, read-only
353	CSSM_CL_HANDLE	mClHand;
354};
355
356FieldArray::FieldArray(
357	CSSM_FIELD *fields,
358	uint32 numFields,
359	CSSM_CL_HANDLE clHand)
360{
361	mFields = fields;
362	mNumFields = numFields;
363	mMallocdSize = 0;
364	mClHand = clHand;
365}
366
367FieldArray::FieldArray(
368	uint32 size)
369{
370	unsigned len = sizeof(CSSM_FIELD) * size;
371	mFields = (CSSM_FIELD_PTR)malloc(len);
372	memset(mFields, 0, len);
373	mNumFields = 0;
374	mMallocdSize = size;
375	mClHand = 0;
376}
377
378FieldArray::~FieldArray()
379{
380	if(mMallocdSize != 0) {
381		/*
382		 * Just free the array of fields we mallocd, not the fields
383		 * themselves
384		 */
385		free(mFields);
386	}
387	else {
388		/* The CL mallocd these fields, tell it to free the whole thing */
389		CSSM_RETURN crtn = CSSM_CL_FreeFields(mClHand,
390			mNumFields, &mFields);
391		if(crtn) {
392			printError("CSSM_CL_FreeFields", crtn);
393		}
394	}
395	mFields = NULL;
396	mNumFields = 0;
397	mMallocdSize = 0;
398}
399
400void FieldArray::appendField(
401	CSSM_FIELD &field)
402{
403	if(mMallocdSize == 0) {
404		printf("***Attempt to append to a read-only FieldArray\n");
405		exit(1);
406	}
407	if(mNumFields >= mMallocdSize) {
408		printf("***Attempt to append past present size of FieldArray\n");
409		exit(1);
410	}
411	mFields[mNumFields] = field;
412	mNumFields++;
413}
414
415CSSM_FIELD &FieldArray::fieldAt(
416	uint32 index)
417{
418	if(index >= mNumFields) {
419		printf("***Attempt to access past present size of FieldArray\n");
420		exit(1);
421	}
422	return mFields[index];
423}
424
425/* get nth occurence of field matching specified OID */
426/* returns nonzero on error */
427int FieldArray::fieldForOid(
428	const CSSM_OID	&oid,
429	unsigned		n,			// n == 0 --> first one
430	CSSM_FIELD		*&found)	// RETURNED
431{
432	unsigned foundDex = 0;
433	for(unsigned dex=0; dex<mNumFields; dex++) {
434		CSSM_FIELD &field = mFields[dex];
435		if(appCompareCssmData(&field.FieldOid, &oid)) {
436			if(foundDex == n) {
437				found = &field;
438				return 0;
439			}
440			foundDex++;
441		}
442	}
443	printf("FieldArray::fieldForOid field not found\n");
444	return 1;
445}
446
447/*
448 * How many items in a NULL-terminated array of pointers?
449 */
450static unsigned nssArraySize(
451	const void **array)
452{
453    unsigned count = 0;
454    if (array) {
455		while (*array++) {
456			count++;
457		}
458    }
459    return count;
460}
461
462static void doPrintCert(
463	const CSSM_DATA &cert)
464{
465	printCert(cert.Data, cert.Length, CSSM_TRUE);
466}
467
468/*
469 * The extensions whose presence causes us to skip the "compare
470 * encoded and original TBS" test.
471 */
472#define USE_SKIPPED_EXTENS		1
473#if		USE_SKIPPED_EXTENS
474static const CSSM_OID *skippedExtens[] = {	// %%% FIXME: this is a workaround for <rdar://8265523>; shouldn't need to skip!
475	&CSSMOID_PolicyMappings,
476	&CSSMOID_PolicyConstraints
477};
478#define NUM_SKIPPED_EXTENS	\
479	(sizeof(skippedExtens) / sizeof(skippedExtens[0]))
480#endif	/* USE_SKIPPED_EXTENS */
481
482static const CSSM_DATA *skippedCerts[] = {
483	&anchor_46_derIssuer,
484	&anchor_53_derIssuer,
485	&anchor_60_derIssuer,
486	&turk1_derIssuer,
487	&turk2_derIssuer,
488	&turk3_derIssuer,
489	&globalSignRoot_derIssuer,
490	&swisssign_derIssuer
491};
492#define NUM_SKIPPED_CERTS	(sizeof(skippedCerts) / sizeof(skippedCerts[0]))
493
494static bool skipThisCert(
495	const NSS_TBSCertificate &tbs)
496{
497	/* search by extension - currently unused */
498	unsigned dex;
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)) {
507				return true;
508			}
509		}
510	}
511	#endif	/* USE_SKIPPED_EXTENS */
512
513	/* search by specific issuer */
514	for(dex=0; dex<NUM_SKIPPED_CERTS; dex++) {
515		if(appCompareCssmData(skippedCerts[dex], &tbs.derIssuer)) {
516			return true;
517		}
518	}
519	return false;
520}
521
522/*
523 * Given a field OID, figure out what WE think this field is.
524 */
525
526/* the field types we grok */
527typedef enum {
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
534} FieldType;
535
536/* map OID --> FieldType */
537typedef struct {
538	const CSSM_OID	*oid;
539	FieldType		type;
540} FieldOidType;
541
542/*
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.
548 */
549FieldOidType 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
561	 * version */
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
569
570	/* Extensions */
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!?
589};
590#define NUM_KNOWN_FIELDS (sizeof(knownFields) / sizeof(knownFields[0]))
591
592static FieldType typeForOid(
593	const CSSM_OID &oid)
594{
595	for(unsigned dex=0; dex<NUM_KNOWN_FIELDS; dex++) {
596		FieldOidType &ft = knownFields[dex];
597		if(appCompareCssmData(&oid, ft.oid)) {
598			return ft.type;
599		}
600	}
601	/* not found */
602	return FT_Unknown;
603}
604
605static const char *fieldTypeStr(
606	FieldType type)
607{
608	switch(type) {
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";
615		default:
616			printf("***BRRZAP!\n");
617			exit(1);
618	}
619}
620
621static const uint8 emptyAuthKeyId[2] = {0x30, 0};
622
623/*
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.
628 */
629static int vfyExtens(
630	FieldArray &extenFields,
631	const CSSM_DATA &cert,		// for error display only
632	CSSM_BOOL quiet)
633{
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;
638
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))) {
644			doPrintCert(cert);
645			printf("***Malformed CSSM_X509_EXTENSION\n");
646			if(testError(quiet)) {
647				return 1;
648			}
649			/* well let's limp along */
650			continue;
651		}
652
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");
657			return 1;
658		}
659
660		switch(exten->format) {
661			case CSSM_X509_DATAFORMAT_ENCODED:
662				if(type != FT_ExtenUnknown) {
663					doPrintCert(cert);
664					printf("***Entension format ENCODED, expected PARSED\n");
665					if(testError(quiet)) {
666						return 1;
667					}
668				}
669
670				/*
671				 * Now make sure that the underlying extension ID isn't
672				 * one that the CL was SUPPOSED to parse
673				 */
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");
677					break;
678				}
679				if(appCompareCssmData(&exten->extnId, &CSSMOID_PolicyMappings)) {
680					printf("...skipping policyMappings extension per <rdar://8265523> (fix me!)\n");
681					break;
682				}
683
684				expectType = typeForOid(exten->extnId);
685				if(expectType != FT_Unknown) {
686					/*
687					 * Swisscom root has an authorityKeyId extension with an illegal value,
688					 * data inside the octet string is <30 00>, no context-specific wrapper
689					 * or tag.
690					 * Instead of a hopeless complaint about that cert, let's just tolerate it
691					 * like this...
692					 */
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");
697						break;
698					}
699					doPrintCert(cert);
700					printf("***underlying exten type %s, expect Unknown\n",
701						fieldTypeStr(expectType));
702					if(testError(quiet)) {
703						return 1;
704					}
705				}
706				break;
707
708			case CSSM_X509_DATAFORMAT_PARSED:
709				if(type != FT_ExtenParsed) {
710					doPrintCert(cert);
711					printf("***Entension format PARSED, expected ENCODED\n");
712					if(testError(quiet)) {
713						return 1;
714					}
715				}
716				if(exten->value.parsedValue == NULL) {
717					doPrintCert(cert);
718					printf("***Parsed extension with NULL parsedValue\n");
719					if(testError(quiet)) {
720						return 1;
721					}
722				}
723				break;
724
725			default:
726				doPrintCert(cert);
727				printf("***Unknown Entension format %u\n",
728					exten->format);
729				if(testError(quiet)) {
730					return 1;
731				}
732				break;
733
734		}	/* switch(exten.format) */
735	}
736	return 0;
737}
738
739/*
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.
744 */
745static int buildTbs(
746	CSSM_CL_HANDLE	clHand,
747	const CSSM_DATA	&rawCert,
748	FieldArray		&allFields,		// on entry, standard fields
749	FieldArray		&extenFields,	// extensions only
750	CSSM_BOOL		quiet,
751	CSSM_BOOL		verbose,
752	CSSM_BOOL		writeBlobs)
753{
754	/*
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.
758	 */
759	SecAsn1CoderRef coder;
760	OSStatus ortn = SecAsn1CoderCreate(&coder);
761	if(ortn) {
762		cssmPerror("SecAsn1CoderCreate", ortn);
763		return testError(quiet);
764	}
765
766	NSS_SignedCertOrCRL signedCert;	// with TBS as ASN_ANY
767	memset(&signedCert, 0, sizeof(signedCert));
768	if(SecAsn1DecodeData(coder, &rawCert, kSecAsn1SignedCertOrCRLTemplate,
769			&signedCert)) {
770		doPrintCert(rawCert);
771		printf("***Error decoding cert to kSecAsn1SignedCertOrCRL\n");
772		return testError(quiet);
773	}
774
775	NSS_Certificate fullCert;		// fully decoded
776	memset(&fullCert, 0, sizeof(fullCert));
777	if(SecAsn1DecodeData(coder, &rawCert, kSecAsn1SignedCertTemplate,
778			&fullCert)) {
779		doPrintCert(rawCert);
780		printf("***Error decoding cert to kSecAsn1Certificate\n");
781		return testError(quiet);
782	}
783
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);
792	}
793
794	if(skipThisCert(tbs)) {
795		if(verbose) {
796			printf("   ...skipping TBS blob check\n");
797		}
798		SecAsn1CoderRelease(coder);
799		return 0;
800	}
801
802	/*
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.
809	 */
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;
816		int rtn;
817		switch(type) {
818			case FT_ExtenParsed:
819				/*
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.
826				 */
827				rtn = extenFields.fieldForOid(oid, 0, found);
828				break;
829			case FT_Unknown:
830				/* search for nth unparsed exten field */
831				rtn = extenFields.fieldForOid(
832					CSSMOID_X509V3CertificateExtensionCStruct,
833					numUnknowns++,
834					found);
835				break;
836			default:
837				/* caller was already supposed to check this */
838				doPrintCert(rawCert);
839				printf("***HEY! buildTBS was given a bogus extension!\n");
840				return 1;
841		}
842		if(rtn) {
843			doPrintCert(rawCert);
844			printf("***buildTBS could not find extension in CL's fields\n");
845			return testError(quiet);
846		}
847
848		allFields.appendField(*found);
849	}	/* processing extensions */
850
851	/*
852	 * OK, the field array in allFields is ready to go down to
853	 * the CL.
854	 */
855	CSSM_RETURN crtn;
856	CSSM_DATA clTbs = {0, NULL};
857	crtn = CSSM_CL_CertCreateTemplate(clHand,
858		allFields.mNumFields,
859		allFields.mFields,
860		&clTbs);
861	if(crtn) {
862		doPrintCert(rawCert);
863		printError("CSSM_CL_CertCreateTemplate", crtn);
864		return testError(quiet);
865	}
866
867	/*
868	 * The moment of truth. Is that template identical to the
869	 * raw undecoded TBS blob we got by decoding a NSS_SignedCertOrCRL?
870	 */
871	int ourRtn = 0;
872	if(!appCompareCssmData(&clTbs, &signedCert.tbsBlob)) {
873		doPrintCert(rawCert);
874		printf("***Encoded TBS does not match decoded TBS.\n");
875		if(writeBlobs) {
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);
881		}
882		ourRtn = testError(quiet);
883	}
884	CSSM_FREE(clTbs.Data);
885	SecAsn1CoderRelease(coder);
886	return ourRtn;
887}
888
889/* verify root with itself using TP */
890static 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,
897	CSSM_BOOL		quiet)
898{
899	BlobList blobs;
900	blobs.addBlob(cert, CSSM_TRUE);
901	int i;
902
903	const char *certStatus;
904	if(useTrustSettings) {
905		/*
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
910		 */
911		certStatus = "0:0x314";
912	}
913	else {
914		/*
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
918		 */
919		certStatus = "0:0x1C";
920	}
921
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,
927			blobs,		// certs
928			blobs,		// and roots
929			CSSM_FALSE, // useSystemAnchors
930			CSSM_TRUE,  // leaf is CA
931			expireEnable,
932			CVP_Basic,
933			NULL,		// SSL host
934			CSSM_FALSE, // SSL client
935			NULL,		// sender email
936			0,			// key use
937			NULL,		// expected error str
938			0, NULL,	// per-cert errors
939			1, &certStatus,	// per-cert status
940			useTrustSettings,
941			quiet,
942			CSSM_FALSE);	// verbose
943		if(i == 0) {
944			/* success */
945			if(dex == 1) {
946				printf("...warning: expired root detected. Be aware.\n");
947			}
948			return 0;
949		}
950		if(!allowExpired) {
951			/* no second chance */
952			return i;
953		}
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";
959		}
960		else {
961			/* now expect EXPIRED, IS_ROOT, IS_IN_ANCHORS, IS_IN_INPUT_CERTS */
962			certStatus = "0:0x1d";
963		}
964	}
965	return i;
966}
967
968
969static int doTest(
970	CSSM_CL_HANDLE	clHand,
971	CSSM_TP_HANDLE  tpHand,
972	CSSM_CSP_HANDLE cspHand,
973	const CSSM_DATA	&cert,
974	CSSM_BOOL		allowExpired,
975	CSSM_BOOL		quiet,
976	CSSM_BOOL		verbose,
977	CSSM_BOOL		writeBlobs,
978	CSSM_BOOL		useTrustSettings)
979{
980	/* first see if this anchor self-verifies. */
981	if(verifyRoot(tpHand, clHand, cspHand, cert, allowExpired,
982			useTrustSettings, quiet)) {
983		doPrintCert(cert);
984		printf("***This anchor does not self-verify!\n");
985		return testError(quiet);
986	}
987
988	/* have the CL parse it to the best of its ability */
989	CSSM_FIELD_PTR certFields;
990	uint32 numFields;
991	CSSM_RETURN crtn = CSSM_CL_CertGetAllFields(clHand, &cert, &numFields,
992		&certFields);
993	if(crtn) {
994		printError("CSSM_CL_CertGetAllFields", crtn);
995		doPrintCert(cert);
996		printf("***The CL can not parse this anchor!\n");
997		return testError(quiet);
998	}
999
1000	/* save, this object does the free fields when it goes out of scope */
1001	FieldArray parsed(certFields, numFields, clHand);
1002
1003	/*
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
1007	 * in the cert.
1008	 *
1009	 * First make two buckets for making copies of incoming fields.
1010	 */
1011	FieldArray forCreate(numFields);	// for creating template
1012	FieldArray extenFields(numFields);
1013
1014	for(unsigned dex=0; dex<numFields; dex++) {
1015		CSSM_FIELD &parsedField = parsed.fieldAt(dex);
1016		FieldType type = typeForOid(parsedField.FieldOid);
1017		switch(type) {
1018			case FT_Normal:
1019				forCreate.appendField(parsedField);
1020				break;
1021			case FT_ReadOnly:
1022			case FT_NotTBS:
1023				/* ignore */
1024				break;
1025			case FT_ExtenParsed:
1026			case FT_ExtenUnknown:
1027				/* extensions, save and process later */
1028				extenFields.appendField(parsedField);
1029				break;
1030			default:
1031				doPrintCert(cert);
1032				printf("***This anchor contains an unknown field!\n");
1033				if(testError(quiet)) {
1034					return 1;
1035				}
1036				/* well let's limp along */
1037				forCreate.appendField(parsedField);
1038				break;
1039		}
1040	}
1041
1042	/* basic extension verification */
1043	if(vfyExtens(extenFields, cert, quiet)) {
1044		return 1;
1045	}
1046	return buildTbs(clHand, cert, forCreate, extenFields, quiet,
1047		verbose, writeBlobs);
1048}
1049
1050int main(int argc, char **argv)
1051{
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;
1057
1058	for(int arg=1; arg<argc; arg++) {
1059		switch(argv[arg][0]) {
1060			case 'q':
1061				quiet = CSSM_TRUE;
1062				break;
1063			case 'v':
1064				verbose = CSSM_TRUE;
1065				break;
1066			case 'w':
1067				writeBlobs = CSSM_TRUE;
1068				break;
1069			case 't':
1070				useTrustSettings = CSSM_TRUE;
1071				break;
1072			case 'e':
1073				allowExpired = CSSM_TRUE;
1074				break;
1075			default:
1076				usage(argv);
1077		}
1078	}
1079
1080	printf("Starting anchorTest; args: ");
1081	for(int i=1; i<argc; i++) {
1082		printf("%s ", argv[i]);
1083	}
1084	printf("\n");
1085
1086	/* get system anchors only; convert to CSSM */
1087	CFArrayRef cfAnchors;
1088	OSStatus ortn;
1089	CSSM_DATA *anchors;
1090	unsigned numAnchors;
1091	ortn = getSystemAnchors(&cfAnchors, &anchors, &numAnchors);
1092	if(ortn) {
1093		exit(1);
1094	}
1095	if(numAnchors < 50) {
1096		printf("***Hey! I can only find %u anchors; there should be way more than that.\n",
1097			numAnchors);
1098		exit(1);
1099	}
1100
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)) {
1105		return 0;
1106	}
1107
1108	int rtn = 0;
1109	for(unsigned dex=0; dex<numAnchors; dex++) {
1110		if(!quiet) {
1111			printf("...anchor %u\n", dex);
1112		}
1113		rtn = doTest(clHand, tpHand, cspHand, anchors[dex], allowExpired,
1114			quiet, verbose, writeBlobs, useTrustSettings);
1115		if(rtn) {
1116			break;
1117		}
1118	}
1119	if(rtn == 0) {
1120		if(!quiet) {
1121			printf("...%s success.\n", argv[0]);
1122		}
1123	}
1124	return rtn;
1125}
1126