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