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