blob: d25b0574760a6bc4b0d36f134cd822046fcd5bb6 [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
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * 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.
Paul Bakker8adf13b2013-08-25 14:50:09 +020018 */
19
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020020#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000021#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020022#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020023#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020024#endif
Paul Bakker8adf13b2013-08-25 14:50:09 +020025
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000026#include "mbedtls/platform.h"
Rich Evansf90016a2015-01-19 14:26:37 +000027
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_FS_IO)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000029#include "mbedtls/error.h"
30#include "mbedtls/base64.h"
Paul Bakker8adf13b2013-08-25 14:50:09 +020031
Rich Evans18b78c72015-02-11 14:06:19 +000032#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#endif
36
Paul Bakker8adf13b2013-08-25 14:50:09 +020037#define DFL_FILENAME "file.pem"
38#define DFL_OUTPUT_FILENAME "file.der"
39
Rich Evans18b78c72015-02-11 14:06:19 +000040#define USAGE \
41 "\n usage: pem2der param=<>...\n" \
42 "\n acceptable parameters:\n" \
43 " filename=%%s default: file.pem\n" \
44 " output_file=%%s default: file.der\n" \
45 "\n"
46
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020047#if !defined(MBEDTLS_BASE64_C) || !defined(MBEDTLS_FS_IO)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010048int main(void)
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020049{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020050 mbedtls_printf("MBEDTLS_BASE64_C and/or MBEDTLS_FS_IO not defined.\n");
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010051 mbedtls_exit(0);
Manuel Pégourié-Gonnard7831b0c2013-09-20 12:29:56 +020052}
53#else
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010054
Manuel Pégourié-Gonnard3ef6a6d2018-12-10 14:31:45 +010055
Paul Bakker8adf13b2013-08-25 14:50:09 +020056/*
57 * global options
58 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010059struct options {
Paul Bakker8fc30b12013-11-25 13:29:43 +010060 const char *filename; /* filename of the input file */
61 const char *output_file; /* where to store the output */
Paul Bakker8adf13b2013-08-25 14:50:09 +020062} opt;
63
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010064int convert_pem_to_der(const unsigned char *input, size_t ilen,
65 unsigned char *output, size_t *olen)
Paul Bakker8adf13b2013-08-25 14:50:09 +020066{
67 int ret;
68 const unsigned char *s1, *s2, *end = input + ilen;
69 size_t len = 0;
70
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010071 s1 = (unsigned char *) strstr((const char *) input, "-----BEGIN");
72 if (s1 == NULL) {
73 return -1;
74 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020075
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010076 s2 = (unsigned char *) strstr((const char *) input, "-----END");
77 if (s2 == NULL) {
78 return -1;
79 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020080
81 s1 += 10;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010082 while (s1 < end && *s1 != '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020083 s1++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010084 }
85 while (s1 < end && *s1 == '-') {
Paul Bakker8adf13b2013-08-25 14:50:09 +020086 s1++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010087 }
88 if (*s1 == '\r') {
89 s1++;
90 }
91 if (*s1 == '\n') {
92 s1++;
93 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020094
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010095 if (s2 <= s1 || s2 > end) {
96 return -1;
97 }
Paul Bakker8adf13b2013-08-25 14:50:09 +020098
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010099 ret = mbedtls_base64_decode(NULL, 0, &len, (const unsigned char *) s1, s2 - s1);
100 if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) {
101 return ret;
102 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200103
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100104 if (len > *olen) {
105 return -1;
106 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200107
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100108 if ((ret = mbedtls_base64_decode(output, len, &len, (const unsigned char *) s1,
109 s2 - s1)) != 0) {
110 return ret;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200111 }
112
113 *olen = len;
114
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100115 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200116}
117
118/*
119 * Load all data from a file into a given buffer.
120 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100121static int load_file(const char *path, unsigned char **buf, size_t *n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200122{
123 FILE *f;
124 long size;
125
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100126 if ((f = fopen(path, "rb")) == NULL) {
127 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200128 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100129
130 fseek(f, 0, SEEK_END);
131 if ((size = ftell(f)) == -1) {
132 fclose(f);
133 return -1;
134 }
135 fseek(f, 0, SEEK_SET);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200136
137 *n = (size_t) size;
138
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100139 if (*n + 1 == 0 ||
140 (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
141 fclose(f);
142 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200143 }
144
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100145 if (fread(*buf, 1, *n, f) != *n) {
146 fclose(f);
147 free(*buf);
Alfred Klomp1d42b3e2014-07-14 22:09:21 +0200148 *buf = NULL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100149 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200150 }
151
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100152 fclose(f);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200153
154 (*buf)[*n] = '\0';
155
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100156 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200157}
158
159/*
160 * Write buffer to a file
161 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100162static int write_file(const char *path, unsigned char *buf, size_t n)
Paul Bakker8adf13b2013-08-25 14:50:09 +0200163{
164 FILE *f;
165
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100166 if ((f = fopen(path, "wb")) == NULL) {
167 return -1;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200168 }
169
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100170 if (fwrite(buf, 1, n, f) != n) {
171 fclose(f);
172 return -1;
173 }
174
175 fclose(f);
176 return 0;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200177}
178
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100179int main(int argc, char *argv[])
Paul Bakker8adf13b2013-08-25 14:50:09 +0200180{
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100181 int ret = 1;
182 int exit_code = MBEDTLS_EXIT_FAILURE;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200183 unsigned char *pem_buffer = NULL;
184 unsigned char der_buffer[4096];
185 char buf[1024];
186 size_t pem_size, der_size = sizeof(der_buffer);
Paul Bakkerc97f9f62013-11-30 15:13:02 +0100187 int i;
Paul Bakker8adf13b2013-08-25 14:50:09 +0200188 char *p, *q;
189
190 /*
191 * Set to sane values
192 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100193 memset(buf, 0, sizeof(buf));
194 memset(der_buffer, 0, sizeof(der_buffer));
Paul Bakker8adf13b2013-08-25 14:50:09 +0200195
Aditya Deshpande0504ac22023-01-30 15:58:50 +0000196 if (argc < 2) {
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100197usage:
198 mbedtls_printf(USAGE);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200199 goto exit;
200 }
201
202 opt.filename = DFL_FILENAME;
203 opt.output_file = DFL_OUTPUT_FILENAME;
204
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100205 for (i = 1; i < argc; i++) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200206
207 p = argv[i];
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100208 if ((q = strchr(p, '=')) == NULL) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200209 goto usage;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100210 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200211 *q++ = '\0';
212
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100213 if (strcmp(p, "filename") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200214 opt.filename = q;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100215 } else if (strcmp(p, "output_file") == 0) {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200216 opt.output_file = q;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100217 } else {
Paul Bakker8adf13b2013-08-25 14:50:09 +0200218 goto usage;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100219 }
Paul Bakker8adf13b2013-08-25 14:50:09 +0200220 }
221
222 /*
223 * 1.1. Load the PEM file
224 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100225 mbedtls_printf("\n . Loading the PEM file ...");
226 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200227
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100228 ret = load_file(opt.filename, &pem_buffer, &pem_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200229
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100230 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200231#ifdef MBEDTLS_ERROR_C
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100232 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200233#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100234 mbedtls_printf(" failed\n ! load_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200235 goto exit;
236 }
237
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100238 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200239
240 /*
241 * 1.2. Convert from PEM to DER
242 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100243 mbedtls_printf(" . Converting from PEM to DER ...");
244 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200245
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100246 if ((ret = convert_pem_to_der(pem_buffer, pem_size, der_buffer, &der_size)) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200247#ifdef MBEDTLS_ERROR_C
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100248 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200249#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100250 mbedtls_printf(" failed\n ! convert_pem_to_der %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200251 goto exit;
252 }
253
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100254 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200255
256 /*
257 * 1.3. Write the DER file
258 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100259 mbedtls_printf(" . Writing the DER file ...");
260 fflush(stdout);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200261
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100262 ret = write_file(opt.output_file, der_buffer, der_size);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200263
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100264 if (ret != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200265#ifdef MBEDTLS_ERROR_C
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100266 mbedtls_strerror(ret, buf, 1024);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200267#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100268 mbedtls_printf(" failed\n ! write_file returned %d - %s\n\n", ret, buf);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200269 goto exit;
270 }
271
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100272 mbedtls_printf(" ok\n");
Paul Bakker8adf13b2013-08-25 14:50:09 +0200273
Andres Amaya Garcia78dabe02018-04-29 22:08:41 +0100274 exit_code = MBEDTLS_EXIT_SUCCESS;
275
Paul Bakker8adf13b2013-08-25 14:50:09 +0200276exit:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100277 free(pem_buffer);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200278
279#if defined(_WIN32)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100280 mbedtls_printf(" + Press Enter to exit this program.\n");
281 fflush(stdout); getchar();
Paul Bakker8adf13b2013-08-25 14:50:09 +0200282#endif
283
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100284 mbedtls_exit(exit_code);
Paul Bakker8adf13b2013-08-25 14:50:09 +0200285}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200286#endif /* MBEDTLS_BASE64_C && MBEDTLS_FS_IO */