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 #include "plgetopt.h"
6 #include "secutil.h"
7 #include "nssb64.h"
8 #include <errno.h>
9 
10 #if defined(XP_WIN) || (defined(__sun) && !defined(SVR4))
11 #if !defined(WIN32)
12 extern int fread(char *, size_t, size_t, FILE *);
13 extern int fwrite(char *, size_t, size_t, FILE *);
14 extern int fprintf(FILE *, char *, ...);
15 #endif
16 #endif
17 
18 #if defined(WIN32)
19 #include "fcntl.h"
20 #include "io.h"
21 #endif
22 
23 static PRInt32
output_ascii(void * arg,const char * obuf,PRInt32 size)24 output_ascii(void *arg, const char *obuf, PRInt32 size)
25 {
26     FILE *outFile = arg;
27     int nb;
28 
29     nb = fwrite(obuf, 1, size, outFile);
30     if (nb != size) {
31         PORT_SetError(SEC_ERROR_IO);
32         return -1;
33     }
34 
35     return nb;
36 }
37 
38 static SECStatus
encode_file(FILE * outFile,FILE * inFile)39 encode_file(FILE *outFile, FILE *inFile)
40 {
41     NSSBase64Encoder *cx;
42     int nb;
43     SECStatus status = SECFailure;
44     unsigned char ibuf[4096];
45 
46     cx = NSSBase64Encoder_Create(output_ascii, outFile);
47     if (!cx) {
48         return -1;
49     }
50 
51     for (;;) {
52         if (feof(inFile))
53             break;
54         nb = fread(ibuf, 1, sizeof(ibuf), inFile);
55         if (nb != sizeof(ibuf)) {
56             if (nb == 0) {
57                 if (ferror(inFile)) {
58                     PORT_SetError(SEC_ERROR_IO);
59                     goto loser;
60                 }
61                 /* eof */
62                 break;
63             }
64         }
65 
66         status = NSSBase64Encoder_Update(cx, ibuf, nb);
67         if (status != SECSuccess)
68             goto loser;
69     }
70 
71     status = NSSBase64Encoder_Destroy(cx, PR_FALSE);
72     if (status != SECSuccess)
73         return status;
74 
75     /*
76      * Add a trailing CRLF.  Note this must be done *after* the call
77      * to Destroy above (because only then are we sure all data has
78      * been written out).
79      */
80     fwrite("\r\n", 1, 2, outFile);
81     return SECSuccess;
82 
83 loser:
84     (void)NSSBase64Encoder_Destroy(cx, PR_TRUE);
85     return status;
86 }
87 
88 static void
Usage(char * progName)89 Usage(char *progName)
90 {
91     fprintf(stderr,
92             "Usage: %s [-i input] [-o output]\n",
93             progName);
94     fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
95             "-i input");
96     fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
97             "-o output");
98     fprintf(stderr, "%-20s Wrap output in BEGIN/END lines and the given suffix\n",
99             "-w suffix");
100     fprintf(stderr, "%-20s (use \"c\" as a shortcut for suffix CERTIFICATE)\n",
101             "");
102     exit(-1);
103 }
104 
105 int
main(int argc,char ** argv)106 main(int argc, char **argv)
107 {
108     char *progName;
109     SECStatus rv;
110     FILE *inFile, *outFile;
111     PLOptState *optstate;
112     PLOptStatus status;
113     char *suffix = NULL;
114 
115     inFile = 0;
116     outFile = 0;
117     progName = strrchr(argv[0], '/');
118     if (!progName)
119         progName = strrchr(argv[0], '\\');
120     progName = progName ? progName + 1 : argv[0];
121 
122     /* Parse command line arguments */
123     optstate = PL_CreateOptState(argc, argv, "i:o:w:");
124     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
125         switch (optstate->option) {
126             default:
127                 Usage(progName);
128                 break;
129 
130             case 'i':
131                 inFile = fopen(optstate->value, "rb");
132                 if (!inFile) {
133                     fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
134                             progName, optstate->value);
135                     return -1;
136                 }
137                 break;
138 
139             case 'o':
140                 outFile = fopen(optstate->value, "wb");
141                 if (!outFile) {
142                     fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
143                             progName, optstate->value);
144                     return -1;
145                 }
146                 break;
147 
148             case 'w':
149                 if (!strcmp(optstate->value, "c"))
150                     suffix = strdup("CERTIFICATE");
151                 else
152                     suffix = strdup(optstate->value);
153                 break;
154         }
155     }
156     if (status == PL_OPT_BAD)
157         Usage(progName);
158     if (!inFile) {
159 #if defined(WIN32)
160         /* If we're going to read binary data from stdin, we must put stdin
161         ** into O_BINARY mode or else incoming \r\n's will become \n's.
162         */
163 
164         int smrv = _setmode(_fileno(stdin), _O_BINARY);
165         if (smrv == -1) {
166             fprintf(stderr,
167                     "%s: Cannot change stdin to binary mode. Use -i option instead.\n",
168                     progName);
169             return smrv;
170         }
171 #endif
172         inFile = stdin;
173     }
174     if (!outFile) {
175 #if defined(WIN32)
176         /* We're going to write binary data to stdout. We must put stdout
177         ** into O_BINARY mode or else outgoing \r\n's will become \r\r\n's.
178         */
179 
180         int smrv = _setmode(_fileno(stdout), _O_BINARY);
181         if (smrv == -1) {
182             fprintf(stderr,
183                     "%s: Cannot change stdout to binary mode. Use -o option instead.\n",
184                     progName);
185             return smrv;
186         }
187 #endif
188         outFile = stdout;
189     }
190     if (suffix) {
191         fprintf(outFile, "-----BEGIN %s-----\n", suffix);
192     }
193     rv = encode_file(outFile, inFile);
194     if (rv != SECSuccess) {
195         fprintf(stderr, "%s: lossage: error=%d errno=%d\n",
196                 progName, PORT_GetError(), errno);
197         return -1;
198     }
199     if (suffix) {
200         fprintf(outFile, "-----END %s-----\n", suffix);
201     }
202     return 0;
203 }
204