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