blob: 8b7088380492d55277636be044577266417f440b [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 Rodgman7ff79652023-11-03 12:04:52 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakker8adf13b2013-08-25 14:50:09 +02006 */
7
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02008#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +00009#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020010#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020011#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020012#endif
Paul Bakker8adf13b2013-08-25 14:50:09 +020013
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000014#include "mbedtls/platform.h"
Rich Evansf90016a2015-01-19 14:26:37 +000015
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020016#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_FS_IO)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000017#include "mbedtls/error.h"
18#include "mbedtls/base64.h"
Paul Bakker8adf13b2013-08-25 14:50:09 +020019
Rich Evans18b78c72015-02-11 14:06:19 +000020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#endif
24
Paul Bakker8adf13b2013-08-25 14:50:09 +020025#define DFL_FILENAME "file.pem"
26#define DFL_OUTPUT_FILENAME "file.der"
27
Rich Evans18b78c72015-02-11 14:06:19 +000028#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
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020035#if !defined(MBEDTLS_BASE64_C) || !defined(MBEDTLS_FS_IO)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010036int main(void)
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020037{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020038 mbedtls_printf("MBEDTLS_BASE64_C and/or MBEDTLS_FS_IO not defined.\n");
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010039 mbedtls_exit(0);
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020040}
41#else
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010042
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010043
Paul Bakker8adf13b2013-08-25 14:50:09 +020044/*
45 * global options
46 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010047struct options {
Paul Bakker8fc30b12013-11-25 13:29:43 +010048 const char *filename; /* filename of the input file */
49 const char *output_file; /* where to store the output */
Paul Bakker8adf13b2013-08-25 14:50:09 +020050} opt;
51
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010052int convert_pem_to_der(const unsigned char *input, size_t ilen,
53 unsigned char *output, size_t *olen)
Paul Bakker8adf13b2013-08-25 14:50:09 +020054{
55 int ret;
56 const unsigned char *s1, *s2, *end = input + ilen;
57 size_t len = 0;
58
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010059 s1 = (unsigned char *) strstr((const char *) input, "-----BEGIN");
60 if (s1 == NULL) {
61 return -1;
62 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020063
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010064 s2 = (unsigned char *) strstr((const char *) input, "-----END");
65 if (s2 == NULL) {
66 return -1;
67 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020068
69 s1 += 10;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010070 while (s1 < end && *s1 != '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020071 s1++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010072 }
73 while (s1 < end && *s1 == '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020074 s1++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010075 }
76 if (*s1 == '\r') {
77 s1++;
78 }
79 if (*s1 == '\n') {
80 s1++;
81 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020082
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010083 if (s2 <= s1 || s2 > end) {
84 return -1;
85 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020086
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010087 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 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020091
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010092 if (len > *olen) {
93 return -1;
94 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020095
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010096 if ((ret = mbedtls_base64_decode(output, len, &len, (const unsigned char *) s1,
97 s2 - s1)) != 0) {
98 return ret;
Paul Bakker8adf13b2013-08-25 14:50:09 +020099 }
100
101 *olen = len;
102
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100103 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200104}
105
106/*
107 * Load all data from a file into a given buffer.
108 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100109static int load_file(const char *path, unsigned char **buf, size_t *n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200110{
111 FILE *f;
112 long size;
113
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100114 if ((f = fopen(path, "rb")) == NULL) {
115 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200116 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100117
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);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200124
125 *n = (size_t) size;
126
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100127 if (*n + 1 == 0 ||
128 (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
129 fclose(f);
130 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200131 }
132
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100133 if (fread(*buf, 1, *n, f) != *n) {
134 fclose(f);
135 free(*buf);
Alfred Klomp1d42b3e2014-07-14 22:09:21 +0200136 *buf = NULL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100137 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200138 }
139
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100140 fclose(f);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200141
142 (*buf)[*n] = '\0';
143
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100144 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200145}
146
147/*
148 * Write buffer to a file
149 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100150static int write_file(const char *path, unsigned char *buf, size_t n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200151{
152 FILE *f;
153
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100154 if ((f = fopen(path, "wb")) == NULL) {
155 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200156 }
157
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100158 if (fwrite(buf, 1, n, f) != n) {
159 fclose(f);
160 return -1;
161 }
162
163 fclose(f);
164 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200165}
166
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100167int main(int argc, char *argv[])
Paul Bakker8adf13b2013-08-25 14:50:09 +0200168{
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100169 int ret = 1;
170 int exit_code = MBEDTLS_EXIT_FAILURE;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200171 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);
Paul Bakkerc97f9f62013-11-30 15:13:02 +0100175 int i;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200176 char *p, *q;
177
178 /*
179 * Set to sane values
180 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100181 memset(buf, 0, sizeof(buf));
182 memset(der_buffer, 0, sizeof(der_buffer));
Paul Bakker8adf13b2013-08-25 14:50:09 +0200183
Aditya Deshpande0504ac22023-01-30 15:58:50 +0000184 if (argc < 2) {
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100185usage:
186 mbedtls_printf(USAGE);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200187 goto exit;
188 }
189
190 opt.filename = DFL_FILENAME;
191 opt.output_file = DFL_OUTPUT_FILENAME;
192
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100193 for (i = 1; i < argc; i++) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200194
195 p = argv[i];
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100196 if ((q = strchr(p, '=')) == NULL) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200197 goto usage;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100198 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200199 *q++ = '\0';
200
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100201 if (strcmp(p, "filename") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200202 opt.filename = q;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100203 } else if (strcmp(p, "output_file") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200204 opt.output_file = q;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100205 } else {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200206 goto usage;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100207 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200208 }
209
210 /*
211 * 1.1. Load the PEM file
212 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100213 mbedtls_printf("\n . Loading the PEM file ...");
214 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200215
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100216 ret = load_file(opt.filename, &pem_buffer, &pem_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200217
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100218 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200219#ifdef MBEDTLS_ERROR_C
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100220 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200221#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100222 mbedtls_printf(" failed\n ! load_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200223 goto exit;
224 }
225
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100226 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200227
228 /*
229 * 1.2. Convert from PEM to DER
230 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100231 mbedtls_printf(" . Converting from PEM to DER ...");
232 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200233
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100234 if ((ret = convert_pem_to_der(pem_buffer, pem_size, der_buffer, &der_size)) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200235#ifdef MBEDTLS_ERROR_C
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100236 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200237#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100238 mbedtls_printf(" failed\n ! convert_pem_to_der %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200239 goto exit;
240 }
241
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100242 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200243
244 /*
245 * 1.3. Write the DER file
246 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100247 mbedtls_printf(" . Writing the DER file ...");
248 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200249
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100250 ret = write_file(opt.output_file, der_buffer, der_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200251
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100252 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200253#ifdef MBEDTLS_ERROR_C
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100254 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200255#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100256 mbedtls_printf(" failed\n ! write_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200257 goto exit;
258 }
259
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100260 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200261
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100262 exit_code = MBEDTLS_EXIT_SUCCESS;
263
Paul Bakker8adf13b2013-08-25 14:50:09 +0200264exit:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100265 free(pem_buffer);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200266
267#if defined(_WIN32)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100268 mbedtls_printf(" + Press Enter to exit this program.\n");
269 fflush(stdout); getchar();
Paul Bakker8adf13b2013-08-25 14:50:09 +0200270#endif
271
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100272 mbedtls_exit(exit_code);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200273}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200274#endif /* MBEDTLS_BASE64_C && MBEDTLS_FS_IO */