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