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