1/*
2 * userTrustTest.cpp - simple test of SecTrustSetUserTrustLegacy() and
3 *					   SecTrustGetUserTrust()
4 */
5
6#include <stdlib.h>
7#include <strings.h>
8#include <stdio.h>
9#include <unistd.h>
10#include <Security/Security.h>
11#include <Security/SecTrustPriv.h>
12#include <Security/SecPolicyPriv.h>
13#include <clAppUtils/tpUtils.h>
14#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
15
16#define IGNORE_EXISTING_STATE		0
17
18static void usage(char **argv)
19{
20	printf("usage: %s [options] known_good_leaf_cert [ca_cert...]\n", argv[0]);
21	printf("Options:\n");
22	printf("  -q              -- quiet\n");
23	exit(1);
24}
25
26static char *secTrustResultStr(
27	SecTrustResultType result)
28{
29	static char unknownStr[100];
30
31	switch(result) {
32		case kSecTrustResultInvalid: return "kSecTrustResultInvalid";
33		case kSecTrustResultProceed: return "kSecTrustResultProceed";
34		case kSecTrustResultConfirm: return "kSecTrustResultConfirm";
35		case kSecTrustResultDeny:    return "kSecTrustResultDeny";
36		case kSecTrustResultUnspecified: return "kSecTrustResultUnspecified";
37		case kSecTrustResultRecoverableTrustFailure:
38			return "kSecTrustResultRecoverableTrustFailure";
39		case kSecTrustResultFatalTrustFailure: return "kSecTrustResultFatalTrustFailure";
40		case kSecTrustResultOtherError: return "kSecTrustResultOtherError";
41		default:
42			sprintf(unknownStr, "UNKNOWN ResultType (%d)\n",
43				(int)result);
44			return unknownStr;
45	}
46}
47
48/* do a SecTrustEvaluate, ensure resultType is as specified */
49static int doEval(
50	CFArrayRef certs,
51	SecPolicyRef policy,
52	SecTrustResultType expectedResult,
53	bool quiet)
54{
55	OSStatus ortn;
56	SecTrustRef trustRef = NULL;
57	SecTrustResultType result;
58	int ourRtn = 0;
59
60	ortn = SecTrustCreateWithCertificates(certs, policy, &trustRef);
61	if(ortn) {
62		cssmPerror("SecTrustCreateWithCertificates", ortn);
63		return -1;
64	}
65	ortn = SecTrustEvaluate(trustRef, &result);
66	if(ortn) {
67		/* shouldn't fail no matter what resultType we expect */
68		cssmPerror("SecTrustEvaluate", ortn);
69		ourRtn = -1;
70		goto errOut;
71	}
72	if(expectedResult == result) {
73		if(!quiet) {
74			printf("...got %s as expected\n", secTrustResultStr(result));
75		}
76	}
77	else {
78		printf("***Expected %s, got %s\n", secTrustResultStr(expectedResult),
79			secTrustResultStr(result));
80		ourRtn = -1;
81	}
82errOut:
83	CFRelease(trustRef);
84	return ourRtn;
85}
86
87/* Do a SecTrustGetUserTrust(), ensure result is as specified */
88static int doGetUserTrust(
89	SecCertificateRef certRef,
90	SecPolicyRef policy,
91	SecTrustResultType expectedResult)
92{
93	SecTrustResultType foundResult;
94	OSStatus ortn = SecTrustGetUserTrust(certRef, policy, &foundResult);
95	if(ortn) {
96		cssmPerror("SecTrustGetUserTrust", ortn);
97		return -1;
98	}
99	if(foundResult != expectedResult) {
100		printf("***Expected current resultType %s; found %s\n",
101			secTrustResultStr(expectedResult), secTrustResultStr(foundResult));
102		return -1;
103	}
104	return 0;
105}
106
107/* Do SecTrustSetUserTrustLegacy() followed by SecTrustGetUserTrust() */
108static int doSetVerifyUserTrust(
109	SecCertificateRef certRef,
110	SecPolicyRef policy,
111	SecTrustResultType result)
112{
113	OSStatus ortn;
114	ortn = SecTrustSetUserTrustLegacy(certRef, policy, result);
115	if(ortn) {
116		cssmPerror("SecTrustSetUserTrustLegacy", ortn);
117		return -1;
118	}
119	return doGetUserTrust(certRef, policy, result);
120}
121
122static int doTest(
123	CFArrayRef certArray,
124	SecPolicyRef policy,
125	bool quiet)
126{
127	int ourRtn = 0;
128	SecCertificateRef leafCert = (SecCertificateRef)CFArrayGetValueAtIndex(
129		certArray, 0);
130
131	if(!quiet) {
132		printf("Verifying cert is good as is...\n");
133	}
134	ourRtn = doEval(certArray, policy, kSecTrustResultUnspecified, quiet);
135	if(ourRtn && !IGNORE_EXISTING_STATE) {
136		return ourRtn;
137	}
138
139	if(!quiet) {
140		printf("Verifying cert currently has kSecTrustResultUnspecified...\n");
141	}
142	if(doGetUserTrust(leafCert, policy, kSecTrustResultUnspecified)) {
143		ourRtn = -1;
144		/* but keep going */
145	}
146
147	if(!quiet) {
148		printf("setting and verifying SecTrustResultDeny...\n");
149	}
150	if(doSetVerifyUserTrust(leafCert, policy, kSecTrustResultDeny)) {
151		ourRtn = -1;
152	}
153
154	if(!quiet) {
155		printf("Verify cert with SecTrustResultDeny...\n");
156	}
157	ourRtn = doEval(certArray, policy, kSecTrustResultDeny, quiet);
158	if(ourRtn) {
159		ourRtn = -1;
160	}
161
162	if(!quiet) {
163		printf("setting and verifying kSecTrustResultConfirm...\n");
164	}
165	if(doSetVerifyUserTrust(leafCert, policy, kSecTrustResultConfirm)) {
166		ourRtn = -1;
167	}
168
169	if(!quiet) {
170		printf("Verify cert with kSecTrustResultConfirm...\n");
171	}
172	ourRtn = doEval(certArray, policy, kSecTrustResultConfirm, quiet);
173	if(ourRtn) {
174		ourRtn = -1;
175	}
176
177	if(!quiet) {
178		printf("setting and verifying kSecTrustResultUnspecified...\n");
179	}
180	if(doSetVerifyUserTrust(leafCert, policy, kSecTrustResultUnspecified)) {
181		ourRtn = -1;
182	}
183
184	if(!quiet) {
185		printf("Verify cert with kSecTrustResultUnspecified...\n");
186	}
187	ourRtn = doEval(certArray, policy, kSecTrustResultUnspecified, quiet);
188
189	if(!quiet) {
190		printf("Verify SecTrustSetUserTrust(kSecTrustResultConfirm) fails...\n");
191	}
192	/* verify Radar 4642125 - this should fail, not crash */
193	OSStatus ortn = SecTrustSetUserTrust(leafCert, policy, kSecTrustResultConfirm);
194	if(ortn != unimpErr) {
195		printf("***SecTrustSetUserTrust returned %ld; expected %ld (unimpErr)\n",
196			(long)ortn, (long)unimpErr);
197		ourRtn = -1;
198	}
199	return ourRtn;
200}
201
202int main(int argc, char **argv)
203{
204	bool quiet = false;
205
206	int arg;
207	while ((arg = getopt(argc, argv, "qh")) != -1) {
208		switch (arg) {
209			case 'q':
210				quiet = true;
211				break;
212			case 'h':
213				usage(argv);
214		}
215	}
216
217	unsigned numCerts = argc - optind;
218	if(numCerts == 0) {
219		usage(argv);
220	}
221	CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0,
222		&kCFTypeArrayCallBacks);
223	for(int dex=optind; dex<argc; dex++) {
224		SecCertificateRef certRef = certFromFile(argv[dex]);
225		if(certRef == NULL) {
226			exit(1);
227		}
228		CFArrayAppendValue(certArray, certRef);
229		CFRelease(certRef);
230	}
231
232	OSStatus ortn;
233	SecPolicyRef policyRef = NULL;
234	ortn = SecPolicyCopy(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL, &policyRef);
235	if(ortn) {
236		cssmPerror("SecPolicyCopy", ortn);
237		exit(1);
238	}
239
240	int ourRtn = doTest(certArray, policyRef, quiet);
241	CFRelease(policyRef);
242	CFRelease(certArray);
243	return ourRtn;
244}
245