|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /* |
|
6 * p7content -- A command to display pkcs7 content. |
|
7 */ |
|
8 |
|
9 #include "nspr.h" |
|
10 #include "secutil.h" |
|
11 #include "plgetopt.h" |
|
12 #include "secpkcs7.h" |
|
13 #include "cert.h" |
|
14 #include "certdb.h" |
|
15 #include "nss.h" |
|
16 #include "pk11pub.h" |
|
17 |
|
18 #if defined(XP_UNIX) |
|
19 #include <unistd.h> |
|
20 #endif |
|
21 |
|
22 #include <stdio.h> |
|
23 #include <string.h> |
|
24 |
|
25 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) |
|
26 extern int fwrite(char *, size_t, size_t, FILE*); |
|
27 extern int fprintf(FILE *, char *, ...); |
|
28 #endif |
|
29 |
|
30 |
|
31 |
|
32 static void |
|
33 Usage(char *progName) |
|
34 { |
|
35 fprintf(stderr, |
|
36 "Usage: %s [-d dbdir] [-i input] [-o output]\n", |
|
37 progName); |
|
38 fprintf(stderr, |
|
39 "%-20s Key/Cert database directory (default is ~/.netscape)\n", |
|
40 "-d dbdir"); |
|
41 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", |
|
42 "-i input"); |
|
43 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", |
|
44 "-o output"); |
|
45 exit(-1); |
|
46 } |
|
47 |
|
48 static PRBool saw_content; |
|
49 static secuPWData pwdata = { PW_NONE, 0 }; |
|
50 |
|
51 static void |
|
52 PrintBytes(void *arg, const char *buf, unsigned long len) |
|
53 { |
|
54 FILE *out; |
|
55 |
|
56 out = arg; |
|
57 fwrite (buf, len, 1, out); |
|
58 |
|
59 saw_content = PR_TRUE; |
|
60 } |
|
61 |
|
62 /* |
|
63 * XXX Someday we may want to do real policy stuff here. This allows |
|
64 * anything to be decrypted, which is okay for a test program but does |
|
65 * not set an example of how a real client with a real policy would |
|
66 * need to do it. |
|
67 */ |
|
68 static PRBool |
|
69 decryption_allowed(SECAlgorithmID *algid, PK11SymKey *key) |
|
70 { |
|
71 return PR_TRUE; |
|
72 } |
|
73 |
|
74 int |
|
75 DecodeAndPrintFile(FILE *out, PRFileDesc *in, char *progName) |
|
76 { |
|
77 SECItem derdata; |
|
78 SEC_PKCS7ContentInfo *cinfo = NULL; |
|
79 SEC_PKCS7DecoderContext *dcx; |
|
80 |
|
81 if (SECU_ReadDERFromFile(&derdata, in, PR_FALSE, PR_FALSE)) { |
|
82 SECU_PrintError(progName, "error converting der"); |
|
83 return -1; |
|
84 } |
|
85 |
|
86 fprintf(out, |
|
87 "Content printed between bars (newline added before second bar):"); |
|
88 fprintf(out, "\n---------------------------------------------\n"); |
|
89 |
|
90 saw_content = PR_FALSE; |
|
91 dcx = SEC_PKCS7DecoderStart(PrintBytes, out, NULL, &pwdata, |
|
92 NULL, NULL, decryption_allowed); |
|
93 if (dcx != NULL) { |
|
94 #if 0 /* Test that decoder works when data is really streaming in. */ |
|
95 { |
|
96 unsigned long i; |
|
97 for (i = 0; i < derdata.len; i++) |
|
98 SEC_PKCS7DecoderUpdate(dcx, derdata.data + i, 1); |
|
99 } |
|
100 #else |
|
101 SEC_PKCS7DecoderUpdate(dcx, (char *)derdata.data, derdata.len); |
|
102 #endif |
|
103 cinfo = SEC_PKCS7DecoderFinish(dcx); |
|
104 } |
|
105 |
|
106 fprintf(out, "\n---------------------------------------------\n"); |
|
107 |
|
108 if (cinfo == NULL) |
|
109 return -1; |
|
110 |
|
111 fprintf(out, "Content was%s encrypted.\n", |
|
112 SEC_PKCS7ContentIsEncrypted(cinfo) ? "" : " not"); |
|
113 |
|
114 if (SEC_PKCS7ContentIsSigned(cinfo)) { |
|
115 char *signer_cname, *signer_ename; |
|
116 SECItem *signing_time; |
|
117 |
|
118 if (saw_content) { |
|
119 fprintf(out, "Signature is "); |
|
120 PORT_SetError(0); |
|
121 if (SEC_PKCS7VerifySignature(cinfo, certUsageEmailSigner, PR_FALSE)) |
|
122 fprintf(out, "valid.\n"); |
|
123 else |
|
124 fprintf(out, "invalid (Reason: %s).\n", |
|
125 SECU_Strerror(PORT_GetError())); |
|
126 } else { |
|
127 fprintf(out, |
|
128 "Content is detached; signature cannot be verified.\n"); |
|
129 } |
|
130 |
|
131 signer_cname = SEC_PKCS7GetSignerCommonName(cinfo); |
|
132 if (signer_cname != NULL) { |
|
133 fprintf(out, "The signer's common name is %s\n", signer_cname); |
|
134 PORT_Free(signer_cname); |
|
135 } else { |
|
136 fprintf(out, "No signer common name.\n"); |
|
137 } |
|
138 |
|
139 signer_ename = SEC_PKCS7GetSignerEmailAddress(cinfo); |
|
140 if (signer_ename != NULL) { |
|
141 fprintf(out, "The signer's email address is %s\n", signer_ename); |
|
142 PORT_Free(signer_ename); |
|
143 } else { |
|
144 fprintf(out, "No signer email address.\n"); |
|
145 } |
|
146 |
|
147 signing_time = SEC_PKCS7GetSigningTime(cinfo); |
|
148 if (signing_time != NULL) { |
|
149 SECU_PrintTimeChoice(out, signing_time, "Signing time", 0); |
|
150 } else { |
|
151 fprintf(out, "No signing time included.\n"); |
|
152 } |
|
153 } else { |
|
154 fprintf(out, "Content was not signed.\n"); |
|
155 } |
|
156 |
|
157 fprintf(out, "There were%s certs or crls included.\n", |
|
158 SEC_PKCS7ContainsCertsOrCrls(cinfo) ? "" : " no"); |
|
159 |
|
160 SEC_PKCS7DestroyContentInfo(cinfo); |
|
161 return 0; |
|
162 } |
|
163 |
|
164 /* |
|
165 * Print the contents of a PKCS7 message, indicating signatures, etc. |
|
166 */ |
|
167 |
|
168 int |
|
169 main(int argc, char **argv) |
|
170 { |
|
171 char *progName; |
|
172 FILE *outFile; |
|
173 PRFileDesc *inFile; |
|
174 PLOptState *optstate; |
|
175 PLOptStatus status; |
|
176 SECStatus rv; |
|
177 |
|
178 progName = strrchr(argv[0], '/'); |
|
179 progName = progName ? progName+1 : argv[0]; |
|
180 |
|
181 inFile = NULL; |
|
182 outFile = NULL; |
|
183 |
|
184 /* |
|
185 * Parse command line arguments |
|
186 */ |
|
187 optstate = PL_CreateOptState(argc, argv, "d:i:o:p:f:"); |
|
188 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
|
189 switch (optstate->option) { |
|
190 case 'd': |
|
191 SECU_ConfigDirectory(optstate->value); |
|
192 break; |
|
193 |
|
194 case 'i': |
|
195 inFile = PR_Open(optstate->value, PR_RDONLY, 0); |
|
196 if (!inFile) { |
|
197 fprintf(stderr, "%s: unable to open \"%s\" for reading\n", |
|
198 progName, optstate->value); |
|
199 return -1; |
|
200 } |
|
201 break; |
|
202 |
|
203 case 'o': |
|
204 outFile = fopen(optstate->value, "w"); |
|
205 if (!outFile) { |
|
206 fprintf(stderr, "%s: unable to open \"%s\" for writing\n", |
|
207 progName, optstate->value); |
|
208 return -1; |
|
209 } |
|
210 break; |
|
211 |
|
212 case 'p': |
|
213 pwdata.source = PW_PLAINTEXT; |
|
214 pwdata.data = PORT_Strdup (optstate->value); |
|
215 break; |
|
216 |
|
217 case 'f': |
|
218 pwdata.source = PW_FROMFILE; |
|
219 pwdata.data = PORT_Strdup (optstate->value); |
|
220 break; |
|
221 |
|
222 default: |
|
223 Usage(progName); |
|
224 break; |
|
225 } |
|
226 } |
|
227 if (status == PL_OPT_BAD) |
|
228 Usage(progName); |
|
229 |
|
230 if (!inFile) inFile = PR_STDIN; |
|
231 if (!outFile) outFile = stdout; |
|
232 |
|
233 /* Call the initialization routines */ |
|
234 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); |
|
235 rv = NSS_Init(SECU_ConfigDirectory(NULL)); |
|
236 if (rv != SECSuccess) { |
|
237 SECU_PrintPRandOSError(progName); |
|
238 return -1; |
|
239 } |
|
240 |
|
241 PK11_SetPasswordFunc(SECU_GetModulePassword); |
|
242 |
|
243 if (DecodeAndPrintFile(outFile, inFile, progName)) { |
|
244 SECU_PrintError(progName, "problem decoding data"); |
|
245 return -1; |
|
246 } |
|
247 |
|
248 if (NSS_Shutdown() != SECSuccess) { |
|
249 exit(1); |
|
250 } |
|
251 |
|
252 return 0; |
|
253 } |