1 /*
2  *  Convert PEM to DER
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  */
7 
8 #include "mbedtls/build_info.h"
9 
10 #include "mbedtls/platform.h"
11 
12 #if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_FS_IO)
13 #include "mbedtls/error.h"
14 #include "mbedtls/base64.h"
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #endif
20 
21 #define DFL_FILENAME            "file.pem"
22 #define DFL_OUTPUT_FILENAME     "file.der"
23 
24 #define USAGE \
25     "\n usage: pem2der param=<>...\n"                   \
26     "\n acceptable parameters:\n"                       \
27     "    filename=%%s         default: file.pem\n"      \
28     "    output_file=%%s      default: file.der\n"      \
29     "\n"
30 
31 #if !defined(MBEDTLS_BASE64_C) || !defined(MBEDTLS_FS_IO)
main(void)32 int main(void)
33 {
34     mbedtls_printf("MBEDTLS_BASE64_C and/or MBEDTLS_FS_IO not defined.\n");
35     mbedtls_exit(0);
36 }
37 #else
38 
39 
40 /*
41  * global options
42  */
43 struct options {
44     const char *filename;       /* filename of the input file             */
45     const char *output_file;    /* where to store the output              */
46 } opt;
47 
convert_pem_to_der(const unsigned char * input,size_t ilen,unsigned char * output,size_t * olen)48 int convert_pem_to_der(const unsigned char *input, size_t ilen,
49                        unsigned char *output, size_t *olen)
50 {
51     int ret;
52     const unsigned char *s1, *s2, *end = input + ilen;
53     size_t len = 0;
54 
55     s1 = (unsigned char *) strstr((const char *) input, "-----BEGIN");
56     if (s1 == NULL) {
57         return -1;
58     }
59 
60     s2 = (unsigned char *) strstr((const char *) input, "-----END");
61     if (s2 == NULL) {
62         return -1;
63     }
64 
65     s1 += 10;
66     while (s1 < end && *s1 != '-') {
67         s1++;
68     }
69     while (s1 < end && *s1 == '-') {
70         s1++;
71     }
72     if (*s1 == '\r') {
73         s1++;
74     }
75     if (*s1 == '\n') {
76         s1++;
77     }
78 
79     if (s2 <= s1 || s2 > end) {
80         return -1;
81     }
82 
83     ret = mbedtls_base64_decode(NULL, 0, &len, (const unsigned char *) s1, s2 - s1);
84     if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) {
85         return ret;
86     }
87 
88     if (len > *olen) {
89         return -1;
90     }
91 
92     if ((ret = mbedtls_base64_decode(output, len, &len, (const unsigned char *) s1,
93                                      s2 - s1)) != 0) {
94         return ret;
95     }
96 
97     *olen = len;
98 
99     return 0;
100 }
101 
102 /*
103  * Load all data from a file into a given buffer.
104  */
load_file(const char * path,unsigned char ** buf,size_t * n)105 static int load_file(const char *path, unsigned char **buf, size_t *n)
106 {
107     FILE *f;
108     long size;
109 
110     if ((f = fopen(path, "rb")) == NULL) {
111         return -1;
112     }
113 
114     fseek(f, 0, SEEK_END);
115     if ((size = ftell(f)) == -1) {
116         fclose(f);
117         return -1;
118     }
119     fseek(f, 0, SEEK_SET);
120 
121     *n = (size_t) size;
122 
123     if (*n + 1 == 0 ||
124         (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
125         fclose(f);
126         return -1;
127     }
128 
129     if (fread(*buf, 1, *n, f) != *n) {
130         fclose(f);
131         free(*buf);
132         *buf = NULL;
133         return -1;
134     }
135 
136     fclose(f);
137 
138     (*buf)[*n] = '\0';
139 
140     return 0;
141 }
142 
143 /*
144  * Write buffer to a file
145  */
write_file(const char * path,unsigned char * buf,size_t n)146 static int write_file(const char *path, unsigned char *buf, size_t n)
147 {
148     FILE *f;
149 
150     if ((f = fopen(path, "wb")) == NULL) {
151         return -1;
152     }
153 
154     if (fwrite(buf, 1, n, f) != n) {
155         fclose(f);
156         return -1;
157     }
158 
159     fclose(f);
160     return 0;
161 }
162 
main(int argc,char * argv[])163 int main(int argc, char *argv[])
164 {
165     int ret = 1;
166     int exit_code = MBEDTLS_EXIT_FAILURE;
167     unsigned char *pem_buffer = NULL;
168     unsigned char der_buffer[4096];
169     char buf[1024];
170     size_t pem_size, der_size = sizeof(der_buffer);
171     int i;
172     char *p, *q;
173 
174     /*
175      * Set to sane values
176      */
177     memset(buf, 0, sizeof(buf));
178     memset(der_buffer, 0, sizeof(der_buffer));
179 
180     if (argc < 2) {
181 usage:
182         mbedtls_printf(USAGE);
183         goto exit;
184     }
185 
186     opt.filename            = DFL_FILENAME;
187     opt.output_file         = DFL_OUTPUT_FILENAME;
188 
189     for (i = 1; i < argc; i++) {
190 
191         p = argv[i];
192         if ((q = strchr(p, '=')) == NULL) {
193             goto usage;
194         }
195         *q++ = '\0';
196 
197         if (strcmp(p, "filename") == 0) {
198             opt.filename = q;
199         } else if (strcmp(p, "output_file") == 0) {
200             opt.output_file = q;
201         } else {
202             goto usage;
203         }
204     }
205 
206     /*
207      * 1.1. Load the PEM file
208      */
209     mbedtls_printf("\n  . Loading the PEM file ...");
210     fflush(stdout);
211 
212     ret = load_file(opt.filename, &pem_buffer, &pem_size);
213 
214     if (ret != 0) {
215 #ifdef MBEDTLS_ERROR_C
216         mbedtls_strerror(ret, buf, 1024);
217 #endif
218         mbedtls_printf(" failed\n  !  load_file returned %d - %s\n\n", ret, buf);
219         goto exit;
220     }
221 
222     mbedtls_printf(" ok\n");
223 
224     /*
225      * 1.2. Convert from PEM to DER
226      */
227     mbedtls_printf("  . Converting from PEM to DER ...");
228     fflush(stdout);
229 
230     if ((ret = convert_pem_to_der(pem_buffer, pem_size, der_buffer, &der_size)) != 0) {
231 #ifdef MBEDTLS_ERROR_C
232         mbedtls_strerror(ret, buf, 1024);
233 #endif
234         mbedtls_printf(" failed\n  !  convert_pem_to_der %d - %s\n\n", ret, buf);
235         goto exit;
236     }
237 
238     mbedtls_printf(" ok\n");
239 
240     /*
241      * 1.3. Write the DER file
242      */
243     mbedtls_printf("  . Writing the DER file ...");
244     fflush(stdout);
245 
246     ret = write_file(opt.output_file, der_buffer, der_size);
247 
248     if (ret != 0) {
249 #ifdef MBEDTLS_ERROR_C
250         mbedtls_strerror(ret, buf, 1024);
251 #endif
252         mbedtls_printf(" failed\n  !  write_file returned %d - %s\n\n", ret, buf);
253         goto exit;
254     }
255 
256     mbedtls_printf(" ok\n");
257 
258     exit_code = MBEDTLS_EXIT_SUCCESS;
259 
260 exit:
261     free(pem_buffer);
262 
263     mbedtls_exit(exit_code);
264 }
265 #endif /* MBEDTLS_BASE64_C && MBEDTLS_FS_IO */
266