--- /dev/null
+/*
+ * anchorTest.cpp - test cert encode/decode using known good system
+ * anchors
+ */
+#include <stdio.h>
+#include <string.h>
+#include <Security/cssm.h>
+#include <Security/x509defs.h>
+#include <Security/oidsattr.h>
+#include <Security/oidscert.h>
+#include <Security/certextensions.h>
+#include <Security/SecTrust.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <security_cdsa_utils/cuOidParser.h>
+#include <security_cdsa_utils/cuPrintCert.h>
+#include <utilLib/common.h>
+#include <utilLib/cspwrap.h>
+#include <security_cdsa_utils/cuFileIo.h>
+#include <clAppUtils/clutils.h>
+#include <clAppUtils/certVerify.h>
+#include <clAppUtils/tpUtils.h>
+#include <Security/SecAsn1Coder.h>
+#include <Security/X509Templates.h>
+
+#define ENC_TBS_BLOB "encodedTbs.der"
+#define DEC_TBS_BLOB "decodedTbs.der"
+
+static void usage(char **argv)
+{
+ printf("Usage: %s [options]\n", argv[0]);
+ printf("Options:\n");
+ printf(" w -- writeBlobs\n");
+ printf(" e -- allow expired roots\n");
+ printf(" t -- use Trust Settings\n");
+ printf(" q -- quiet\n");
+ printf(" v -- verbose\n");
+ exit(1);
+}
+
+/*
+ * Certs for which we skip the "compare TBS blob" test, enumerated by
+ * DER-encoded issuer name.
+ *
+ * Get this formatted data from the extractCertFields program.
+ *
+ * All of these have non-standard KeyUsage encoding (legal but it's
+ * not the same as ours or everyone else's).
+ */
+/*
+ Country : HU
+ Locality : Budapest
+ Org : NetLock Halozatbiztonsagi Kft.
+ OrgUnit : Tanusitvanykiadok
+ Common Name : NetLock Expressz (Class C) Tanusitvanykiado
+ */
+static const uint8 anchor_46_derIssuer_bytes[] = {
+ 0x30, 0x81, 0x9b, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
+ 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+ 0x07, 0x13, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70,
+ 0x65, 0x73, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e, 0x4e, 0x65,
+ 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x48, 0x61,
+ 0x6c, 0x6f, 0x7a, 0x61, 0x74, 0x62, 0x69, 0x7a,
+ 0x74, 0x6f, 0x6e, 0x73, 0x61, 0x67, 0x69, 0x20,
+ 0x4b, 0x66, 0x74, 0x2e, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x11, 0x54,
+ 0x61, 0x6e, 0x75, 0x73, 0x69, 0x74, 0x76, 0x61,
+ 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64, 0x6f, 0x6b,
+ 0x31, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x2b, 0x4e, 0x65, 0x74, 0x4c, 0x6f,
+ 0x63, 0x6b, 0x20, 0x45, 0x78, 0x70, 0x72, 0x65,
+ 0x73, 0x73, 0x7a, 0x20, 0x28, 0x43, 0x6c, 0x61,
+ 0x73, 0x73, 0x20, 0x43, 0x29, 0x20, 0x54, 0x61,
+ 0x6e, 0x75, 0x73, 0x69, 0x74, 0x76, 0x61, 0x6e,
+ 0x79, 0x6b, 0x69, 0x61, 0x64, 0x6f
+};
+static const CSSM_DATA anchor_46_derIssuer = { 158, (uint8 *)anchor_46_derIssuer_bytes };
+
+/*
+ Country : HU
+ State : Hungary
+ Locality : Budapest
+ Org : NetLock Halozatbiztonsagi Kft.
+ OrgUnit : Tanusitvanykiadok
+ Common Name : NetLock Kozjegyzoi (Class A) Tanusitvanykiado
+*/
+static const uint8 anchor_53_derIssuer_bytes[] = {
+ 0x30, 0x81, 0xaf, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
+ 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
+ 0x08, 0x13, 0x07, 0x48, 0x75, 0x6e, 0x67, 0x61,
+ 0x72, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x04, 0x07, 0x13, 0x08, 0x42, 0x75, 0x64,
+ 0x61, 0x70, 0x65, 0x73, 0x74, 0x31, 0x27, 0x30,
+ 0x25, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e,
+ 0x4e, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20,
+ 0x48, 0x61, 0x6c, 0x6f, 0x7a, 0x61, 0x74, 0x62,
+ 0x69, 0x7a, 0x74, 0x6f, 0x6e, 0x73, 0x61, 0x67,
+ 0x69, 0x20, 0x4b, 0x66, 0x74, 0x2e, 0x31, 0x1a,
+ 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+ 0x11, 0x54, 0x61, 0x6e, 0x75, 0x73, 0x69, 0x74,
+ 0x76, 0x61, 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64,
+ 0x6f, 0x6b, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x13, 0x2d, 0x4e, 0x65, 0x74,
+ 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x4b, 0x6f, 0x7a,
+ 0x6a, 0x65, 0x67, 0x79, 0x7a, 0x6f, 0x69, 0x20,
+ 0x28, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x41,
+ 0x29, 0x20, 0x54, 0x61, 0x6e, 0x75, 0x73, 0x69,
+ 0x74, 0x76, 0x61, 0x6e, 0x79, 0x6b, 0x69, 0x61,
+ 0x64, 0x6f
+};
+static const CSSM_DATA anchor_53_derIssuer = { 178, (uint8 *)anchor_53_derIssuer_bytes };
+
+/*
+ Country : HU
+ Locality : Budapest
+ Org : NetLock Halozatbiztonsagi Kft.
+ OrgUnit : Tanusitvanykiadok
+ Common Name : NetLock Uzleti (Class B) Tanusitvanykiado
+*/
+static const uint8 anchor_60_derIssuer_bytes[] = {
+ 0x30, 0x81, 0x99, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
+ 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+ 0x07, 0x13, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70,
+ 0x65, 0x73, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e, 0x4e, 0x65,
+ 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x48, 0x61,
+ 0x6c, 0x6f, 0x7a, 0x61, 0x74, 0x62, 0x69, 0x7a,
+ 0x74, 0x6f, 0x6e, 0x73, 0x61, 0x67, 0x69, 0x20,
+ 0x4b, 0x66, 0x74, 0x2e, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x11, 0x54,
+ 0x61, 0x6e, 0x75, 0x73, 0x69, 0x74, 0x76, 0x61,
+ 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64, 0x6f, 0x6b,
+ 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x29, 0x4e, 0x65, 0x74, 0x4c, 0x6f,
+ 0x63, 0x6b, 0x20, 0x55, 0x7a, 0x6c, 0x65, 0x74,
+ 0x69, 0x20, 0x28, 0x43, 0x6c, 0x61, 0x73, 0x73,
+ 0x20, 0x42, 0x29, 0x20, 0x54, 0x61, 0x6e, 0x75,
+ 0x73, 0x69, 0x74, 0x76, 0x61, 0x6e, 0x79, 0x6b,
+ 0x69, 0x61, 0x64, 0x6f
+};
+static const CSSM_DATA anchor_60_derIssuer = { 156, (uint8 *)anchor_60_derIssuer_bytes };
+
+/*
+ Country : TR
+ Locality : Ankara
+ Org : (c) 2005 TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
+ Common Name : TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
+ Serial Number : 01
+ Not Before : 10:27:17 May 13, 2005
+ Not After : 10:27:17 Mar 22, 2015
+*/
+static const uint8 turk1_derIssuer_bytes[] = {
+ 0x30, 0x81, 0xb7, 0x31, 0x3f, 0x30, 0x3d, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x0c, 0x36, 0x54, 0xc3,
+ 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
+ 0x20, 0x45, 0x6c, 0x65, 0x6b, 0x74, 0x72, 0x6f,
+ 0x6e, 0x69, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x69,
+ 0x7a, 0x6d, 0x65, 0x74, 0x20, 0x53, 0x61, 0xc4,
+ 0x9f, 0x6c, 0x61, 0x79, 0xc4, 0xb1, 0x63, 0xc4,
+ 0xb1, 0x73, 0xc4, 0xb1, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x0c, 0x02, 0x54,
+ 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
+ 0x04, 0x07, 0x0c, 0x06, 0x41, 0x4e, 0x4b, 0x41,
+ 0x52, 0x41, 0x31, 0x56, 0x30, 0x54, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x0c, 0x4d, 0x28, 0x63, 0x29,
+ 0x20, 0x32, 0x30, 0x30, 0x35, 0x20, 0x54, 0xc3,
+ 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
+ 0x20, 0x42, 0x69, 0x6c, 0x67, 0x69, 0x20, 0xc4,
+ 0xb0, 0x6c, 0x65, 0x74, 0x69, 0xc5, 0x9f, 0x69,
+ 0x6d, 0x20, 0x76, 0x65, 0x20, 0x42, 0x69, 0x6c,
+ 0x69, 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x47, 0xc3,
+ 0xbc, 0x76, 0x65, 0x6e, 0x6c, 0x69, 0xc4, 0x9f,
+ 0x69, 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74,
+ 0x6c, 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5,
+ 0x9e, 0x2e
+};
+static const CSSM_DATA turk1_derIssuer = { 186, (uint8 *)turk1_derIssuer_bytes };
+
+/*
+ Country : TR
+ Locality : Ankara
+ Org : TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Kasım 2005
+ Common Name : TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
+ Serial Number : 01
+ Not Before : 10:07:57 Nov 7, 2005
+ Not After : 10:07:57 Sep 16, 2015
+*/
+static const uint8 turk2_derIssuer_bytes[] = {
+ 0x30, 0x81, 0xbe, 0x31, 0x3f, 0x30, 0x3d, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x0c, 0x36, 0x54, 0xc3,
+ 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
+ 0x20, 0x45, 0x6c, 0x65, 0x6b, 0x74, 0x72, 0x6f,
+ 0x6e, 0x69, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x69,
+ 0x7a, 0x6d, 0x65, 0x74, 0x20, 0x53, 0x61, 0xc4,
+ 0x9f, 0x6c, 0x61, 0x79, 0xc4, 0xb1, 0x63, 0xc4,
+ 0xb1, 0x73, 0xc4, 0xb1, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54,
+ 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
+ 0x04, 0x07, 0x0c, 0x06, 0x41, 0x6e, 0x6b, 0x61,
+ 0x72, 0x61, 0x31, 0x5d, 0x30, 0x5b, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x0c, 0x54, 0x54, 0xc3, 0x9c,
+ 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
+ 0x42, 0x69, 0x6c, 0x67, 0x69, 0x20, 0xc4, 0xb0,
+ 0x6c, 0x65, 0x74, 0x69, 0xc5, 0x9f, 0x69, 0x6d,
+ 0x20, 0x76, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69,
+ 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x47, 0xc3, 0xbc,
+ 0x76, 0x65, 0x6e, 0x6c, 0x69, 0xc4, 0x9f, 0x69,
+ 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74, 0x6c,
+ 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e,
+ 0x2e, 0x20, 0x28, 0x63, 0x29, 0x20, 0x4b, 0x61,
+ 0x73, 0xc4, 0xb1, 0x6d, 0x20, 0x32, 0x30, 0x30,
+ 0x35
+};
+static const CSSM_DATA turk2_derIssuer = { 193, (uint8 *)turk2_derIssuer_bytes };
+
+/*
+ Country : TR
+ Locality : Ankara
+ Org : TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Aralık 2007
+ Common Name : TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
+ Serial Number : 01
+ Not Before : 18:37:19 Dec 25, 2007
+ Not After : 18:37:19 Dec 22, 2017
+*/
+static const uint8 turk3_derIssuer_bytes[] = {
+ 0x30, 0x81, 0xbf, 0x31, 0x3f, 0x30, 0x3d, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x0c, 0x36, 0x54, 0xc3,
+ 0x9c, 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54,
+ 0x20, 0x45, 0x6c, 0x65, 0x6b, 0x74, 0x72, 0x6f,
+ 0x6e, 0x69, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x69,
+ 0x7a, 0x6d, 0x65, 0x74, 0x20, 0x53, 0x61, 0xc4,
+ 0x9f, 0x6c, 0x61, 0x79, 0xc4, 0xb1, 0x63, 0xc4,
+ 0xb1, 0x73, 0xc4, 0xb1, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54,
+ 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
+ 0x04, 0x07, 0x0c, 0x06, 0x41, 0x6e, 0x6b, 0x61,
+ 0x72, 0x61, 0x31, 0x5e, 0x30, 0x5c, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x0c, 0x55, 0x54, 0xc3, 0x9c,
+ 0x52, 0x4b, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
+ 0x42, 0x69, 0x6c, 0x67, 0x69, 0x20, 0xc4, 0xb0,
+ 0x6c, 0x65, 0x74, 0x69, 0xc5, 0x9f, 0x69, 0x6d,
+ 0x20, 0x76, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69,
+ 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x47, 0xc3, 0xbc,
+ 0x76, 0x65, 0x6e, 0x6c, 0x69, 0xc4, 0x9f, 0x69,
+ 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74, 0x6c,
+ 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e,
+ 0x2e, 0x20, 0x28, 0x63, 0x29, 0x20, 0x41, 0x72,
+ 0x61, 0x6c, 0xc4, 0xb1, 0x6b, 0x20, 0x32, 0x30,
+ 0x30, 0x37
+};
+static const CSSM_DATA turk3_derIssuer = { 194, (uint8 *)turk3_derIssuer_bytes };
+
+/*
+Cert File Name: globalSignRoot.cer
+ Country : BE
+ Org : GlobalSign nv-sa
+ OrgUnit : Root CA
+ Common Name : GlobalSign Root CA
+*/
+static const uint8 globalSignRoot_derIssuer_bytes[] = {
+ 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31,
+ 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+ 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d,
+ 0x73, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
+ 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, 0x6f,
+ 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47,
+ 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67,
+ 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+ 0x41
+};
+static const CSSM_DATA globalSignRoot_derIssuer = { 89, (uint8 *)globalSignRoot_derIssuer_bytes };
+
+/***********************
+Cert File Name: swisssign.der
+Subject Name :
+ Country : CH
+ Org : SwissSign
+ Common Name : SwissSign CA (RSA IK May 6 1999 18:00:58)
+ Email addrs : ca@SwissSign.com
+
+ This one has a bogus AuthorityKeyId, with a value of {0x30, 0} inside the octet string.
+ ***********************/
+static const uint8 swisssign_derIssuer_bytes[] = {
+ 0x30, 0x76, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x31,
+ 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x09, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53,
+ 0x69, 0x67, 0x6e, 0x31, 0x32, 0x30, 0x30, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, 0x53, 0x77,
+ 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20,
+ 0x43, 0x41, 0x20, 0x28, 0x52, 0x53, 0x41, 0x20,
+ 0x49, 0x4b, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x36,
+ 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x31, 0x38,
+ 0x3a, 0x30, 0x30, 0x3a, 0x35, 0x38, 0x29, 0x31,
+ 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10,
+ 0x63, 0x61, 0x40, 0x53, 0x77, 0x69, 0x73, 0x73,
+ 0x53, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d
+
+};
+static const CSSM_DATA swisssign_derIssuer = { 120, (uint8 *)swisssign_derIssuer_bytes };
+
+/*
+ * Simple class to hold arrays of fields.
+ */
+class FieldArray {
+public:
+ /*
+ * Create from existing field array obtained from
+ * CSSM_CL_CertGetAllFields(). We'll do the CSSM_CL_FreeFields()
+ * in our destructor.
+ */
+ FieldArray(
+ CSSM_FIELD *fields,
+ uint32 numFields,
+ CSSM_CL_HANDLE clHand);
+
+ /*
+ * Create empty array of specified size. We don't own the fields
+ * themselves.
+ */
+ FieldArray(
+ uint32 size);
+
+ ~FieldArray();
+
+ /*
+ * Append a field - no realloc!
+ */
+ void appendField(CSSM_FIELD &field);
+
+ /* get specified field */
+ CSSM_FIELD &fieldAt(uint32 index);
+
+ /* get nth occurence of field matching specified OID */
+ int fieldForOid(
+ const CSSM_OID &oid,
+ unsigned n, // n == 0 --> first one
+ CSSM_FIELD *&found); // RETURNED
+
+ CSSM_FIELD *mFields;
+ uint32 mNumFields; // sizeof of *fields
+ uint32 mMallocdSize; // if NULL, read-only
+ CSSM_CL_HANDLE mClHand;
+};
+
+FieldArray::FieldArray(
+ CSSM_FIELD *fields,
+ uint32 numFields,
+ CSSM_CL_HANDLE clHand)
+{
+ mFields = fields;
+ mNumFields = numFields;
+ mMallocdSize = 0;
+ mClHand = clHand;
+}
+
+FieldArray::FieldArray(
+ uint32 size)
+{
+ unsigned len = sizeof(CSSM_FIELD) * size;
+ mFields = (CSSM_FIELD_PTR)malloc(len);
+ memset(mFields, 0, len);
+ mNumFields = 0;
+ mMallocdSize = size;
+ mClHand = 0;
+}
+
+FieldArray::~FieldArray()
+{
+ if(mMallocdSize != 0) {
+ /*
+ * Just free the array of fields we mallocd, not the fields
+ * themselves
+ */
+ free(mFields);
+ }
+ else {
+ /* The CL mallocd these fields, tell it to free the whole thing */
+ CSSM_RETURN crtn = CSSM_CL_FreeFields(mClHand,
+ mNumFields, &mFields);
+ if(crtn) {
+ printError("CSSM_CL_FreeFields", crtn);
+ }
+ }
+ mFields = NULL;
+ mNumFields = 0;
+ mMallocdSize = 0;
+}
+
+void FieldArray::appendField(
+ CSSM_FIELD &field)
+{
+ if(mMallocdSize == 0) {
+ printf("***Attempt to append to a read-only FieldArray\n");
+ exit(1);
+ }
+ if(mNumFields >= mMallocdSize) {
+ printf("***Attempt to append past present size of FieldArray\n");
+ exit(1);
+ }
+ mFields[mNumFields] = field;
+ mNumFields++;
+}
+
+CSSM_FIELD &FieldArray::fieldAt(
+ uint32 index)
+{
+ if(index >= mNumFields) {
+ printf("***Attempt to access past present size of FieldArray\n");
+ exit(1);
+ }
+ return mFields[index];
+}
+
+/* get nth occurence of field matching specified OID */
+/* returns nonzero on error */
+int FieldArray::fieldForOid(
+ const CSSM_OID &oid,
+ unsigned n, // n == 0 --> first one
+ CSSM_FIELD *&found) // RETURNED
+{
+ unsigned foundDex = 0;
+ for(unsigned dex=0; dex<mNumFields; dex++) {
+ CSSM_FIELD &field = mFields[dex];
+ if(appCompareCssmData(&field.FieldOid, &oid)) {
+ if(foundDex == n) {
+ found = &field;
+ return 0;
+ }
+ foundDex++;
+ }
+ }
+ printf("FieldArray::fieldForOid field not found\n");
+ return 1;
+}
+
+/*
+ * How many items in a NULL-terminated array of pointers?
+ */
+static unsigned nssArraySize(
+ const void **array)
+{
+ unsigned count = 0;
+ if (array) {
+ while (*array++) {
+ count++;
+ }
+ }
+ return count;
+}
+
+static void doPrintCert(
+ const CSSM_DATA &cert)
+{
+ printCert(cert.Data, cert.Length, CSSM_TRUE);
+}
+
+/*
+ * The extensions whose presence causes us to skip the "compare
+ * encoded and original TBS" test.
+ */
+#define USE_SKIPPED_EXTENS 1
+#if USE_SKIPPED_EXTENS
+static const CSSM_OID *skippedExtens[] = { // %%% FIXME: this is a workaround for <rdar://8265523>; shouldn't need to skip!
+ &CSSMOID_PolicyMappings,
+ &CSSMOID_PolicyConstraints
+};
+#define NUM_SKIPPED_EXTENS \
+ (sizeof(skippedExtens) / sizeof(skippedExtens[0]))
+#endif /* USE_SKIPPED_EXTENS */
+
+static const CSSM_DATA *skippedCerts[] = {
+ &anchor_46_derIssuer,
+ &anchor_53_derIssuer,
+ &anchor_60_derIssuer,
+ &turk1_derIssuer,
+ &turk2_derIssuer,
+ &turk3_derIssuer,
+ &globalSignRoot_derIssuer,
+ &swisssign_derIssuer
+};
+#define NUM_SKIPPED_CERTS (sizeof(skippedCerts) / sizeof(skippedCerts[0]))
+
+static bool skipThisCert(
+ const NSS_TBSCertificate &tbs)
+{
+ /* search by extension - currently unused */
+ unsigned dex;
+ #if USE_SKIPPED_EXTENS
+ unsigned numExtens = nssArraySize((const void **)tbs.extensions);
+ /* skip this section if that's empty - compiler warning causes failure */
+ for(dex=0; dex<numExtens; dex++) {
+ NSS_CertExtension *exten = tbs.extensions[dex];
+ CSSM_OID *oid = &exten->extnId;
+ for(unsigned skipDex=0; skipDex<NUM_SKIPPED_EXTENS; skipDex++) {
+ if(appCompareCssmData(skippedExtens[skipDex], oid)) {
+ return true;
+ }
+ }
+ }
+ #endif /* USE_SKIPPED_EXTENS */
+
+ /* search by specific issuer */
+ for(dex=0; dex<NUM_SKIPPED_CERTS; dex++) {
+ if(appCompareCssmData(skippedCerts[dex], &tbs.derIssuer)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * Given a field OID, figure out what WE think this field is.
+ */
+
+/* the field types we grok */
+typedef enum {
+ FT_Unknown, // probably means we're out of sync with the CL
+ FT_Normal, // standard component of TBS
+ FT_ReadOnly, // Read only, don't use to create template
+ FT_NotTBS, // part of top-level cert, don't use to create TBS
+ FT_ExtenParsed, // extension the CL SHOULD HAVE parsed
+ FT_ExtenUnknown // extension the CL should NOT have parsed
+} FieldType;
+
+/* map OID --> FieldType */
+typedef struct {
+ const CSSM_OID *oid;
+ FieldType type;
+} FieldOidType;
+
+/*
+ * The CL-specific mapping table.
+ * This has to change whenever the CL is modified to add or delete
+ * an extension or field!
+ * For newbies, a tip: this basically has to stay in sync with the
+ * fieldFuncTable array in Security/AppleX509CL/CertFields.cpp.
+ */
+FieldOidType knownFields[] = {
+ { &CSSMOID_X509V1Version, FT_Normal },
+ { &CSSMOID_X509V1SerialNumber, FT_Normal },
+ { &CSSMOID_X509V1IssuerNameCStruct, FT_Normal },
+ { &CSSMOID_X509V1SubjectNameCStruct, FT_Normal },
+ { &CSSMOID_X509V1SignatureAlgorithmTBS, FT_Normal },
+ { &CSSMOID_X509V1SignatureAlgorithm, FT_NotTBS },
+ { &CSSMOID_X509V1ValidityNotBefore, FT_Normal },
+ { &CSSMOID_X509V1ValidityNotAfter, FT_Normal },
+ { &CSSMOID_X509V1CertificateIssuerUniqueId, FT_Normal },
+ { &CSSMOID_X509V1CertificateSubjectUniqueId, FT_Normal },
+ /* only one of these two can be set - use the SubjectPublicKeyInfo
+ * version */
+ { &CSSMOID_X509V1SubjectPublicKeyCStruct, FT_Normal },
+ { &CSSMOID_CSSMKeyStruct, FT_ReadOnly },
+ { &CSSMOID_X509V1Signature, FT_NotTBS },
+ { &CSSMOID_X509V1IssuerName, FT_ReadOnly }, // DER encoded
+ { &CSSMOID_X509V1SubjectName, FT_ReadOnly }, // DER encoded
+ { &CSSMOID_X509V1IssuerNameStd, FT_ReadOnly }, // DER encoded
+ { &CSSMOID_X509V1SubjectNameStd,FT_ReadOnly }, // DER encoded
+
+ /* Extensions */
+ { &CSSMOID_KeyUsage, FT_ExtenParsed },
+ { &CSSMOID_BasicConstraints, FT_ExtenParsed },
+ { &CSSMOID_ExtendedKeyUsage, FT_ExtenParsed } ,
+ { &CSSMOID_SubjectKeyIdentifier, FT_ExtenParsed } ,
+ { &CSSMOID_AuthorityKeyIdentifier, FT_ExtenParsed } ,
+ { &CSSMOID_SubjectAltName, FT_ExtenParsed } ,
+ { &CSSMOID_IssuerAltName, FT_ExtenParsed } ,
+ { &CSSMOID_CertificatePolicies, FT_ExtenParsed } ,
+ { &CSSMOID_NetscapeCertType, FT_ExtenParsed } ,
+ { &CSSMOID_CrlDistributionPoints, FT_ExtenParsed },
+ { &CSSMOID_AuthorityInfoAccess, FT_ExtenParsed },
+ { &CSSMOID_SubjectInfoAccess, FT_ExtenParsed },
+ { &CSSMOID_X509V3CertificateExtensionCStruct, FT_ExtenUnknown },
+ { &CSSMOID_QC_Statements, FT_ExtenParsed },
+ { &CSSMOID_NameConstraints, FT_ExtenParsed },
+ { &CSSMOID_PolicyMappings, FT_ExtenParsed },
+ { &CSSMOID_PolicyConstraints, FT_ExtenParsed },
+// { &CSSMOID_InhibitAnyPolicy, FT_ExtenParsed } //%%% FIXME: CSSMOID_InhibitAnyPolicy not exported!?
+};
+#define NUM_KNOWN_FIELDS (sizeof(knownFields) / sizeof(knownFields[0]))
+
+static FieldType typeForOid(
+ const CSSM_OID &oid)
+{
+ for(unsigned dex=0; dex<NUM_KNOWN_FIELDS; dex++) {
+ FieldOidType &ft = knownFields[dex];
+ if(appCompareCssmData(&oid, ft.oid)) {
+ return ft.type;
+ }
+ }
+ /* not found */
+ return FT_Unknown;
+}
+
+static const char *fieldTypeStr(
+ FieldType type)
+{
+ switch(type) {
+ case FT_Unknown: return "FT_Unknown";
+ case FT_Normal: return "FT_Normal";
+ case FT_ReadOnly: return "FT_ReadOnly";
+ case FT_NotTBS: return "FT_NotTBS";
+ case FT_ExtenParsed: return "FT_ExtenParsed";
+ case FT_ExtenUnknown: return "FT_ExtenUnknown";
+ default:
+ printf("***BRRZAP!\n");
+ exit(1);
+ }
+}
+
+static const uint8 emptyAuthKeyId[2] = {0x30, 0};
+
+/*
+ * Extensions come in two flavors - parsed and not. However the
+ * CL will give us an unparsed version for extensions it normally
+ * understands but failed to decode. Detect that, and basic
+ * extension formatting screwups, here.
+ */
+static int vfyExtens(
+ FieldArray &extenFields,
+ const CSSM_DATA &cert, // for error display only
+ CSSM_BOOL quiet)
+{
+ for(unsigned dex=0; dex<extenFields.mNumFields; dex++) {
+ CSSM_FIELD &extenField = extenFields.fieldAt(dex);
+ FieldType type = typeForOid(extenField.FieldOid);
+ FieldType expectType;
+
+ /* first verify well-formed extension field */
+ CSSM_DATA &fieldValue = extenField.FieldValue;
+ CSSM_X509_EXTENSION *exten = (CSSM_X509_EXTENSION *)fieldValue.Data;
+ if((exten == NULL) ||
+ (fieldValue.Length != sizeof(CSSM_X509_EXTENSION))) {
+ doPrintCert(cert);
+ printf("***Malformed CSSM_X509_EXTENSION\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ /* well let's limp along */
+ continue;
+ }
+
+ /* currently (since Radar 3593624), these are both always valid */
+ if((exten->BERvalue.Data == NULL) ||
+ (exten->value.parsedValue == NULL)) { /* actually, one of three variants */
+ printf("***Malformed CSSM_X509_EXTENSION (1)\n");
+ return 1;
+ }
+
+ switch(exten->format) {
+ case CSSM_X509_DATAFORMAT_ENCODED:
+ if(type != FT_ExtenUnknown) {
+ doPrintCert(cert);
+ printf("***Entension format ENCODED, expected PARSED\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+
+ /*
+ * Now make sure that the underlying extension ID isn't
+ * one that the CL was SUPPOSED to parse
+ */
+ // %%% FIXME: need to investigate why these are not fully parsed: <rdar://8265523>
+ if(appCompareCssmData(&exten->extnId, &CSSMOID_PolicyConstraints)) {
+ printf("...skipping policyConstraints extension per <rdar://8265523> (fix me!)\n");
+ break;
+ }
+ if(appCompareCssmData(&exten->extnId, &CSSMOID_PolicyMappings)) {
+ printf("...skipping policyMappings extension per <rdar://8265523> (fix me!)\n");
+ break;
+ }
+
+ expectType = typeForOid(exten->extnId);
+ if(expectType != FT_Unknown) {
+ /*
+ * Swisscom root has an authorityKeyId extension with an illegal value,
+ * data inside the octet string is <30 00>, no context-specific wrapper
+ * or tag.
+ * Instead of a hopeless complaint about that cert, let's just tolerate it
+ * like this...
+ */
+ if(appCompareCssmData(&exten->extnId, &CSSMOID_AuthorityKeyIdentifier) &&
+ (exten->BERvalue.Length == 2) &&
+ !memcmp(emptyAuthKeyId, exten->BERvalue.Data, 2)) {
+ printf("...skipping bogus swisssign AuthorityKeyId\n");
+ break;
+ }
+ doPrintCert(cert);
+ printf("***underlying exten type %s, expect Unknown\n",
+ fieldTypeStr(expectType));
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ break;
+
+ case CSSM_X509_DATAFORMAT_PARSED:
+ if(type != FT_ExtenParsed) {
+ doPrintCert(cert);
+ printf("***Entension format PARSED, expected ENCODED\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ if(exten->value.parsedValue == NULL) {
+ doPrintCert(cert);
+ printf("***Parsed extension with NULL parsedValue\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ break;
+
+ default:
+ doPrintCert(cert);
+ printf("***Unknown Entension format %u\n",
+ exten->format);
+ if(testError(quiet)) {
+ return 1;
+ }
+ break;
+
+ } /* switch(exten.format) */
+ }
+ return 0;
+}
+
+/*
+ * Here's the hard part.
+ * Given a raw cert and its components in two FieldArrays, crate a TBS
+ * cert from scratch from those fields and ensure that the result
+ * is the same as the raw TBS field in the original cert.
+ */
+static int buildTbs(
+ CSSM_CL_HANDLE clHand,
+ const CSSM_DATA &rawCert,
+ FieldArray &allFields, // on entry, standard fields
+ FieldArray &extenFields, // extensions only
+ CSSM_BOOL quiet,
+ CSSM_BOOL verbose,
+ CSSM_BOOL writeBlobs)
+{
+ /*
+ * First do raw BER-decode in two ways - one to get the
+ * extensions as they actuallly appear in the cert, and one
+ * to get the raw undecoded TBS.
+ */
+ SecAsn1CoderRef coder;
+ OSStatus ortn = SecAsn1CoderCreate(&coder);
+ if(ortn) {
+ cssmPerror("SecAsn1CoderCreate", ortn);
+ return testError(quiet);
+ }
+
+ NSS_SignedCertOrCRL signedCert; // with TBS as ASN_ANY
+ memset(&signedCert, 0, sizeof(signedCert));
+ if(SecAsn1DecodeData(coder, &rawCert, kSecAsn1SignedCertOrCRLTemplate,
+ &signedCert)) {
+ doPrintCert(rawCert);
+ printf("***Error decoding cert to kSecAsn1SignedCertOrCRL\n");
+ return testError(quiet);
+ }
+
+ NSS_Certificate fullCert; // fully decoded
+ memset(&fullCert, 0, sizeof(fullCert));
+ if(SecAsn1DecodeData(coder, &rawCert, kSecAsn1SignedCertTemplate,
+ &fullCert)) {
+ doPrintCert(rawCert);
+ printf("***Error decoding cert to kSecAsn1Certificate\n");
+ return testError(quiet);
+ }
+
+ NSS_TBSCertificate &tbs = fullCert.tbs;
+ unsigned numExtens = nssArraySize((const void **)tbs.extensions);
+ if(numExtens != extenFields.mNumFields) {
+ /* The CL told us the wrong number of extensions */
+ doPrintCert(rawCert);
+ printf("***NSS says %u extens, CL says %u\n", numExtens,
+ (unsigned)extenFields.mNumFields);
+ return testError(quiet);
+ }
+
+ if(skipThisCert(tbs)) {
+ if(verbose) {
+ printf(" ...skipping TBS blob check\n");
+ }
+ SecAsn1CoderRelease(coder);
+ return 0;
+ }
+
+ /*
+ * The CL returns extension fields in an order which differs from
+ * the order of the extensions in the actual cert (because it
+ * does a table-based lookup, field by field, when doing a
+ * CSSM_CL_CertGetAllFields()). We have to add the extensions
+ * from extenFields to allFields in the order they appear in
+ * OUR decoded fullCert.
+ */
+ unsigned numUnknowns = 0;
+ for(unsigned dex=0; dex<numExtens; dex++) {
+ NSS_CertExtension *exten = tbs.extensions[dex];
+ CSSM_OID &oid = exten->extnId;
+ FieldType type = typeForOid(oid);
+ CSSM_FIELD *found = NULL;
+ int rtn;
+ switch(type) {
+ case FT_ExtenParsed:
+ /*
+ * look for this exact extension
+ * NOTE we're assuming that only one copy of
+ * each specific parsed extension exists. The
+ * 509 spec does't specifically require this but
+ * I've never seen a case of multiple extensions
+ * of the same type in one cert.
+ */
+ rtn = extenFields.fieldForOid(oid, 0, found);
+ break;
+ case FT_Unknown:
+ /* search for nth unparsed exten field */
+ rtn = extenFields.fieldForOid(
+ CSSMOID_X509V3CertificateExtensionCStruct,
+ numUnknowns++,
+ found);
+ break;
+ default:
+ /* caller was already supposed to check this */
+ doPrintCert(rawCert);
+ printf("***HEY! buildTBS was given a bogus extension!\n");
+ return 1;
+ }
+ if(rtn) {
+ doPrintCert(rawCert);
+ printf("***buildTBS could not find extension in CL's fields\n");
+ return testError(quiet);
+ }
+
+ allFields.appendField(*found);
+ } /* processing extensions */
+
+ /*
+ * OK, the field array in allFields is ready to go down to
+ * the CL.
+ */
+ CSSM_RETURN crtn;
+ CSSM_DATA clTbs = {0, NULL};
+ crtn = CSSM_CL_CertCreateTemplate(clHand,
+ allFields.mNumFields,
+ allFields.mFields,
+ &clTbs);
+ if(crtn) {
+ doPrintCert(rawCert);
+ printError("CSSM_CL_CertCreateTemplate", crtn);
+ return testError(quiet);
+ }
+
+ /*
+ * The moment of truth. Is that template identical to the
+ * raw undecoded TBS blob we got by decoding a NSS_SignedCertOrCRL?
+ */
+ int ourRtn = 0;
+ if(!appCompareCssmData(&clTbs, &signedCert.tbsBlob)) {
+ doPrintCert(rawCert);
+ printf("***Encoded TBS does not match decoded TBS.\n");
+ if(writeBlobs) {
+ writeFile(ENC_TBS_BLOB, clTbs.Data, clTbs.Length);
+ writeFile(DEC_TBS_BLOB, signedCert.tbsBlob.Data,
+ signedCert.tbsBlob.Length);
+ printf("...wrote TBS blobs to %s and %s\n",
+ ENC_TBS_BLOB, DEC_TBS_BLOB);
+ }
+ ourRtn = testError(quiet);
+ }
+ CSSM_FREE(clTbs.Data);
+ SecAsn1CoderRelease(coder);
+ return ourRtn;
+}
+
+/* verify root with itself using TP */
+static int verifyRoot(
+ CSSM_TP_HANDLE tpHand,
+ CSSM_CL_HANDLE clHand,
+ CSSM_CSP_HANDLE cspHand,
+ const CSSM_DATA &cert,
+ CSSM_BOOL allowExpired,
+ CSSM_BOOL useTrustSettings,
+ CSSM_BOOL quiet)
+{
+ BlobList blobs;
+ blobs.addBlob(cert, CSSM_TRUE);
+ int i;
+
+ const char *certStatus;
+ if(useTrustSettings) {
+ /*
+ * CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
+ * CSSM_CERT_STATUS_IS_ROOT
+ * CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM
+ * CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
+ */
+ certStatus = "0:0x314";
+ }
+ else {
+ /*
+ * CSSM_CERT_STATUS_IS_IN_INPUT_CERTS (new since radar 3855635 was fixed)
+ * CSSM_CERT_STATUS_IS_IN_ANCHORS
+ * CSSM_CERT_STATUS_IS_ROOT
+ */
+ certStatus = "0:0x1C";
+ }
+
+ /* try one with allowExpiredRoot false, then true on error and if so
+ * enabled to make sure we know what's going wrong */
+ CSSM_BOOL expireEnable = CSSM_FALSE;
+ for(int dex=0; dex<2; dex++) {
+ i = certVerifySimple(tpHand, clHand, cspHand,
+ blobs, // certs
+ blobs, // and roots
+ CSSM_FALSE, // useSystemAnchors
+ CSSM_TRUE, // leaf is CA
+ expireEnable,
+ CVP_Basic,
+ NULL, // SSL host
+ CSSM_FALSE, // SSL client
+ NULL, // sender email
+ 0, // key use
+ NULL, // expected error str
+ 0, NULL, // per-cert errors
+ 1, &certStatus, // per-cert status
+ useTrustSettings,
+ quiet,
+ CSSM_FALSE); // verbose
+ if(i == 0) {
+ /* success */
+ if(dex == 1) {
+ printf("...warning: expired root detected. Be aware.\n");
+ }
+ return 0;
+ }
+ if(!allowExpired) {
+ /* no second chance */
+ return i;
+ }
+ expireEnable = CSSM_TRUE;
+ if(useTrustSettings) {
+ /* now expect EXPIRED, IS_ROOT, IS_IN_INPUT_CERTS, TRUST_SETTINGS_FOUND_SYSTEM,
+ * CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST */
+ certStatus = "0:0x315";
+ }
+ else {
+ /* now expect EXPIRED, IS_ROOT, IS_IN_ANCHORS, IS_IN_INPUT_CERTS */
+ certStatus = "0:0x1d";
+ }
+ }
+ return i;
+}
+
+
+static int doTest(
+ CSSM_CL_HANDLE clHand,
+ CSSM_TP_HANDLE tpHand,
+ CSSM_CSP_HANDLE cspHand,
+ const CSSM_DATA &cert,
+ CSSM_BOOL allowExpired,
+ CSSM_BOOL quiet,
+ CSSM_BOOL verbose,
+ CSSM_BOOL writeBlobs,
+ CSSM_BOOL useTrustSettings)
+{
+ /* first see if this anchor self-verifies. */
+ if(verifyRoot(tpHand, clHand, cspHand, cert, allowExpired,
+ useTrustSettings, quiet)) {
+ doPrintCert(cert);
+ printf("***This anchor does not self-verify!\n");
+ return testError(quiet);
+ }
+
+ /* have the CL parse it to the best of its ability */
+ CSSM_FIELD_PTR certFields;
+ uint32 numFields;
+ CSSM_RETURN crtn = CSSM_CL_CertGetAllFields(clHand, &cert, &numFields,
+ &certFields);
+ if(crtn) {
+ printError("CSSM_CL_CertGetAllFields", crtn);
+ doPrintCert(cert);
+ printf("***The CL can not parse this anchor!\n");
+ return testError(quiet);
+ }
+
+ /* save, this object does the free fields when it goes out of scope */
+ FieldArray parsed(certFields, numFields, clHand);
+
+ /*
+ * We're going to build a TBSCert from these received fields.
+ * Extensions need to be processed specially because they
+ * come back from the CL ordered differently than they appear
+ * in the cert.
+ *
+ * First make two buckets for making copies of incoming fields.
+ */
+ FieldArray forCreate(numFields); // for creating template
+ FieldArray extenFields(numFields);
+
+ for(unsigned dex=0; dex<numFields; dex++) {
+ CSSM_FIELD &parsedField = parsed.fieldAt(dex);
+ FieldType type = typeForOid(parsedField.FieldOid);
+ switch(type) {
+ case FT_Normal:
+ forCreate.appendField(parsedField);
+ break;
+ case FT_ReadOnly:
+ case FT_NotTBS:
+ /* ignore */
+ break;
+ case FT_ExtenParsed:
+ case FT_ExtenUnknown:
+ /* extensions, save and process later */
+ extenFields.appendField(parsedField);
+ break;
+ default:
+ doPrintCert(cert);
+ printf("***This anchor contains an unknown field!\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ /* well let's limp along */
+ forCreate.appendField(parsedField);
+ break;
+ }
+ }
+
+ /* basic extension verification */
+ if(vfyExtens(extenFields, cert, quiet)) {
+ return 1;
+ }
+ return buildTbs(clHand, cert, forCreate, extenFields, quiet,
+ verbose, writeBlobs);
+}
+
+int main(int argc, char **argv)
+{
+ CSSM_BOOL quiet = CSSM_FALSE;
+ CSSM_BOOL verbose = CSSM_FALSE;
+ CSSM_BOOL writeBlobs = CSSM_FALSE;
+ CSSM_BOOL allowExpired = CSSM_FALSE;
+ CSSM_BOOL useTrustSettings = CSSM_FALSE;
+
+ for(int arg=1; arg<argc; arg++) {
+ switch(argv[arg][0]) {
+ case 'q':
+ quiet = CSSM_TRUE;
+ break;
+ case 'v':
+ verbose = CSSM_TRUE;
+ break;
+ case 'w':
+ writeBlobs = CSSM_TRUE;
+ break;
+ case 't':
+ useTrustSettings = CSSM_TRUE;
+ break;
+ case 'e':
+ allowExpired = CSSM_TRUE;
+ break;
+ default:
+ usage(argv);
+ }
+ }
+
+ printf("Starting anchorTest; args: ");
+ for(int i=1; i<argc; i++) {
+ printf("%s ", argv[i]);
+ }
+ printf("\n");
+
+ /* get system anchors only; convert to CSSM */
+ CFArrayRef cfAnchors;
+ OSStatus ortn;
+ CSSM_DATA *anchors;
+ unsigned numAnchors;
+ ortn = getSystemAnchors(&cfAnchors, &anchors, &numAnchors);
+ if(ortn) {
+ exit(1);
+ }
+ if(numAnchors < 50) {
+ printf("***Hey! I can only find %u anchors; there should be way more than that.\n",
+ numAnchors);
+ exit(1);
+ }
+
+ CSSM_CL_HANDLE clHand = clStartup();
+ CSSM_TP_HANDLE tpHand = tpStartup();
+ CSSM_CSP_HANDLE cspHand = cspStartup();
+ if((clHand == 0) || (tpHand == 0) || (cspHand == 0)) {
+ return 0;
+ }
+
+ int rtn = 0;
+ for(unsigned dex=0; dex<numAnchors; dex++) {
+ if(!quiet) {
+ printf("...anchor %u\n", dex);
+ }
+ rtn = doTest(clHand, tpHand, cspHand, anchors[dex], allowExpired,
+ quiet, verbose, writeBlobs, useTrustSettings);
+ if(rtn) {
+ break;
+ }
+ }
+ if(rtn == 0) {
+ if(!quiet) {
+ printf("...%s success.\n", argv[0]);
+ }
+ }
+ return rtn;
+}