1 /* smime.c  -  Command line tool for testing smimeutil.c
2  *
3  * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
4  * License: This software may be distributed under the same license
5  *          terms as openssl (i.e. free, but mandatory attribution).
6  *
7  * Official web site:  http://zxid.org/Net_SSLeay/smime.html
8  *
9  * 11.9.1999, Created. --Sampo
10  * 13.9.1999, added decryption and sig verification --Sampo
11  * 25.10.1999, added query sig to know who signed --Sampo
12  * 17.11.1999, added detached verification functions --Sampo
13  *
14  * Memory management: most routines malloc the results. Freeing them is
15  * application's responsibility. I use libc malloc, but if in doubt
16  * it might be safer to just leak the memory (i.e. don't ever free it).
17  * This library works entirely in memory, so maximum memory consumption
18  * might be more than twice the total size of all files to be encrypted.
19  *
20  * This tool is not generic in any sense (for that see openssl tool). It has
21  * many choices hard wired in a way that is convenient for me. They are
22  * just one way that works. There are many others equally good, but not
23  * implemented here.
24  *
25 gcc -c -g smimeutil.c -I/usr/local/ssl/include -o smimeutil.o
26 gcc -c -g smime.c -I/usr/local/ssl/include -o smime.o
27 gcc -g smime.o smimeutil.o -L/usr/local/ssl/lib -lcrypto -o smime
28  *
29  * ### For importing to browsers (S/MIME)
30  * openssl pkcs12 -name "End-CA" -nokey -inkey ca-priv.pem -in ca-cert.pem -export >end-ca.p12
31  *
32  * ### Note: to arrange for delivery of the certificate, arrange
33  * ### for web server to send it using mimetype (or extension)
34  *	AddType application/x-x509-ca-cert .crt
35  *	AddType application/x-pkcs7-crl    .crl
36  *
37  * ### then just copy the pem file under extension .crt
38  */
39 
40 #include "smimeutil.h"
41 
42 char usage[] =
43 SMIME_VERSION "\n"
44 "Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>. All Rights Reserved.\n"
45 "See file LICENSE in distribution directory for full copyright and license\n"
46 "information. This file also explains OpenSSL and SSLeay licenses.\n"
47 "Copyright (c) 1999 The OpenSSL Project.  All rights reserved.\n"
48 "This product includes software developed by the OpenSSL Project\n"
49 "for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
50 "Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com), All rights reserved.\n"
51 "This product includes cryptographic software written by Eric Young\n"
52 "(eay@cryptsoft.com).  This product includes software written by Tim\n"
53 "Hudson (tjh@cryptsoft.com).\n\n"
54 
55 "Official web site:  http://zxid.org/Net_SSLeay/smime.html\n\n"
56 
57 "./smime -cs private password <mime-entity >smime  # clear sign\n"
58 "./smime -cv cert <smime-entity >data              # verify clear signature\n"
59 "./smime -ds private passwd <file >smime-sig       # make detached signature\n"
60 "./smime -dv file <cert+sig-entity                 # verify detached sig\n"
61 "./smime -s  private password <mime-entity >smime  # sign\n"
62 "./smime -qs <smime-entity >signing-cert-info      # find out who signed\n"
63 "./smime -v cert <smime-entity >signer-dn          # verify signature\n\n"
64 "./smime -vc cacert <cert                          # verify certificate\n\n"
65 "./smime -e public <mime-entity >smime-ent         # encrypt\n"
66 "./smime -d private password <smime-entity >mime   # decrypt\n\n"
67 "./smime -qr <req.pem    # Query all you can about request\n"
68 "./smime -qc <cert.pem   # Query all you can about certificate\n"
69 "./smime -ca ca_cert passwd serial <req.pem >cert.pem # sign a req into cert\n\n"
70 "./smime -p12-pem p12pw pempw <x.p12 >x.pem  # convert PKCS12 to pem\n"
71 "./smime -pem-p12 frindly@name.com pempw p12pw <x.pem >x.p12  # pem to PKCS12\n\n"
72 "./smime -m type1 file1 type2 file2 type3 file3 <text  # make multipart\n"
73 "./smime -m image/gif foo.gif <message | ./smime -s private pass >smime\n\n"
74 "./smime -kg attr passwd req.pem <dn >priv_ss.pem  # keygen\n\n"
75 "./smime -base64 <file >file.base64\n"
76 "./smime -unbase64 <file.base64 >file\n"
77 "./smime -mime text/plain <file >mime-entity\n"
78 "./smime -mime_base64 image/gif <file.gif >mime-entity\n"
79 "./smime -split dirprefix <multipart         # splits multipart into files\n"
80 "./smime -base64 <in | ./smime -unbase64 >out\n"
81 "./smime -cat <in >out   # copy input to output using slurp and barf\n\n"
82 "./smime -kg 'description=Test' secret req.pem <me.dn >ss.pem\n\n"
83 "echo 'countryName=PT|organizationName=Universidade|organizationalUnitName=IST|commonName=t11|emailAddress=t11@test.com' | ./smime -kg 'description=t11' secret r11.pem | tee t11.pem | ./smime -pem-p12 t11@test.com secret secret >t11.p12\n\n"
84 "./smime -p12-pem secret secret <t.p12 | ./smime -qc\n"
85 "./smime -m image/gif a.gif <text | ./smime -cs both.pem 1234 | ./smime -e both.pem | ./send.pl\n\n"
86 "WARNING: passing passwords on command line or environment is not secure. \n"
87 "  You can pass\n"
88 "  -\\d+     (`-' and a number) to cause the password to be read from fd, or\n"
89 "  -[A-Z]+  to cause the password to be taken from an environment variable.\n"
90 "  Like this: ./smime -s priv.pem -3 <me >sme\n"
91 "  The file descriptor method is the safest. Be careful.\n"
92 ;
93 
94 #include <stdio.h>
95 #include <string.h>
96 #include <stdlib.h>
97 
98 #define DETACHED_SIG_TYPE_FILE  "application/x-detached-file-signature-file"
99 
100 /* Read all of a file descriptor to malloc'd buffer, return size.
101  * This repeatedly reallocs the buffer (probably internally copying
102  * the contents each time). This is a bit inefficient, but will do
103  * for quick and dirty now.
104  */
105 
106 /* Called by:  get_passwd, main x22, mk_multipart, read_file */
slurp(FILE * fd,char ** pb)107 static int slurp(FILE* fd, char** pb)
108 {
109   int n = 0;
110   int nn;
111   if (!fd) /*return -1*/ exit(1);;
112   if (!pb) /*return -1*/ exit(1);;
113   if ((*pb = (char*)malloc(4097))==NULL) /*return -1;*/ exit(1);
114 
115   for(;;) {
116     nn = fread((*pb)+n, 1, 4096, fd);
117     if (nn <= 0) break;
118     n+=nn;
119     if ((*pb = (char*)realloc(*pb, n+4097))==NULL) /*return -1;*/ exit(1);
120   }
121   if (nn<0) /*return -1*/ exit(1);;
122 
123   /* add NULL termination and shrink the buffer */
124 
125   (*pb)[n] = '\0';
126   if ((*pb = (char*)realloc(*pb, n+1))==NULL) /*return -1*/ exit(1);;
127   return n;  /* returns file length */
128 }
129 
130 /* Called by:  main x12, write_file */
barf(FILE * fd,char * b,int len)131 static int barf(FILE* fd, char* b, int len)
132 {
133   int n = 0;
134   int nn;
135   if (!fd) return -1;
136   if (!b) return -1;
137 
138   for (;;) {
139     /*nn = fwrite(b+n, 1, (len - n) > 4096 ? 4096 : (len-n), fd);*/
140     nn = fwrite(b+n, 1, (len - n), fd);
141     if (nn <= 0) break;
142     n+=nn;
143   }
144   if (nn<0) return -1;
145   return n;
146 }
147 
148 /* Called by:  main x10, mk_multipart x3 */
read_file(char * file,char * type,char ** data)149 static int read_file(char* file, char* type, char** data) {
150   FILE* fd;
151   int n;
152 
153   if (!(fd = fopen(file, "rb"))) {
154     fprintf(stderr, "File `%s' not found? (type=%s)\n", file, type);
155     perror(file);
156     exit(1);
157   }
158   n = slurp(fd, data);
159   fclose(fd);
160   return n;   /* returns file length */
161 }
162 
163 /* Called by:  main x2 */
write_file(char * file,char * type,char * data,int len)164 static int write_file(char* file, char* type, char* data, int len) {
165   FILE* fd;
166   int n;
167 
168   if (!(fd = fopen(file, "wb"))) {
169     fprintf(stderr, "Cant write file `%s' (type=%s)\n", file, type);
170     perror(file);
171     exit(1);
172   }
173   n = barf(fd, data, len);
174   fclose(fd);
175   return n;
176 }
177 
178 /* --------------------- */
179 
180 /* Get password from file descriptor or environment variable */
181 
182 /* Called by:  main x10 */
get_passwd(const char * pass)183 const char* get_passwd(const char* pass)
184 {
185   FILE* in = NULL;
186   char* p;
187   int fd;
188 
189   if (pass[0] != '-') return pass;
190   p = (char*)(pass+1);
191   if (strlen(p) == strspn(p, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
192     /* Environment */
193     if (!(p = getenv(p))) {
194       fprintf(stderr, "No password environment variable `%s'\n", pass);
195       exit(1);
196     }
197     return p;
198   }
199 
200   if (strlen(p) != strspn(p, "0123456789")) return pass;
201 
202   /* Read it from file descriptor */
203 
204   fd = atoi(p);
205   if (!(in = fdopen(fd, "r"))) {
206     fprintf(stderr, "Cant open file descriptor %d for reading password\n", fd);
207     perror("fdopen");
208     exit(1);
209   }
210   slurp(in, &p);
211   return p;
212 }
213 
214 /* --------------------- */
215 
216 /* Called by:  main */
mk_multipart(int ac,char * av[])217 static char* mk_multipart (int ac, char* av[]) {
218     char* text;
219     char* f1 = NULL;
220     char* f2 = NULL;
221     char* f3 = NULL;
222     char* t1 = NULL;
223     char* t2 = NULL;
224     char* t3 = NULL;
225     char* n1 = NULL;
226     char* n2 = NULL;
227     char* n3 = NULL;
228     int l1 = 0, l2 = 0, l3 = 0;
229 
230     /* Read attachment files, if any */
231 
232     av++; ac--;
233     if (ac>1) {
234       t1 = *av;
235       av++; ac--;
236       l1 = read_file(n1=*av, t1, &f1);
237 
238       av++; ac--;
239       if (ac>1) {
240 	t2 = *av;
241 	av++; ac--;
242 	l2 = read_file(n2=*av, t2, &f2);
243 
244 	av++; ac--;
245 	if (ac>1) {
246 	  t3 = *av;
247 	  av++; ac--;
248 	  l3 = read_file(n3=*av, t3, &f3);
249 	}
250       }
251     }
252 
253     /* Read text from stdin */
254 
255     slurp(stdin, &text);
256 
257     return mime_mk_multipart(text,
258 			     f1, l1, t1, n1,
259 			     f2, l2, t2, n2,
260 			     f3, l3, t3, n3);
261 }
262 
263 #define TOO_FEW_OPTIONS(ac,n,s) if ((ac)<(n)) { \
264       fprintf(stderr, "%s needs %d arguments (%d supplied).\n%s", (s), n, ac, \
265       usage); exit(1); }
266 
267 /* ===== M A I N ===== */
268 
269 /* Called by: */
main(int ac,char * av[])270 int main(int ac, char* av[]) {
271   av++; ac--;
272 
273   if (ac < 1) {
274     fprintf(stderr, "Too few options. Need to provide a command switch.\n%s",
275 	    usage);
276     exit(1);
277   }
278 
279   smime_init("random.txt", "ssaddsfa", 8 );
280 
281   /* ./smime -base64 <file >file.base64 */
282   if (!strcmp(*av, "-base64")) {
283     int n, nn;
284     char* b;
285     char* b64;
286     n = slurp(stdin, &b);
287     nn = smime_base64(1, b, n, &b64);
288     fprintf(stderr, "%d bytes in, %d bytes out\n", n, nn);
289     barf(stdout, b64, nn);
290     exit(nn > 0 ? 0 : 1);
291   }
292 
293   /* ./smime -unbase64 <file.base64 >file */
294   if (!strcmp(*av, "-unbase64")) {
295     int n, nn;
296     char* b;
297     char* b64;
298     n = slurp(stdin, &b);
299     nn = smime_base64(0, b, n, &b64);
300     fprintf(stderr, "%d bytes in, %d bytes out\n", n, nn);
301     barf(stdout, b64, nn);
302     exit(nn > 0 ? 0 : 1);
303   }
304 
305   /* ./smime -cat <in >out */
306   if (!strcmp(*av, "-cat")) {
307     int n;
308     char* b;
309     n = slurp(stdin, &b);
310     fprintf(stderr, "%d bytes\n", n);
311     barf(stdout, b, n);
312     exit(n > 0 ? 0 : 1);
313   }
314 
315   /* ./smime -mime text/plain <file >mime-entity */
316   if (!strcmp(*av, "-mime")) {
317     int n, nn;
318     char* b;
319     char* b64;
320 
321     ac--; av++;
322     TOO_FEW_OPTIONS(ac,1,"-mime");
323 
324     n = slurp(stdin, &b);
325     b64 = mime_raw_entity(b, av[0]);
326     fprintf(stderr, "%d bytes in, %d bytes out\n", n, nn=strlen(b64));
327     barf(stdout, b64, nn);
328     exit(nn > 0 ? 0 : 1);
329   }
330 
331   /* ./smime -split dirprefix <multipart   # splits multipart into files */
332   if (!strcmp(*av, "-split")) {
333     int n, nn;
334     char* b;
335     char* parts[100];
336     int lengths[100];
337     char file[4096];
338 
339     ac--; av++;
340     TOO_FEW_OPTIONS(ac,1,"-split");
341 
342     n = slurp(stdin, &b);
343     if ((nn = mime_split_multipart(b, 100, parts, lengths))==-1) {
344       fprintf(stderr, "mime error\n%s", smime_get_errors());
345       exit(1);
346     }
347 
348     /* Write out the parts */
349 
350     for (n = 0; n < nn; n++) {
351       snprintf(file, sizeof(file), "%s%d", av[0], n);
352       fprintf(stderr, "%s\n", file);
353       write_file(file, "part", parts[n], lengths[n]);
354     }
355 
356     exit(0);
357   }
358 
359   /* ./smime -mime_base64 image/gif <file.gif >mime-entity */
360   if (!strcmp(*av, "-mime_base64")) {
361     int n, nn;
362     char* b;
363     char* b64;
364 
365     ac--; av++;
366     TOO_FEW_OPTIONS(ac,1,"-mime_base64");
367 
368     n = slurp(stdin, &b);
369     b64 = mime_base64_entity(b, n, av[0]);
370     fprintf(stderr, "%d bytes in, %d bytes out\n", n, nn=strlen(b64));
371     barf(stdout, b64, nn);
372     exit(nn > 0 ? 0 : 1);
373   }
374 
375   /* ./smime -m type1 file1 type2 file2 type3 file3 <text  # make multipart */
376   if (!strcmp(*av, "-m")) {
377     char* mime;
378     if (!(mime = mk_multipart(ac, av))) exit(1);
379     barf(stdout, mime, strlen(mime));
380     exit(0);
381   }
382 
383   /* ./smime -cs private password <mime-entity >smime */
384   if (!strcmp(*av, "-cs")) {
385     char* smime;
386     char* mime;
387     char* privkey;
388 
389     ac--; av++;
390     TOO_FEW_OPTIONS(ac,2,"-cs");
391 
392     slurp(stdin, &mime);
393     read_file(av[0], "privkey", &privkey);
394 
395     if (!(smime = smime_clear_sign(privkey, get_passwd(av[1]), mime))) {
396       fprintf(stderr, "crypto error\n%s", smime_get_errors());
397       exit(1);
398     }
399     barf(stdout, smime, strlen(smime));
400     exit(0);
401   }
402 
403   /* ./smime -s  private password <mime-entity >smime */
404   if (!strcmp(*av, "-s")) {
405     char* smime;
406     char* mime;
407     char* privkey;
408 
409     ac--; av++;
410     TOO_FEW_OPTIONS(ac,2,"-s");
411 
412     slurp(stdin, &mime);
413     read_file(av[0], "privkey", &privkey);
414 
415     if (!(smime = smime_sign(privkey, get_passwd(av[1]), mime))) {
416       fprintf(stderr, "crypto error\n%s", smime_get_errors());
417       exit(1);
418     }
419     barf(stdout, smime, strlen(smime));
420     exit(0);
421   }
422 
423   /* ./smime -v cert <smime-entity >signer-dn          # verify sig */
424   if (!strcmp(*av, "-v")) {
425     char* cert;
426     char* smime;
427     char* signed_data;
428     int n = slurp(stdin, &smime);
429 
430     ac--; av++;
431     TOO_FEW_OPTIONS(ac,1,"-v");
432 
433     fprintf(stderr, "%d bytes in\n", n);
434     read_file(av[0], "cert", &cert);
435 
436     if (!(signed_data = smime_verify_signature(cert, smime, NULL, 0))) {
437       fprintf(stderr, "crypto error\n%s", smime_get_errors());
438       exit(1);
439     }
440     fputs(signed_data, stdout);  /* careful not to output trailing newline */
441     exit(0);
442   }
443 
444   /* ./smime -cv cert <smime-entity >signer-dn    # verify clear signature */
445   if (!strcmp(*av, "-cv")) {
446     char* cert;
447     char* smime;
448     char* parts[2];  /* parts[0] is the clear text, parts[1] is the sig */
449     int lengths[2];
450     char* signed_data;
451     int n = slurp(stdin, &smime);
452 
453     ac--; av++;
454     TOO_FEW_OPTIONS(ac,1,"-cv");
455 
456     fprintf(stderr, "%d bytes in\n", n);
457     read_file(av[0], "cert", &cert);
458 
459     /* multipart/signed has always exactly two parts */
460 
461     if (mime_split_multipart(smime, 2, parts, lengths) != 2) {
462       fprintf(stderr, "mime error\n%s", smime_get_errors());
463       exit(1);
464     }
465 
466     if (!(signed_data =
467 	  smime_verify_signature(cert, parts[1] /*sig*/,
468 				 parts[0] /*plain*/, lengths[0]))) {
469       fprintf(stderr, "crypto error\n%s", smime_get_errors());
470       exit(1);
471     }
472     fputs(signed_data, stdout);  /* careful not to output trailing newline */
473     exit(0);
474   }
475 
476   /* ./smime -vc cacert <cert  # verify certificate */
477   if (!strcmp(*av, "-vc")) {
478     char* cert;
479     char* ca_cert;
480     int x;
481     int n = slurp(stdin, &cert);
482 
483     ac--; av++;
484     TOO_FEW_OPTIONS(ac,1,"-vc");
485 
486     fprintf(stderr, "%d bytes in\n", n);
487     read_file(av[0], "ca_cert", &ca_cert);
488 
489     x = smime_verify_cert(ca_cert, cert);
490 
491     if (x == 1) {
492       printf("OK\n");
493       exit(0);
494     }
495 
496     if (x == 0) {
497       printf("NOT OK\n");
498       exit(2);
499     }
500 
501     fprintf(stderr, "crypto error\n%s", smime_get_errors());
502     exit(1);
503   }
504 
505   /* ./smime -ds private passwd <file >smime-sig  # make detached signature */
506 
507   if (!strcmp(*av, "-ds")) {
508     char* file;
509     char* smime;
510     char* mime;
511     char* privkey;
512     char* parts[2];  /* parts[0] is the clear text, parts[1] is the sig */
513     int lengths[2];
514     int n;
515 
516     ac--; av++;
517     TOO_FEW_OPTIONS(ac,2,"-ds");
518 
519     n = slurp(stdin, &file);
520     read_file(av[0], "privkey", &privkey);
521 
522     if (!(mime = mime_base64_entity(file, n, DETACHED_SIG_TYPE_FILE))) {
523       fprintf(stderr, "mime error\n%s", smime_get_errors());
524       exit(1);
525     }
526 
527     if (!(smime = smime_clear_sign(privkey, get_passwd(av[1]), mime))) {
528       fprintf(stderr, "crypto error\n%s", smime_get_errors());
529       exit(1);
530     }
531 
532     if (mime_split_multipart(smime, 2, parts, lengths) != 2) {
533       fprintf(stderr, "mime error\n%s", smime_get_errors());
534       exit(1);
535     }
536 
537     barf(stdout, parts[1], lengths[1]);
538     exit(0);
539   }
540 
541   /* ./smime -dv file <sig+cert  # verify detached signature */
542 
543   if (!strcmp(*av, "-dv")) {
544     char* sig;
545     char* file;
546     char* cert;
547     char* mime;
548     char* canon;
549     char* p;
550     char c;
551     int n;
552 
553     ac--; av++;
554     TOO_FEW_OPTIONS(ac,1,"-dv");
555 
556     n = slurp(stdin, &sig);
557     if (!(p = strstr(sig, "-----BEGIN CERTIFICATE-----"))) {
558       fprintf(stderr, "No certificate found in stdin.\n");
559       exit(1);
560     }
561 
562     if (p == sig) {
563       /* Certificate first, then signature */
564 
565       if (!(p = strstr(sig, "-----END CERTIFICATE-----"))) exit(1);
566       p+=strlen("-----END CERTIFICATE-----");
567       if (*p == '\015') p++;
568       if (*p == '\012') p++;
569       c = p[0];
570       p[0] = '\0';
571       cert = strdup(sig);
572       p[0] = c;
573       sig = p;
574 
575     } else {
576 
577       /* Signature first, then certificate */
578 
579       p[0] = '\0';
580       sig = strdup(sig);
581       p[0] = '-';
582       cert = p;
583     }
584 
585     n = read_file(av[0], "file", &file);
586 
587     /* wrap the file in mime entity */
588 
589     if (!(mime = mime_base64_entity(file, n, DETACHED_SIG_TYPE_FILE))) {
590       fprintf(stderr, "mime error\n%s", smime_get_errors());
591       exit(1);
592     }
593 
594     /* Must canonize, otherwise the sig will not verify */
595 
596     if (!(canon = mime_canon(mime))) {
597       fprintf(stderr, "canon error\n%s", smime_get_errors());
598       exit(1);
599     }
600 
601     if (!smime_verify_signature(cert, sig, canon, strlen(canon))) {
602       fprintf(stderr, "crypto error\n%s", smime_get_errors());
603       exit(1);
604     }
605     printf("Signature verified OK.\n");
606     exit(0);
607   }
608 
609   /* ./smime -e public <mime-entity >smime-ent */
610   if (!strcmp(*av, "-e")) {
611     char* smime;
612     char* mime;
613     char* cert;
614 
615     ac--; av++;
616     TOO_FEW_OPTIONS(ac,1,"-e");
617 
618     slurp(stdin, &mime);
619     read_file(av[0], "cert", &cert);
620 
621     if (!(smime = smime_encrypt(cert, mime))) {
622       fprintf(stderr, "crypto error\n%s", smime_get_errors());
623       exit(1);
624     }
625     barf(stdout, smime, strlen(smime));
626     exit(0);
627   }
628 
629   /* ./smime -d private password <smime-entity >mime   # decrypt */
630   if (!strcmp(*av, "-d")) {
631     char* smime;
632     char* mime;
633     char* privkey;
634     int n;
635 
636     ac--; av++;
637     TOO_FEW_OPTIONS(ac,2,"-d");
638 
639     n = slurp(stdin, &smime);
640     read_file(av[0], "privkey", &privkey);
641 
642     if ((n = smime_decrypt(privkey, get_passwd(av[1]), smime, &mime)) < 0) {
643       fprintf(stderr, "crypto error\n%s", smime_get_errors());
644       exit(1);
645     }
646     barf(stdout, mime, n);
647     exit(0);
648   }
649 
650   /* ./smime -kg attr password priv_x509ss.pem req.pem <dn >modulus */
651 
652   if (!strcmp(*av, "-kg")) {
653     char* dn;
654     char* priv;
655     char* x509ss;
656     char* request;
657 
658     ac--; av++;
659     TOO_FEW_OPTIONS(ac,2,"-kg");
660 
661     slurp(stdin, &dn);
662 
663     if (smime_keygen(dn, av[0] /*attr*/, get_passwd(av[1]),
664 	     "Test certificate. See http://www.bacus.pt/Net_SSLeay/smime.html",
665 	     &priv, &x509ss, &request)<0) {
666       fprintf(stderr, "crypto error\n%s", smime_get_errors());
667       exit(1);
668     }
669 
670     puts(priv);
671     puts(x509ss);
672     write_file(av[2], "pem", request, strlen(request));
673     exit(0);
674   }
675 
676   /* ./smime -qr <req.pem    # Query all you can about request */
677 
678   if (!strcmp(*av, "-qr")) {
679     char* req;
680     char* name;
681     char* attr;
682     char* mod;
683     char* md5;
684     char* hash;
685     char block1[14];
686     int n = slurp(stdin, &req);
687     fprintf(stderr, "%d bytes in\n", n);
688 
689     if (!(name = smime_get_req_name(req))) {
690       fprintf(stderr, "crypto error\n%s", smime_get_errors());
691       exit(1);
692     }
693     puts(name);
694 
695     if (!(attr = smime_get_req_attr(req))) {
696       fprintf(stderr, "crypto error\n%s", smime_get_errors());
697       exit(1);
698     }
699     puts(attr);
700 
701     if (!(mod = smime_get_req_modulus(req))) {
702       fprintf(stderr, "crypto error\n%s", smime_get_errors());
703       exit(1);
704     }
705     puts(mod);
706 
707     if (!(md5 = smime_md5(mod))) {
708       fprintf(stderr, "crypto error\n%s", smime_get_errors());
709       exit(1);
710     }
711     puts(md5);
712 
713     if (!(hash = smime_get_req_hash(req))) {
714       fprintf(stderr, "crypto error\n%s", smime_get_errors());
715       exit(1);
716     }
717     memcpy(block1, hash, 13);
718     block1[13] = '\0';
719     printf("\n*%s*\n*%s*\n", block1, hash+13);
720     exit(0);
721   }
722 
723   /* ./smime -qc <cert.pem   # Query all you can about certificate */
724 
725   if (!strcmp(*av, "-qc")) {
726     char* cert;
727     char* name;
728     char* issuer;
729     char* fingerprint;
730     char* mod;
731     char* md5;
732     long serial;
733     int n = slurp(stdin, &cert);
734     fprintf(stderr, "%d bytes in\n", n);
735 
736     if ((serial = smime_get_cert_names(cert, &name, &issuer)) == -1) {
737       fprintf(stderr, "crypto error\n%s", smime_get_errors());
738       exit(1);
739     }
740     puts(name);
741     puts(issuer);
742     printf("serial: %ld\n", serial);
743 
744     if ((serial = smime_get_cert_info(cert, &mod, &fingerprint)) == -1) {
745       fprintf(stderr, "crypto error\n%s", smime_get_errors());
746       exit(1);
747     }
748 
749     printf("serial: %ld\n", serial);
750 
751     puts(fingerprint);
752     puts(mod);
753 
754     if (!(md5 = smime_md5(mod))) {
755       fprintf(stderr, "crypto error\n%s", smime_get_errors());
756       exit(1);
757     }
758     puts(md5);
759     exit(0);
760   }
761 
762   /* ./smime -qs <smime-entity >signing-cert-info
763    * find out who signed (query sig) */
764   if (!strcmp(*av, "-qs")) {
765     char* issuer;
766     char* signed_entity;
767     long serial;
768     int sig_count = 0;
769     int n = slurp(stdin, &signed_entity);
770     fprintf(stderr, "%d bytes in\n", n);
771 
772     while ((serial = smime_get_signer_info(signed_entity,
773 					   sig_count, &issuer)) != -1) {
774       puts(issuer);
775       printf("serial: %ld\n", serial);
776       sig_count++;
777     }
778     if (!sig_count) {
779       fprintf(stderr, "crypto error\n%s", smime_get_errors());
780       exit(1);
781     }
782     exit(0);
783   }
784 
785   /* ./smime -ca ca_cert passwd serial <req.pem >cert.pem */
786 
787   if (!strcmp(*av, "-ca")) {
788     char* req;
789     char* ca_cert;
790     char* cert;
791     slurp(stdin, &req);
792 
793     ac--; av++;
794     TOO_FEW_OPTIONS(ac,3,"-ca");
795 
796     read_file(av[0], "ca_cert_pem", &ca_cert);
797 
798     if (!(cert = smime_ca(ca_cert, get_passwd(av[1]), req,
799 			  "today", "days:365", atoi(av[2]),
800 			  "CA:TRUE,pathlen:3",
801 			  "client,server,email,objsign,sslCA,emailCA,objCA",
802 			  "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign",
803 			  "Test certificate. See http://www.bacus.pt/Net_SSLeay/smime.html"))) {
804       fprintf(stderr, "crypto error\n%s", smime_get_errors());
805       exit(1);
806     }
807     puts(cert);
808     exit(0);
809   }
810 
811   /* ./smime -p12-pem imppw0 exppw1 <x.p12 >x.pem */
812 
813   if (!strcmp(*av, "-p12-pem")) {
814     char* x;
815     char* pk;
816     char* cert;
817     int n = slurp(stdin, &x);
818 
819     ac--; av++;
820     TOO_FEW_OPTIONS(ac,2,"-p12-pem");
821 
822     if (smime_pkcs12_to_pem(x, n, get_passwd(av[0]), get_passwd(av[1]),
823 			    &pk, &cert) == -1) {
824       fprintf(stderr, "crypto error\n%s", smime_get_errors());
825       exit(1);
826     }
827 
828     puts(pk);
829     puts(cert);
830     exit(0);
831   }
832 
833   /* ./smime -pem-p12 frindly@name0 pw1 pw2 <x.pem >x.p12 */
834 
835   if (!strcmp(*av, "-pem-p12")) {
836     char* x;
837     char* pkcs12;
838     int n = slurp(stdin, &x);
839 
840     ac--; av++;
841     TOO_FEW_OPTIONS(ac,3,"-pem-p12");
842 
843     if ((n = smime_pem_to_pkcs12(av[0], x /*cert*/, x /*privkey*/,
844 				 get_passwd(av[1]), get_passwd(av[2]),
845 				 &pkcs12)) == -1) {
846       fprintf(stderr, "crypto error\n%s", smime_get_errors());
847       exit(1);
848     }
849 
850     barf(stdout, pkcs12, n);
851     exit(0);
852   }
853 
854   fprintf(stderr, "Unknown option.\n%s", usage);
855   return 1;
856 }
857 
858 /* EOF  -  smime.c */
859