]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/ocspdTool/ocspdTool.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / ocspdTool / ocspdTool.cpp
1 /*
2 * Copyright (c) 2004-2005,2008 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * ocspdTool.cpp - basic ocspdtool
25 *
26 * Created 11 July 2004 by Doug Mitchell.
27 */
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <utilLib/common.h>
32 #include <Security/Security.h>
33 #include <security_ocspd/ocspdDbSchema.h>
34 #include <security_ocspd/ocspdUtils.h>
35 #include <security_ocspd/ocspdClient.h>
36 #include <security_cdsa_utils/cuCdsaUtils.h>
37 #include <security_cdsa_utils/cuTimeStr.h>
38 #include <Security/SecAsn1Coder.h>
39 #include <Security/ocspTemplates.h>
40
41 static void usage(char **argv)
42 {
43 printf("Usage: op [option..]\n");
44 printf("Ops:\n");
45 printf(" d dump database\n");
46 printf(" f flush stale entries\n");
47 printf(" F flush ALL\n");
48 printf("Options:\n");
49 printf(" TBD\n");
50 exit(1);
51 }
52
53 #define OCSP_DB_FILE "/private/var/db/crls/ocspcache.db"
54
55 static CSSM_DL_DB_HANDLE dlDbHandle = {0, 0};
56
57 static CSSM_API_MEMORY_FUNCS memFuncs = {
58 cuAppMalloc,
59 cuAppFree,
60 cuAppRealloc,
61 cuAppCalloc,
62 NULL
63 };
64
65 static CSSM_VERSION vers = {2, 0};
66
67
68 static CSSM_RETURN dlAttach()
69 {
70 if(dlDbHandle.DLHandle != 0) {
71 return CSSM_OK;
72 }
73 if(cuCssmStartup() == CSSM_FALSE) {
74 return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
75 }
76 CSSM_RETURN crtn = CSSM_ModuleLoad(&gGuidAppleFileDL,
77 CSSM_KEY_HIERARCHY_NONE,
78 NULL, // eventHandler
79 NULL); // AppNotifyCallbackCtx
80 if(crtn) {
81 return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
82 }
83 crtn = CSSM_ModuleAttach (&gGuidAppleFileDL,
84 &vers,
85 &memFuncs, // memFuncs
86 0, // SubserviceID
87 CSSM_SERVICE_DL,
88 0, // AttachFlags
89 CSSM_KEY_HIERARCHY_NONE,
90 NULL, // FunctionTable
91 0, // NumFuncTable
92 NULL, // reserved
93 &dlDbHandle.DLHandle);
94 if(crtn) {
95 return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
96 }
97 return CSSM_OK;
98 }
99
100 static CSSM_RETURN dbAttach(const char *dbFile)
101 {
102 CSSM_RETURN crtn = dlAttach();
103 if(crtn) {
104 return crtn;
105 }
106 if(dlDbHandle.DBHandle != 0) {
107 return CSSM_OK;
108 }
109 return CSSM_DL_DbOpen(dlDbHandle.DLHandle,
110 dbFile,
111 NULL, // DbLocation
112 CSSM_DB_ACCESS_READ,
113 NULL, // CSSM_ACCESS_CREDENTIALS *AccessCred
114 NULL, // void *OpenParameters
115 &dlDbHandle.DBHandle);
116 }
117
118 static const char *months[] = {
119 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
120 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
121 };
122
123 static void printTimeStr(const CSSM_DATA *cssmTime)
124 {
125 struct tm tm;
126
127 /* ignore cssmTime->timeType for now */
128 if(cuTimeStringToTm((char *)cssmTime->Data, cssmTime->Length, &tm)) {
129 printf("***Bad time string format***\n");
130 return;
131 }
132 if(tm.tm_mon > 11) {
133 printf("***Bad time string format***\n");
134 return;
135 }
136 printf("%02d:%02d:%02d %s %d, %04d\n",
137 tm.tm_hour, tm.tm_min, tm.tm_sec,
138 months[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900);
139
140 }
141
142 static void freeAttrData(
143 CSSM_DB_ATTRIBUTE_DATA *attrData,
144 unsigned numAttrs)
145 {
146 if(attrData == NULL) {
147 return;
148 }
149 for(unsigned dex=0; dex<numAttrs; dex++) {
150 CSSM_DB_ATTRIBUTE_DATA *a = &attrData[dex];
151 if(a->Value == NULL) {
152 continue;
153 }
154 for(unsigned i=0; i<a->NumberOfValues; i++) {
155 CSSM_DATA_PTR d = &a->Value[i];
156 if(d->Data) {
157 APP_FREE(d->Data);
158 }
159 }
160 APP_FREE(a->Value);
161 }
162 }
163
164 static void printString(
165 const char *title,
166 const CSSM_DATA *str)
167 {
168 unsigned i;
169 printf("%s: %lu bytes: ", title, str ? str->Length : 0);
170 if((str == NULL) || (str->Length == 0)) {
171 printf("Empty\n");
172 return;
173 }
174 char *cp = (char *)str->Data;
175 for(i=0; i<str->Length; i++) {
176 printf("%c", *cp++);
177 }
178 printf("\n");
179 }
180
181 static void printData(
182 const char *title,
183 const CSSM_DATA *d)
184 {
185 printf("%s: %lu bytes: ", title, d ? d->Length : 0);
186 if((d == NULL) || (d->Length == 0)) {
187 printf("Empty\n");
188 return;
189 }
190 unsigned toPrint = 20;
191 bool ellipsis = false;
192 if(d->Length < toPrint) {
193 toPrint = d->Length;
194 }
195 else if(d->Length > toPrint) {
196 ellipsis = true;
197 }
198 for(unsigned dex=0; dex<toPrint; dex++) {
199 printf("%02X", d->Data[dex]);
200 if((dex % 4) == 3) {
201 printf(" ");
202 }
203 }
204 if(ellipsis) {
205 printf("...\n");
206 }
207 else {
208 printf("\n");
209 }
210 }
211
212 static void printCertID(
213 const CSSM_DATA &certID)
214 {
215 SecAsn1CoderRef coder;
216 SecAsn1CoderCreate(&coder);
217 SecAsn1OCSPCertID asn1CertID;
218 memset(&asn1CertID, 0, sizeof(SecAsn1OCSPCertID));
219 if(SecAsn1DecodeData(coder, &certID, kSecAsn1OCSPCertIDTemplate, &asn1CertID)) {
220 printf("***ERROR decoding stored CertID\n");
221 return;
222 }
223
224 printf(" --- Parsed CertID ---\n");
225 printf(" "); printData("issuerNameHash ", &asn1CertID.issuerNameHash);
226 printf(" "); printData("issuerPubKeyHash", &asn1CertID.issuerPubKeyHash);
227 printf(" "); printData("serialNumber ", &asn1CertID.serialNumber);
228 SecAsn1CoderRelease(coder);
229 }
230 static void printRecord(
231 const CSSM_DB_ATTRIBUTE_DATA *attrData,
232 unsigned numAttrs,
233 const CSSM_DATA *recordData)
234 {
235 printf("===== printRecord: %u attributes, %lu bytes of data =====\n", numAttrs,
236 recordData ? recordData->Length : 0);
237 for(unsigned dex=0; dex<numAttrs; dex++) {
238 const CSSM_DB_ATTRIBUTE_DATA *a = &attrData[dex];
239 char *attrName = a->Info.Label.AttributeName;
240 CSSM_DB_ATTRIBUTE_FORMAT form = a->Info.AttributeFormat;
241 if(a->NumberOfValues == 0) {
242 printf("++++++++ zero values for attribute %s ++++++++\n", attrName);
243 }
244 for(unsigned v=0; v<a->NumberOfValues; v++) {
245 if(!memcmp(attrName, "Expiration", 10)) {
246 const CSSM_DATA *td = &a->Value[v];
247 printf("Expiration: ");
248 printTimeStr(td);
249 }
250 else {
251 switch(form) {
252 case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
253 printString(attrName, &a->Value[v]);
254 break;
255 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
256 printData(attrName, &a->Value[v]);
257 break;
258 default:
259 printf("Help! How do you print format %u\n", (unsigned)form);
260 break;
261 }
262 if(!memcmp(attrName, "CertID", 6)) {
263 printCertID(a->Value[v]);
264 }
265 }
266 }
267 }
268 }
269
270 static void dumpOcspdDb(char *dbFile)
271 {
272 CSSM_QUERY query;
273 CSSM_DB_UNIQUE_RECORD_PTR recordPtr = NULL;
274 CSSM_RETURN crtn;
275 CSSM_HANDLE resultHand;
276 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
277 CSSM_DATA recordData = {0, NULL};
278 CSSM_DB_ATTRIBUTE_DATA attrData[OCSPD_NUM_DB_ATTRS];
279 CSSM_DB_ATTRIBUTE_INFO certIDInfo = OCSPD_DBATTR_CERT_ID ;
280 CSSM_DB_ATTRIBUTE_INFO uriInfo = OCSPD_DBATTR_URI ;
281 CSSM_DB_ATTRIBUTE_INFO expireInfo = OCSPD_DBATTR_EXPIRATION ;
282
283 if(dbAttach(dbFile)) {
284 printf("***Error opening %s. Aborting.\n", dbFile);
285 return;
286 }
287
288 recordAttrs.DataRecordType = OCSPD_DB_RECORDTYPE;
289 recordAttrs.NumberOfAttributes = OCSPD_NUM_DB_ATTRS;
290 recordAttrs.AttributeData = attrData;
291 attrData[0].Info = certIDInfo;
292 attrData[1].Info = uriInfo;
293 attrData[2].Info = expireInfo;
294
295 /* just search by recordType, no predicates */
296 query.RecordType = OCSPD_DB_RECORDTYPE;
297 query.Conjunctive = CSSM_DB_NONE;
298 query.NumSelectionPredicates = 0;
299 query.SelectionPredicate = NULL;
300 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
301 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
302 query.QueryFlags = CSSM_QUERY_RETURN_DATA;
303
304 crtn = CSSM_DL_DataGetFirst(dlDbHandle,
305 &query,
306 &resultHand,
307 &recordAttrs,
308 &recordData,
309 &recordPtr);
310 switch(crtn) {
311 case CSSM_OK:
312 break; // proceed
313 case CSSMERR_DL_ENDOFDATA:
314 printf("***No records found in %s.\n", dbFile);
315 /* OK, no certs */
316 return;
317 default:
318 printError("DataGetFirst", crtn);
319 return;
320 }
321
322 printRecord(attrData, OCSPD_NUM_DB_ATTRS, &recordData);
323 freeAttrData(attrData, 3);
324 CSSM_DL_FreeUniqueRecord(dlDbHandle, recordPtr);
325 if(recordData.Data) {
326 APP_FREE(recordData.Data);
327 recordData.Data = NULL;
328 }
329
330 /* now the rest of them */
331 for(;;) {
332 crtn = CSSM_DL_DataGetNext(dlDbHandle,
333 resultHand,
334 &recordAttrs,
335 NULL,
336 &recordPtr);
337 switch(crtn) {
338 case CSSM_OK:
339 printRecord(attrData, OCSPD_NUM_DB_ATTRS, &recordData);
340 freeAttrData(attrData, 3);
341 CSSM_DL_FreeUniqueRecord(dlDbHandle, recordPtr);
342 if(recordData.Data) {
343 APP_FREE(recordData.Data);
344 recordData.Data = NULL;
345 }
346 break; // and go again
347 case CSSMERR_DL_ENDOFDATA:
348 /* normal termination */
349 break;
350 default:
351 printError("DataGetNext", crtn);
352 return;
353 }
354 if(crtn != CSSM_OK) {
355 break;
356 }
357 }
358 CSSM_DL_DataAbortQuery(dlDbHandle, resultHand);
359 return;
360 }
361
362 static void cleanOcspdDb(char *dbFile)
363 {
364 CSSM_QUERY query;
365 CSSM_DB_UNIQUE_RECORD_PTR recordPtr = NULL;
366 CSSM_RETURN crtn;
367 CSSM_HANDLE resultHand;
368 unsigned numRecords = 0;
369
370 if(dbAttach(dbFile)) {
371 printf("***Error opening %s. Aborting.\n", dbFile);
372 return;
373 }
374
375 /* just search by recordType, no predicates, no returned attrs, no returned data*/
376 query.RecordType = OCSPD_DB_RECORDTYPE;
377 query.Conjunctive = CSSM_DB_NONE;
378 query.NumSelectionPredicates = 0;
379 query.SelectionPredicate = NULL;
380 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
381 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
382 query.QueryFlags = 0;
383
384 crtn = CSSM_DL_DataGetFirst(dlDbHandle,
385 &query,
386 &resultHand,
387 NULL,
388 NULL,
389 &recordPtr);
390 switch(crtn) {
391 case CSSM_OK:
392 break; // proceed
393 case CSSMERR_DL_ENDOFDATA:
394 printf("***No records found in %s.\n", dbFile);
395 /* OK, no certs */
396 return;
397 default:
398 printError("DataGetFirst", crtn);
399 return;
400 }
401
402 crtn = CSSM_DL_DataDelete(dlDbHandle, recordPtr);
403 if(crtn) {
404 cssmPerror("CSSM_DL_DataDelete", crtn);
405 }
406 CSSM_DL_FreeUniqueRecord(dlDbHandle, recordPtr);
407 if(crtn) {
408 return;
409 }
410 numRecords++;
411
412 /* now the rest of them */
413 for(;;) {
414 crtn = CSSM_DL_DataGetNext(dlDbHandle,
415 resultHand,
416 NULL,
417 NULL,
418 &recordPtr);
419 switch(crtn) {
420 case CSSM_OK:
421 crtn = CSSM_DL_DataDelete(dlDbHandle, recordPtr);
422 if(crtn) {
423 cssmPerror("CSSM_DL_DataDelete", crtn);
424 }
425 CSSM_DL_FreeUniqueRecord(dlDbHandle, recordPtr);
426 if(crtn) {
427 return;
428 }
429 numRecords++;
430 break; // and go again
431 case CSSMERR_DL_ENDOFDATA:
432 /* normal termination */
433 break;
434 default:
435 printError("DataGetNext", crtn);
436 return;
437 }
438 if(crtn != CSSM_OK) {
439 break;
440 }
441 }
442 CSSM_DL_DataAbortQuery(dlDbHandle, resultHand);
443 printf("...%u records deleted\n", numRecords);
444 return;
445 }
446
447 int main(int argc, char **argv)
448 {
449 if(argc < 2) {
450 usage(argv);
451 }
452
453 extern int optind;
454 // extern char *optarg;
455 int arg;
456
457 optind = 2;
458 while ((arg = getopt(argc, argv, "h")) != -1) {
459 switch (arg) {
460 case 'h':
461 case '?':
462 default:
463 usage(argv);
464 }
465 }
466 if(optind != argc) {
467 usage(argv);
468 }
469 switch (argv[1][0]) {
470 case 'd':
471 dumpOcspdDb((char *)OCSP_DB_FILE);
472 break;
473 case 'f':
474 ocspdCacheFlushStale();
475 printf("...stale entries flushed\n");
476 break;
477 case 'F':
478 cleanOcspdDb((char *)OCSP_DB_FILE);
479 break;
480 default:
481 usage(argv);
482 }
483 return 0;
484 }
485