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