blob: 177365b87c5edf0a055c412c024cfc80a3521559 [file] [log] [blame]
Paul Bakker8adf13b2013-08-25 14:50:09 +02001/*
2 * Convert PEM to DER
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman16799db2023-11-02 19:47:20 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakker8adf13b2013-08-25 14:50:09 +02006 */
7
Bence Szépkútic662b362021-05-27 11:25:03 +02008#include "mbedtls/build_info.h"
Paul Bakker8adf13b2013-08-25 14:50:09 +02009
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000010#include "mbedtls/platform.h"
Rich Evansf90016a2015-01-19 14:26:37 +000011
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020012#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_FS_IO)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000013#include "mbedtls/error.h"
14#include "mbedtls/base64.h"
Paul Bakker8adf13b2013-08-25 14:50:09 +020015
Rich Evans18b78c72015-02-11 14:06:19 +000016#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#endif
20
Paul Bakker8adf13b2013-08-25 14:50:09 +020021#define DFL_FILENAME "file.pem"
22#define DFL_OUTPUT_FILENAME "file.der"
23
Rich Evans18b78c72015-02-11 14:06:19 +000024#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
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020031#if !defined(MBEDTLS_BASE64_C) || !defined(MBEDTLS_FS_IO)
Gilles Peskine449bd832023-01-11 14:50:10 +010032int main(void)
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020033{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020034 mbedtls_printf("MBEDTLS_BASE64_C and/or MBEDTLS_FS_IO not defined.\n");
Gilles Peskine449bd832023-01-11 14:50:10 +010035 mbedtls_exit(0);
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020036}
37#else
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010038
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010039
Paul Bakker8adf13b2013-08-25 14:50:09 +020040/*
41 * global options
42 */
Gilles Peskine449bd832023-01-11 14:50:10 +010043struct options {
Paul Bakker8fc30b12013-11-25 13:29:43 +010044 const char *filename; /* filename of the input file */
45 const char *output_file; /* where to store the output */
Paul Bakker8adf13b2013-08-25 14:50:09 +020046} opt;
47
Michael Schuster6fa32fd2024-06-01 21:15:02 +020048static int convert_pem_to_der(const unsigned char *input, size_t ilen,
Michael Schuster82984bc2024-06-12 00:05:25 +020049 unsigned char *output, size_t *olen)
Paul Bakker8adf13b2013-08-25 14:50:09 +020050{
51 int ret;
52 const unsigned char *s1, *s2, *end = input + ilen;
53 size_t len = 0;
54
Gilles Peskine449bd832023-01-11 14:50:10 +010055 s1 = (unsigned char *) strstr((const char *) input, "-----BEGIN");
56 if (s1 == NULL) {
57 return -1;
58 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020059
Gilles Peskine449bd832023-01-11 14:50:10 +010060 s2 = (unsigned char *) strstr((const char *) input, "-----END");
61 if (s2 == NULL) {
62 return -1;
63 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020064
65 s1 += 10;
Gilles Peskine449bd832023-01-11 14:50:10 +010066 while (s1 < end && *s1 != '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020067 s1++;
Gilles Peskine449bd832023-01-11 14:50:10 +010068 }
69 while (s1 < end && *s1 == '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020070 s1++;
Gilles Peskine449bd832023-01-11 14:50:10 +010071 }
72 if (*s1 == '\r') {
73 s1++;
74 }
75 if (*s1 == '\n') {
76 s1++;
77 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020078
Gilles Peskine449bd832023-01-11 14:50:10 +010079 if (s2 <= s1 || s2 > end) {
80 return -1;
81 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020082
Gilles Peskine449bd832023-01-11 14:50:10 +010083 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 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020087
Gilles Peskine449bd832023-01-11 14:50:10 +010088 if (len > *olen) {
89 return -1;
90 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020091
Gilles Peskine449bd832023-01-11 14:50:10 +010092 if ((ret = mbedtls_base64_decode(output, len, &len, (const unsigned char *) s1,
93 s2 - s1)) != 0) {
94 return ret;
Paul Bakker8adf13b2013-08-25 14:50:09 +020095 }
96
97 *olen = len;
98
Gilles Peskine449bd832023-01-11 14:50:10 +010099 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200100}
101
102/*
103 * Load all data from a file into a given buffer.
104 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100105static int load_file(const char *path, unsigned char **buf, size_t *n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200106{
107 FILE *f;
108 long size;
109
Gilles Peskine449bd832023-01-11 14:50:10 +0100110 if ((f = fopen(path, "rb")) == NULL) {
111 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200112 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100113
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);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200120
121 *n = (size_t) size;
122
Gilles Peskine449bd832023-01-11 14:50:10 +0100123 if (*n + 1 == 0 ||
124 (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
125 fclose(f);
126 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200127 }
128
Gilles Peskine449bd832023-01-11 14:50:10 +0100129 if (fread(*buf, 1, *n, f) != *n) {
130 fclose(f);
131 free(*buf);
Alfred Klomp1d42b3e2014-07-14 22:09:21 +0200132 *buf = NULL;
Gilles Peskine449bd832023-01-11 14:50:10 +0100133 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200134 }
135
Gilles Peskine449bd832023-01-11 14:50:10 +0100136 fclose(f);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200137
138 (*buf)[*n] = '\0';
139
Gilles Peskine449bd832023-01-11 14:50:10 +0100140 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200141}
142
143/*
144 * Write buffer to a file
145 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100146static int write_file(const char *path, unsigned char *buf, size_t n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200147{
148 FILE *f;
149
Gilles Peskine449bd832023-01-11 14:50:10 +0100150 if ((f = fopen(path, "wb")) == NULL) {
151 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200152 }
153
Gilles Peskine449bd832023-01-11 14:50:10 +0100154 if (fwrite(buf, 1, n, f) != n) {
155 fclose(f);
156 return -1;
157 }
158
159 fclose(f);
160 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200161}
162
Gilles Peskine449bd832023-01-11 14:50:10 +0100163int main(int argc, char *argv[])
Paul Bakker8adf13b2013-08-25 14:50:09 +0200164{
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100165 int ret = 1;
166 int exit_code = MBEDTLS_EXIT_FAILURE;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200167 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);
Paul Bakkerc97f9f62013-11-30 15:13:02 +0100171 int i;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200172 char *p, *q;
173
174 /*
175 * Set to sane values
176 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100177 memset(buf, 0, sizeof(buf));
178 memset(der_buffer, 0, sizeof(der_buffer));
Paul Bakker8adf13b2013-08-25 14:50:09 +0200179
Aditya Deshpande644a5c02023-01-30 15:58:50 +0000180 if (argc < 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100181usage:
182 mbedtls_printf(USAGE);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200183 goto exit;
184 }
185
186 opt.filename = DFL_FILENAME;
187 opt.output_file = DFL_OUTPUT_FILENAME;
188
Gilles Peskine449bd832023-01-11 14:50:10 +0100189 for (i = 1; i < argc; i++) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200190
191 p = argv[i];
Gilles Peskine449bd832023-01-11 14:50:10 +0100192 if ((q = strchr(p, '=')) == NULL) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200193 goto usage;
Gilles Peskine449bd832023-01-11 14:50:10 +0100194 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200195 *q++ = '\0';
196
Gilles Peskine449bd832023-01-11 14:50:10 +0100197 if (strcmp(p, "filename") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200198 opt.filename = q;
Gilles Peskine449bd832023-01-11 14:50:10 +0100199 } else if (strcmp(p, "output_file") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200200 opt.output_file = q;
Gilles Peskine449bd832023-01-11 14:50:10 +0100201 } else {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200202 goto usage;
Gilles Peskine449bd832023-01-11 14:50:10 +0100203 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200204 }
205
206 /*
207 * 1.1. Load the PEM file
208 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100209 mbedtls_printf("\n . Loading the PEM file ...");
210 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200211
Gilles Peskine449bd832023-01-11 14:50:10 +0100212 ret = load_file(opt.filename, &pem_buffer, &pem_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200213
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200215#ifdef MBEDTLS_ERROR_C
Gilles Peskine449bd832023-01-11 14:50:10 +0100216 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200217#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100218 mbedtls_printf(" failed\n ! load_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200219 goto exit;
220 }
221
Gilles Peskine449bd832023-01-11 14:50:10 +0100222 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200223
224 /*
225 * 1.2. Convert from PEM to DER
226 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100227 mbedtls_printf(" . Converting from PEM to DER ...");
228 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200229
Gilles Peskine449bd832023-01-11 14:50:10 +0100230 if ((ret = convert_pem_to_der(pem_buffer, pem_size, der_buffer, &der_size)) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200231#ifdef MBEDTLS_ERROR_C
Gilles Peskine449bd832023-01-11 14:50:10 +0100232 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200233#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100234 mbedtls_printf(" failed\n ! convert_pem_to_der %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200235 goto exit;
236 }
237
Gilles Peskine449bd832023-01-11 14:50:10 +0100238 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200239
240 /*
241 * 1.3. Write the DER file
242 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100243 mbedtls_printf(" . Writing the DER file ...");
244 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200245
Gilles Peskine449bd832023-01-11 14:50:10 +0100246 ret = write_file(opt.output_file, der_buffer, der_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200247
Gilles Peskine449bd832023-01-11 14:50:10 +0100248 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200249#ifdef MBEDTLS_ERROR_C
Gilles Peskine449bd832023-01-11 14:50:10 +0100250 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200251#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100252 mbedtls_printf(" failed\n ! write_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200253 goto exit;
254 }
255
Gilles Peskine449bd832023-01-11 14:50:10 +0100256 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200257
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100258 exit_code = MBEDTLS_EXIT_SUCCESS;
259
Paul Bakker8adf13b2013-08-25 14:50:09 +0200260exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100261 free(pem_buffer);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200262
Gilles Peskine449bd832023-01-11 14:50:10 +0100263 mbedtls_exit(exit_code);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200264}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200265#endif /* MBEDTLS_BASE64_C && MBEDTLS_FS_IO */