1/*
2 * certsFromDb.cpp - extract all certs from a DB, write to files or parse to stdout.
3 */
4#include <security_cdsa_utils/cuFileIo.h>
5#include <utilLib/common.h>
6#include <utilLib/cspwrap.h>
7#include <security_cdsa_utils/cuPrintCert.h>
8#include <stdlib.h>
9#include <stdio.h>
10#include <string.h>
11#include <Security/cssm.h>
12#include <string.h>
13
14static void usage(char **argv)
15{
16	printf("Usage: \n");
17	printf("   %s keychainFile f certFileBase [option...]\n", argv[0]);
18	printf("   %s keychainFile p(arse) [option...]\n", argv[0]);
19	printf("Options:\n");
20	printf("   R   fetch CRLs, not certs\n");
21	printf("   P   pause for MallocDebug one each item\n");
22	printf("   q   Quiet\n");
23	exit(1);
24}
25
26int main(int argc, char **argv)
27{
28	int 						rtn;
29	CSSM_DL_DB_HANDLE			dlDbHand;
30	CSSM_RETURN 				crtn;
31	char 						filePath[300];
32	unsigned 					certNum=0;
33	CSSM_QUERY					query;
34	CSSM_DB_UNIQUE_RECORD_PTR	record = NULL;
35	CSSM_HANDLE 				resultHand;
36	CSSM_DATA					theData = {0, NULL};
37	char						*fileBase = NULL;
38	CSSM_BOOL					doPause = CSSM_FALSE;
39    CSSM_BOOL					isCrl = CSSM_FALSE;
40	CSSM_BOOL					quiet = CSSM_FALSE;
41	int							optarg = 3;
42
43	if(argc < 3) {
44		usage(argv);
45	}
46	switch(argv[2][0]) {
47		case 'f':
48			if(argc < 4) {
49				usage(argv);
50			}
51			fileBase = argv[3];
52			optarg = 4;
53			break;
54		case 'p':
55			/* default, parse mode */
56			break;
57		default:
58			usage(argv);
59	}
60	for(int arg=optarg; arg<argc; arg++) {
61		switch(argv[arg][0]) {
62			case 'q':
63				quiet = CSSM_TRUE;
64				break;
65			case 'P':
66				doPause = CSSM_TRUE;
67				break;
68			case 'R':
69				isCrl = CSSM_TRUE;
70				break;
71			default:
72				usage(argv);
73		}
74	}
75
76	/* attach to specified keychain as a DL/DB */
77	dlDbHand.DLHandle = dlStartup();
78	if(dlDbHand.DLHandle == 0) {
79		exit(1);
80	}
81	crtn = dbCreateOpen(dlDbHand.DLHandle, argv[1],
82		CSSM_FALSE, 		// doCreate
83		CSSM_FALSE,			// deleteExist
84		NULL,				// pwd
85		&dlDbHand.DBHandle);
86	if(crtn) {
87		exit(1);
88	}
89
90loopTop:
91	/* search by record type, no predicates, no returned attributes. We just want
92	 * the data. */
93	query.RecordType = isCrl ? CSSM_DL_DB_RECORD_X509_CRL :
94			CSSM_DL_DB_RECORD_X509_CERTIFICATE;
95	query.Conjunctive = CSSM_DB_NONE;
96	query.NumSelectionPredicates = 0;
97	query.SelectionPredicate = NULL;
98	query.QueryLimits.TimeLimit = 0;	// FIXME - meaningful?
99	query.QueryLimits.SizeLimit = 1;	// FIXME - meaningful?
100	query.QueryFlags = CSSM_QUERY_RETURN_DATA;	// FIXME - used?
101
102	crtn = CSSM_DL_DataGetFirst(dlDbHand,
103		&query,
104		&resultHand,
105		NULL,
106		&theData,
107		&record);
108	if(crtn) {
109		printError("CSSM_DL_DataGetFirst", crtn);
110		printf("Error fetching certs from %s. Aborting.\n", argv[1]);
111		exit(1);
112	}
113	CSSM_DL_FreeUniqueRecord(dlDbHand, record);
114
115    if(doPause) {
116        fpurge(stdin);
117        printf("set up MallocDebug, then any key to continue: ");
118		getchar();
119    }
120	if(fileBase) {
121		/* write the data */
122		sprintf(filePath, "%s_%d", fileBase, certNum);
123		rtn = writeFile(filePath, theData.Data, theData.Length);
124		if(rtn == 0) {
125			if(!quiet) {
126				printf("...wrote %u bytes to %s\n", (unsigned)theData.Length,
127					filePath);
128			}
129		}
130		else {
131			printf("***Error writing %s: %s\n", filePath, strerror(rtn));
132			exit(1);
133		}
134	}
135	else {
136		if(isCrl) {
137			printf("CRL 0:\n");
138			printCrl(theData.Data, theData.Length, CSSM_FALSE);
139		}
140		else {
141			printf("Cert 0:\n");
142			printCert(theData.Data, theData.Length, CSSM_FALSE);
143		}
144	}
145	CSSM_FREE(theData.Data);
146	certNum++;
147
148	/* again */
149	for(;;) {
150		crtn = CSSM_DL_DataGetNext(dlDbHand,
151			resultHand,
152			NULL,
153			&theData,
154			&record);
155		switch(crtn) {
156			case CSSM_OK:
157				if(fileBase) {
158					sprintf(filePath, "%s_%d", fileBase, certNum);
159					rtn = writeFile(filePath, theData.Data, theData.Length);
160					if(rtn == 0) {
161						if(!quiet) {
162							printf("...wrote %u bytes to %s\n", (unsigned)theData.Length,
163								filePath);
164						}
165					}
166					else {
167						printf("***Error writing %s: %s\n", filePath, strerror(rtn));
168						exit(1);
169					}
170				}
171				else {
172					if(isCrl) {
173						printf("CRL 0:\n");
174						printCrl(theData.Data, theData.Length, CSSM_FALSE);
175					}
176					else {
177						printf("Cert %u:\n", certNum);
178						printCert(theData.Data, theData.Length, CSSM_FALSE);
179					}
180				}
181				certNum++;
182				CSSM_FREE(theData.Data);
183				CSSM_DL_FreeUniqueRecord(dlDbHand, record);
184				break;		// and go again
185			case CSSMERR_DL_ENDOFDATA:
186				/* normal termination */
187				break;
188			default:
189				printError("DataGetNext", crtn);
190				break;
191		}
192		if(crtn != CSSM_OK) {
193			break;
194		}
195	}
196	CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
197    if(doPause) {
198        fpurge(stdin);
199        printf("End of loop, l to loop, enything else to end: ");
200		char c = getchar();
201        if(c == 'l') {
202            goto loopTop;
203        }
204    }
205	if(!quiet) {
206		printf("...%d %s extracted.\n", certNum, isCrl ? "CRLs" : "certs");
207	}
208	return 0;
209}
210
211