Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / cmd / vfychain / vfychain.c
blob2c85832a3328b75c2cb6b6cebc0ad764cb80672e
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 /****************************************************************************
38 * Read in a cert chain from one or more files, and verify the chain for
39 * some usage.
40 * *
41 * This code was modified from other code also kept in the NSS directory.
42 ****************************************************************************/
44 #include <stdio.h>
45 #include <string.h>
47 #if defined(XP_UNIX)
48 #include <unistd.h>
49 #endif
51 #include "prerror.h"
53 #include "nssrenam.h"
54 #include "pk11func.h"
55 #include "seccomon.h"
56 #include "secutil.h"
57 #include "secmod.h"
58 #include "secitem.h"
59 #include "cert.h"
62 /* #include <stdlib.h> */
63 /* #include <errno.h> */
64 /* #include <fcntl.h> */
65 /* #include <stdarg.h> */
67 #include "nspr.h"
68 #include "plgetopt.h"
69 #include "prio.h"
70 #include "nss.h"
72 /* #include "vfyutil.h" */
74 #define RD_BUF_SIZE (60 * 1024)
76 int verbose;
78 char *password = NULL;
80 /* Function: char * myPasswd()
82 * Purpose: This function is our custom password handler that is called by
83 * SSL when retreiving private certs and keys from the database. Returns a
84 * pointer to a string that with a password for the database. Password pointer
85 * should point to dynamically allocated memory that will be freed later.
87 char *
88 myPasswd(PK11SlotInfo *info, PRBool retry, void *arg)
90 char * passwd = NULL;
92 if ( (!retry) && arg ) {
93 passwd = PORT_Strdup((char *)arg);
95 return passwd;
98 static void
99 Usage(const char *progName)
101 fprintf(stderr,
102 "Usage: %s [options] certfile [[options] certfile] ...\n"
103 "\twhere options are:\n"
104 "\t-a\t\t following certfile is base64 encoded\n"
105 "\t-b YYMMDDHHMMZ\t Validate date (default: now)\n"
106 "\t-d directory\t Database directory\n"
107 "\t-r\t\t following certfile is raw binary DER (default)\n"
108 "\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n"
109 "\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n"
110 "\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA\n"
111 "\t-v\t\t verbose mode\n"
112 "\t-w password\t Database password\n",
113 progName);
114 exit(1);
117 /**************************************************************************
119 ** Error and information routines.
121 **************************************************************************/
123 void
124 errWarn(char *function)
126 PRErrorCode errorNumber = PR_GetError();
127 const char * errorString = SECU_Strerror(errorNumber);
129 fprintf(stderr, "Error in function %s: %d\n - %s\n",
130 function, errorNumber, errorString);
133 void
134 exitErr(char *function)
136 errWarn(function);
137 /* Exit gracefully. */
138 /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/
139 (void) NSS_Shutdown();
140 PR_Cleanup();
141 exit(1);
144 typedef struct certMemStr {
145 struct certMemStr * next;
146 CERTCertificate * cert;
147 } certMem;
149 certMem * theCerts;
151 void
152 rememberCert(CERTCertificate * cert)
154 certMem * newCertMem = PORT_ZNew(certMem);
155 if (newCertMem) {
156 newCertMem->next = theCerts;
157 newCertMem->cert = cert;
158 theCerts = newCertMem;
162 void
163 forgetCerts(void)
165 certMem * oldCertMem;
166 while (oldCertMem = theCerts) {
167 theCerts = oldCertMem->next;
168 CERT_DestroyCertificate(oldCertMem->cert);
169 PORT_Free(oldCertMem);
171 theCerts = NULL;
175 CERTCertificate *
176 readCertFile(const char * fileName, PRBool isAscii)
178 unsigned char * pb;
179 CERTCertificate * cert = NULL;
180 CERTCertDBHandle *defaultDB = NULL;
181 PRFileDesc* fd;
182 PRInt32 cc = -1;
183 PRInt32 total;
184 PRInt32 remaining;
185 SECItem item;
186 static unsigned char certBuf[RD_BUF_SIZE];
188 fd = PR_Open(fileName, PR_RDONLY, 0777);
189 if (!fd) {
190 PRIntn err = PR_GetError();
191 fprintf(stderr, "open of %s failed, %d = %s\n",
192 fileName, err, SECU_Strerror(err));
193 return cert;
195 /* read until EOF or buffer is full */
196 pb = certBuf;
197 while (0 < (remaining = (sizeof certBuf) - (pb - certBuf))) {
198 cc = PR_Read(fd, pb, remaining);
199 if (cc == 0)
200 break;
201 if (cc < 0) {
202 PRIntn err = PR_GetError();
203 fprintf(stderr, "read of %s failed, %d = %s\n",
204 fileName, err, SECU_Strerror(err));
205 break;
207 /* cc > 0 */
208 pb += cc;
210 PR_Close(fd);
211 if (cc < 0)
212 return cert;
213 if (!remaining || cc > 0) { /* file was too big. */
214 fprintf(stderr, "cert file %s was too big.\n", fileName);
215 return cert;
217 total = pb - certBuf;
218 if (!total) { /* file was empty */
219 fprintf(stderr, "cert file %s was empty.\n", fileName);
220 return cert;
222 if (isAscii) {
223 /* convert from Base64 to binary here ... someday */
225 item.type = siBuffer;
226 item.data = certBuf;
227 item.len = total;
228 defaultDB = CERT_GetDefaultCertDB();
229 cert = CERT_NewTempCertificate(defaultDB, &item,
230 NULL /* nickname */,
231 PR_FALSE /* isPerm */,
232 PR_TRUE /* copyDER */);
233 if (!cert) {
234 PRIntn err = PR_GetError();
235 fprintf(stderr, "couldn't import %s, %d = %s\n",
236 fileName, err, SECU_Strerror(err));
238 return cert;
242 main(int argc, char *argv[], char *envp[])
244 char * certDir = NULL;
245 char * progName = NULL;
246 CERTCertificate * cert;
247 CERTCertificate * firstCert = NULL;
248 CERTCertDBHandle * defaultDB = NULL;
249 PRBool isAscii = PR_FALSE;
250 SECStatus secStatus;
251 SECCertificateUsage certUsage = certificateUsageSSLServer;
252 PLOptState * optstate;
253 PRTime time = 0;
254 PLOptStatus status;
255 int rv = 1;
256 int usage;
258 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
260 progName = PL_strdup(argv[0]);
262 optstate = PL_CreateOptState(argc, argv, "ab:d:ru:w:v");
263 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
264 switch(optstate->option) {
265 case 0 : /* positional parameter */ goto breakout;
266 case 'a' : isAscii = PR_TRUE; break;
267 case 'b' : secStatus = DER_AsciiToTime(&time, optstate->value);
268 if (secStatus != SECSuccess) Usage(progName); break;
269 case 'd' : certDir = PL_strdup(optstate->value); break;
270 case 'r' : isAscii = PR_FALSE; break;
271 case 'u' : usage = PORT_Atoi(optstate->value);
272 if (usage < 0 || usage > 62) Usage(progName);
273 certUsage = ((SECCertificateUsage)1) << usage;
274 if (certUsage > certificateUsageHighest) Usage(progName);
275 break;
276 case 'w' : password = PL_strdup(optstate->value); break;
277 case 'v' : verbose++; break;
278 default : Usage(progName); break;
281 breakout:
282 if (status != PL_OPT_OK)
283 Usage(progName);
285 /* Set our password function callback. */
286 PK11_SetPasswordFunc(myPasswd);
288 /* Initialize the NSS libraries. */
289 if (certDir) {
290 secStatus = NSS_Init(certDir);
291 } else {
292 secStatus = NSS_NoDB_Init(NULL);
294 /* load the builtins */
295 SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0);
297 if (secStatus != SECSuccess) {
298 exitErr("NSS_Init");
300 SECU_RegisterDynamicOids();
302 while (status == PL_OPT_OK) {
303 switch(optstate->option) {
304 default : Usage(progName); break;
305 case 'a' : isAscii = PR_TRUE; break;
306 case 'r' : isAscii = PR_FALSE; break;
307 case 0 : /* positional parameter */
308 cert = readCertFile(optstate->value, isAscii);
309 if (!cert)
310 goto punt;
311 rememberCert(cert);
312 if (!firstCert)
313 firstCert = cert;
314 break;
316 status = PL_GetNextOpt(optstate);
318 PL_DestroyOptState(optstate);
319 if (status == PL_OPT_BAD || !firstCert)
320 Usage(progName);
322 if (!time)
323 time = PR_Now();
325 /* NOW, verify the cert chain. */
326 defaultDB = CERT_GetDefaultCertDB();
327 secStatus = CERT_VerifyCertificate(defaultDB, firstCert,
328 PR_TRUE /* check sig */,
329 certUsage,
330 time,
331 NULL, /* wincx */
332 NULL, /* error log */
333 NULL); /* returned usages */
335 if (secStatus != SECSuccess) {
336 PRIntn err = PR_GetError();
337 fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err));
338 SECU_printCertProblemsOnDate(stderr, defaultDB, firstCert,
339 PR_TRUE, certUsage, NULL, verbose, time);
340 rv = 1;
341 } else {
342 fprintf(stderr, "Chain is good!\n");
343 rv = 0;
346 punt:
347 forgetCerts();
348 if (NSS_Shutdown() != SECSuccess) {
349 SECU_PrintError(progName, "NSS_Shutdown");
350 rv = 1;
352 PR_Cleanup();
353 return rv;