blob: 9515ed43d2813732c2571a6cff53eebbc7529a33 [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
Felix Conway998760a2025-03-24 11:37:33 +00008#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS
9
Bence Szépkútic662b362021-05-27 11:25:03 +020010#include "mbedtls/build_info.h"
Paul Bakker8adf13b2013-08-25 14:50:09 +020011
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000012#include "mbedtls/platform.h"
Rich Evansf90016a2015-01-19 14:26:37 +000013
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020014#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_FS_IO)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000015#include "mbedtls/error.h"
16#include "mbedtls/base64.h"
Paul Bakker8adf13b2013-08-25 14:50:09 +020017
Rich Evans18b78c72015-02-11 14:06:19 +000018#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#endif
22
Paul Bakker8adf13b2013-08-25 14:50:09 +020023#define DFL_FILENAME "file.pem"
24#define DFL_OUTPUT_FILENAME "file.der"
25
Rich Evans18b78c72015-02-11 14:06:19 +000026#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
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020033#if !defined(MBEDTLS_BASE64_C) || !defined(MBEDTLS_FS_IO)
Gilles Peskine449bd832023-01-11 14:50:10 +010034int main(void)
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020035{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020036 mbedtls_printf("MBEDTLS_BASE64_C and/or MBEDTLS_FS_IO not defined.\n");
Gilles Peskine449bd832023-01-11 14:50:10 +010037 mbedtls_exit(0);
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020038}
39#else
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010040
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010041
Paul Bakker8adf13b2013-08-25 14:50:09 +020042/*
43 * global options
44 */
Gilles Peskine449bd832023-01-11 14:50:10 +010045struct options {
Paul Bakker8fc30b12013-11-25 13:29:43 +010046 const char *filename; /* filename of the input file */
47 const char *output_file; /* where to store the output */
Paul Bakker8adf13b2013-08-25 14:50:09 +020048} opt;
49
Michael Schuster8db8d612024-06-01 21:15:02 +020050static int convert_pem_to_der(const unsigned char *input, size_t ilen,
Michael Schuster04200932024-06-12 00:05:25 +020051 unsigned char *output, size_t *olen)
Paul Bakker8adf13b2013-08-25 14:50:09 +020052{
53 int ret;
54 const unsigned char *s1, *s2, *end = input + ilen;
55 size_t len = 0;
56
Gilles Peskine449bd832023-01-11 14:50:10 +010057 s1 = (unsigned char *) strstr((const char *) input, "-----BEGIN");
58 if (s1 == NULL) {
59 return -1;
60 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020061
Gilles Peskine449bd832023-01-11 14:50:10 +010062 s2 = (unsigned char *) strstr((const char *) input, "-----END");
63 if (s2 == NULL) {
64 return -1;
65 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020066
67 s1 += 10;
Gilles Peskine449bd832023-01-11 14:50:10 +010068 while (s1 < end && *s1 != '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020069 s1++;
Gilles Peskine449bd832023-01-11 14:50:10 +010070 }
71 while (s1 < end && *s1 == '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020072 s1++;
Gilles Peskine449bd832023-01-11 14:50:10 +010073 }
74 if (*s1 == '\r') {
75 s1++;
76 }
77 if (*s1 == '\n') {
78 s1++;
79 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020080
Gilles Peskine449bd832023-01-11 14:50:10 +010081 if (s2 <= s1 || s2 > end) {
82 return -1;
83 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020084
Gilles Peskine449bd832023-01-11 14:50:10 +010085 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 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020089
Gilles Peskine449bd832023-01-11 14:50:10 +010090 if (len > *olen) {
91 return -1;
92 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020093
Gilles Peskine449bd832023-01-11 14:50:10 +010094 if ((ret = mbedtls_base64_decode(output, len, &len, (const unsigned char *) s1,
95 s2 - s1)) != 0) {
96 return ret;
Paul Bakker8adf13b2013-08-25 14:50:09 +020097 }
98
99 *olen = len;
100
Gilles Peskine449bd832023-01-11 14:50:10 +0100101 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200102}
103
104/*
105 * Load all data from a file into a given buffer.
106 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100107static int load_file(const char *path, unsigned char **buf, size_t *n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200108{
109 FILE *f;
110 long size;
111
Gilles Peskine449bd832023-01-11 14:50:10 +0100112 if ((f = fopen(path, "rb")) == NULL) {
113 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200114 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100115
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);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200122
123 *n = (size_t) size;
124
Gilles Peskine449bd832023-01-11 14:50:10 +0100125 if (*n + 1 == 0 ||
126 (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
127 fclose(f);
128 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200129 }
130
Gilles Peskine449bd832023-01-11 14:50:10 +0100131 if (fread(*buf, 1, *n, f) != *n) {
132 fclose(f);
133 free(*buf);
Alfred Klomp1d42b3e2014-07-14 22:09:21 +0200134 *buf = NULL;
Gilles Peskine449bd832023-01-11 14:50:10 +0100135 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200136 }
137
Gilles Peskine449bd832023-01-11 14:50:10 +0100138 fclose(f);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200139
140 (*buf)[*n] = '\0';
141
Gilles Peskine449bd832023-01-11 14:50:10 +0100142 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200143}
144
145/*
146 * Write buffer to a file
147 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100148static int write_file(const char *path, unsigned char *buf, size_t n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200149{
150 FILE *f;
151
Gilles Peskine449bd832023-01-11 14:50:10 +0100152 if ((f = fopen(path, "wb")) == NULL) {
153 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200154 }
155
Gilles Peskine449bd832023-01-11 14:50:10 +0100156 if (fwrite(buf, 1, n, f) != n) {
157 fclose(f);
158 return -1;
159 }
160
161 fclose(f);
162 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200163}
164
Gilles Peskine449bd832023-01-11 14:50:10 +0100165int main(int argc, char *argv[])
Paul Bakker8adf13b2013-08-25 14:50:09 +0200166{
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100167 int ret = 1;
168 int exit_code = MBEDTLS_EXIT_FAILURE;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200169 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);
Paul Bakkerc97f9f62013-11-30 15:13:02 +0100173 int i;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200174 char *p, *q;
175
176 /*
177 * Set to sane values
178 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100179 memset(buf, 0, sizeof(buf));
180 memset(der_buffer, 0, sizeof(der_buffer));
Paul Bakker8adf13b2013-08-25 14:50:09 +0200181
Aditya Deshpande644a5c02023-01-30 15:58:50 +0000182 if (argc < 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100183usage:
184 mbedtls_printf(USAGE);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200185 goto exit;
186 }
187
188 opt.filename = DFL_FILENAME;
189 opt.output_file = DFL_OUTPUT_FILENAME;
190
Gilles Peskine449bd832023-01-11 14:50:10 +0100191 for (i = 1; i < argc; i++) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200192
193 p = argv[i];
Gilles Peskine449bd832023-01-11 14:50:10 +0100194 if ((q = strchr(p, '=')) == NULL) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200195 goto usage;
Gilles Peskine449bd832023-01-11 14:50:10 +0100196 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200197 *q++ = '\0';
198
Gilles Peskine449bd832023-01-11 14:50:10 +0100199 if (strcmp(p, "filename") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200200 opt.filename = q;
Gilles Peskine449bd832023-01-11 14:50:10 +0100201 } else if (strcmp(p, "output_file") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200202 opt.output_file = q;
Gilles Peskine449bd832023-01-11 14:50:10 +0100203 } else {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200204 goto usage;
Gilles Peskine449bd832023-01-11 14:50:10 +0100205 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200206 }
207
208 /*
209 * 1.1. Load the PEM file
210 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100211 mbedtls_printf("\n . Loading the PEM file ...");
212 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200213
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 ret = load_file(opt.filename, &pem_buffer, &pem_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200215
Gilles Peskine449bd832023-01-11 14:50:10 +0100216 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200217#ifdef MBEDTLS_ERROR_C
Gilles Peskine449bd832023-01-11 14:50:10 +0100218 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200219#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100220 mbedtls_printf(" failed\n ! load_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200221 goto exit;
222 }
223
Gilles Peskine449bd832023-01-11 14:50:10 +0100224 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200225
226 /*
227 * 1.2. Convert from PEM to DER
228 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100229 mbedtls_printf(" . Converting from PEM to DER ...");
230 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200231
Gilles Peskine449bd832023-01-11 14:50:10 +0100232 if ((ret = convert_pem_to_der(pem_buffer, pem_size, der_buffer, &der_size)) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200233#ifdef MBEDTLS_ERROR_C
Gilles Peskine449bd832023-01-11 14:50:10 +0100234 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200235#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100236 mbedtls_printf(" failed\n ! convert_pem_to_der %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200237 goto exit;
238 }
239
Gilles Peskine449bd832023-01-11 14:50:10 +0100240 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200241
242 /*
243 * 1.3. Write the DER file
244 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100245 mbedtls_printf(" . Writing the DER file ...");
246 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200247
Gilles Peskine449bd832023-01-11 14:50:10 +0100248 ret = write_file(opt.output_file, der_buffer, der_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200249
Gilles Peskine449bd832023-01-11 14:50:10 +0100250 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200251#ifdef MBEDTLS_ERROR_C
Gilles Peskine449bd832023-01-11 14:50:10 +0100252 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200253#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100254 mbedtls_printf(" failed\n ! write_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200255 goto exit;
256 }
257
Gilles Peskine449bd832023-01-11 14:50:10 +0100258 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200259
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100260 exit_code = MBEDTLS_EXIT_SUCCESS;
261
Paul Bakker8adf13b2013-08-25 14:50:09 +0200262exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100263 free(pem_buffer);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200264
Gilles Peskine449bd832023-01-11 14:50:10 +0100265 mbedtls_exit(exit_code);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200266}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200267#endif /* MBEDTLS_BASE64_C && MBEDTLS_FS_IO */