text
[RRG-proxmark3.git] / common / mbedtls / pem.c
blob8d90beee77b89c6cbd43fec751b022aa82c64f60
1 /*
2 * Privacy Enhanced Mail (PEM) decoding
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "common.h"
22 #if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
24 #include "mbedtls/pem.h"
25 #include "mbedtls/base64.h"
26 #include "mbedtls/des.h"
27 #include "mbedtls/aes.h"
28 #include "mbedtls/md5.h"
29 #include "mbedtls/cipher.h"
30 #include "mbedtls/platform_util.h"
31 #include "mbedtls/error.h"
33 #include <string.h>
35 #if defined(MBEDTLS_PLATFORM_C)
36 #include "mbedtls/platform.h"
37 #else
38 #include <stdlib.h>
39 #define mbedtls_calloc calloc
40 #define mbedtls_free free
41 #endif
43 #if defined(MBEDTLS_PEM_PARSE_C)
44 void mbedtls_pem_init(mbedtls_pem_context *ctx) {
45 memset(ctx, 0, sizeof(mbedtls_pem_context));
48 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
49 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
51 * Read a 16-byte hex string and convert it to binary
53 static int pem_get_iv(const unsigned char *s, unsigned char *iv,
54 size_t iv_len) {
55 size_t i, j, k;
57 memset(iv, 0, iv_len);
59 for (i = 0; i < iv_len * 2; i++, s++) {
60 if (*s >= '0' && *s <= '9') j = *s - '0';
61 else if (*s >= 'A' && *s <= 'F') j = *s - '7';
62 else if (*s >= 'a' && *s <= 'f') j = *s - 'W';
63 else
64 return (MBEDTLS_ERR_PEM_INVALID_ENC_IV);
66 k = ((i & 1) != 0) ? j : j << 4;
68 iv[i >> 1] = (unsigned char)(iv[i >> 1] | k);
71 return (0);
74 static int pem_pbkdf1(unsigned char *key, size_t keylen,
75 unsigned char *iv,
76 const unsigned char *pwd, size_t pwdlen) {
77 mbedtls_md5_context md5_ctx;
78 unsigned char md5sum[16];
79 size_t use_len;
80 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
82 mbedtls_md5_init(&md5_ctx);
85 * key[ 0..15] = MD5(pwd || IV)
87 if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0)
88 goto exit;
89 if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0)
90 goto exit;
91 if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0)
92 goto exit;
93 if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0)
94 goto exit;
96 if (keylen <= 16) {
97 memcpy(key, md5sum, keylen);
98 goto exit;
101 memcpy(key, md5sum, 16);
104 * key[16..23] = MD5(key[ 0..15] || pwd || IV])
106 if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0)
107 goto exit;
108 if ((ret = mbedtls_md5_update_ret(&md5_ctx, md5sum, 16)) != 0)
109 goto exit;
110 if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0)
111 goto exit;
112 if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0)
113 goto exit;
114 if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0)
115 goto exit;
117 use_len = 16;
118 if (keylen < 32)
119 use_len = keylen - 16;
121 memcpy(key + 16, md5sum, use_len);
123 exit:
124 mbedtls_md5_free(&md5_ctx);
125 mbedtls_platform_zeroize(md5sum, 16);
127 return (ret);
130 #if defined(MBEDTLS_DES_C)
132 * Decrypt with DES-CBC, using PBKDF1 for key derivation
134 static int pem_des_decrypt(unsigned char des_iv[8],
135 unsigned char *buf, size_t buflen,
136 const unsigned char *pwd, size_t pwdlen) {
137 mbedtls_des_context des_ctx;
138 unsigned char des_key[8];
139 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
141 mbedtls_des_init(&des_ctx);
143 if ((ret = pem_pbkdf1(des_key, 8, des_iv, pwd, pwdlen)) != 0)
144 goto exit;
146 if ((ret = mbedtls_des_setkey_dec(&des_ctx, des_key)) != 0)
147 goto exit;
148 ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_DECRYPT, buflen,
149 des_iv, buf, buf);
151 exit:
152 mbedtls_des_free(&des_ctx);
153 mbedtls_platform_zeroize(des_key, 8);
155 return (ret);
159 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
161 static int pem_des3_decrypt(unsigned char des3_iv[8],
162 unsigned char *buf, size_t buflen,
163 const unsigned char *pwd, size_t pwdlen) {
164 mbedtls_des3_context des3_ctx;
165 unsigned char des3_key[24];
166 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
168 mbedtls_des3_init(&des3_ctx);
170 if ((ret = pem_pbkdf1(des3_key, 24, des3_iv, pwd, pwdlen)) != 0)
171 goto exit;
173 if ((ret = mbedtls_des3_set3key_dec(&des3_ctx, des3_key)) != 0)
174 goto exit;
175 ret = mbedtls_des3_crypt_cbc(&des3_ctx, MBEDTLS_DES_DECRYPT, buflen,
176 des3_iv, buf, buf);
178 exit:
179 mbedtls_des3_free(&des3_ctx);
180 mbedtls_platform_zeroize(des3_key, 24);
182 return (ret);
184 #endif /* MBEDTLS_DES_C */
186 #if defined(MBEDTLS_AES_C)
188 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
190 static int pem_aes_decrypt(unsigned char aes_iv[16], unsigned int keylen,
191 unsigned char *buf, size_t buflen,
192 const unsigned char *pwd, size_t pwdlen) {
193 mbedtls_aes_context aes_ctx;
194 unsigned char aes_key[32];
195 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
197 mbedtls_aes_init(&aes_ctx);
199 if ((ret = pem_pbkdf1(aes_key, keylen, aes_iv, pwd, pwdlen)) != 0)
200 goto exit;
202 if ((ret = mbedtls_aes_setkey_dec(&aes_ctx, aes_key, keylen * 8)) != 0)
203 goto exit;
204 ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, buflen,
205 aes_iv, buf, buf);
207 exit:
208 mbedtls_aes_free(&aes_ctx);
209 mbedtls_platform_zeroize(aes_key, keylen);
211 return (ret);
213 #endif /* MBEDTLS_AES_C */
215 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
216 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
218 int mbedtls_pem_read_buffer(mbedtls_pem_context *ctx, const char *header, const char *footer,
219 const unsigned char *data, const unsigned char *pwd,
220 size_t pwdlen, size_t *use_len) {
221 int ret, enc;
222 size_t len;
223 unsigned char *buf;
224 const unsigned char *s1, *s2, *end;
225 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
226 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
227 unsigned char pem_iv[16];
228 mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE;
229 #else
230 ((void) pwd);
231 ((void) pwdlen);
232 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
233 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
235 if (ctx == NULL)
236 return (MBEDTLS_ERR_PEM_BAD_INPUT_DATA);
238 s1 = (unsigned char *) strstr((const char *) data, header);
240 if (s1 == NULL)
241 return (MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT);
243 s2 = (unsigned char *) strstr((const char *) data, footer);
245 if (s2 == NULL || s2 <= s1)
246 return (MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT);
248 s1 += strlen(header);
249 if (*s1 == ' ') s1++;
250 if (*s1 == '\r') s1++;
251 if (*s1 == '\n') s1++;
252 else return (MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT);
254 end = s2;
255 end += strlen(footer);
256 if (*end == ' ') end++;
257 if (*end == '\r') end++;
258 if (*end == '\n') end++;
259 *use_len = end - data;
261 enc = 0;
263 if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) {
264 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
265 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
266 enc++;
268 s1 += 22;
269 if (*s1 == '\r') s1++;
270 if (*s1 == '\n') s1++;
271 else return (MBEDTLS_ERR_PEM_INVALID_DATA);
274 #if defined(MBEDTLS_DES_C)
275 if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) {
276 enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC;
278 s1 += 23;
279 if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0)
280 return (MBEDTLS_ERR_PEM_INVALID_ENC_IV);
282 s1 += 16;
283 } else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) {
284 enc_alg = MBEDTLS_CIPHER_DES_CBC;
286 s1 += 18;
287 if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0)
288 return (MBEDTLS_ERR_PEM_INVALID_ENC_IV);
290 s1 += 16;
292 #endif /* MBEDTLS_DES_C */
294 #if defined(MBEDTLS_AES_C)
295 if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) {
296 if (s2 - s1 < 22)
297 return (MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG);
298 else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0)
299 enc_alg = MBEDTLS_CIPHER_AES_128_CBC;
300 else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0)
301 enc_alg = MBEDTLS_CIPHER_AES_192_CBC;
302 else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0)
303 enc_alg = MBEDTLS_CIPHER_AES_256_CBC;
304 else
305 return (MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG);
307 s1 += 22;
308 if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0)
309 return (MBEDTLS_ERR_PEM_INVALID_ENC_IV);
311 s1 += 32;
313 #endif /* MBEDTLS_AES_C */
315 if (enc_alg == MBEDTLS_CIPHER_NONE)
316 return (MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG);
318 if (*s1 == '\r') s1++;
319 if (*s1 == '\n') s1++;
320 else return (MBEDTLS_ERR_PEM_INVALID_DATA);
321 #else
322 return (MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE);
323 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
324 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
327 if (s1 >= s2)
328 return (MBEDTLS_ERR_PEM_INVALID_DATA);
330 ret = mbedtls_base64_decode(NULL, 0, &len, s1, s2 - s1);
332 if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER)
333 return (MBEDTLS_ERR_PEM_INVALID_DATA + ret);
335 if ((buf = mbedtls_calloc(1, len)) == NULL)
336 return (MBEDTLS_ERR_PEM_ALLOC_FAILED);
338 if ((ret = mbedtls_base64_decode(buf, len, &len, s1, s2 - s1)) != 0) {
339 mbedtls_platform_zeroize(buf, len);
340 mbedtls_free(buf);
341 return (MBEDTLS_ERR_PEM_INVALID_DATA + ret);
344 if (enc != 0) {
345 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
346 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
347 if (pwd == NULL) {
348 mbedtls_platform_zeroize(buf, len);
349 mbedtls_free(buf);
350 return (MBEDTLS_ERR_PEM_PASSWORD_REQUIRED);
353 ret = 0;
355 #if defined(MBEDTLS_DES_C)
356 if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC)
357 ret = pem_des3_decrypt(pem_iv, buf, len, pwd, pwdlen);
358 else if (enc_alg == MBEDTLS_CIPHER_DES_CBC)
359 ret = pem_des_decrypt(pem_iv, buf, len, pwd, pwdlen);
360 #endif /* MBEDTLS_DES_C */
362 #if defined(MBEDTLS_AES_C)
363 if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC)
364 ret = pem_aes_decrypt(pem_iv, 16, buf, len, pwd, pwdlen);
365 else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC)
366 ret = pem_aes_decrypt(pem_iv, 24, buf, len, pwd, pwdlen);
367 else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC)
368 ret = pem_aes_decrypt(pem_iv, 32, buf, len, pwd, pwdlen);
369 #endif /* MBEDTLS_AES_C */
371 if (ret != 0) {
372 mbedtls_free(buf);
373 return (ret);
377 * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
378 * length bytes (allow 4 to be sure) in all known use cases.
380 * Use that as a heuristic to try to detect password mismatches.
382 if (len <= 2 || buf[0] != 0x30 || buf[1] > 0x83) {
383 mbedtls_platform_zeroize(buf, len);
384 mbedtls_free(buf);
385 return (MBEDTLS_ERR_PEM_PASSWORD_MISMATCH);
387 #else
388 mbedtls_platform_zeroize(buf, len);
389 mbedtls_free(buf);
390 return (MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE);
391 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
392 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
395 ctx->buf = buf;
396 ctx->buflen = len;
398 return (0);
401 void mbedtls_pem_free(mbedtls_pem_context *ctx) {
402 if (ctx->buf != NULL) {
403 mbedtls_platform_zeroize(ctx->buf, ctx->buflen);
404 mbedtls_free(ctx->buf);
406 mbedtls_free(ctx->info);
408 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_pem_context));
410 #endif /* MBEDTLS_PEM_PARSE_C */
412 #if defined(MBEDTLS_PEM_WRITE_C)
413 int mbedtls_pem_write_buffer(const char *header, const char *footer,
414 const unsigned char *der_data, size_t der_len,
415 unsigned char *buf, size_t buf_len, size_t *olen) {
416 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
417 unsigned char *encode_buf = NULL, *c, *p = buf;
418 size_t len = 0, use_len, add_len = 0;
420 mbedtls_base64_encode(NULL, 0, &use_len, der_data, der_len);
421 add_len = strlen(header) + strlen(footer) + (use_len / 64) + 1;
423 if (use_len + add_len > buf_len) {
424 *olen = use_len + add_len;
425 return (MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL);
428 if (use_len != 0 &&
429 ((encode_buf = mbedtls_calloc(1, use_len)) == NULL))
430 return (MBEDTLS_ERR_PEM_ALLOC_FAILED);
432 if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data,
433 der_len)) != 0) {
434 mbedtls_free(encode_buf);
435 return (ret);
438 memcpy(p, header, strlen(header));
439 p += strlen(header);
440 c = encode_buf;
442 while (use_len) {
443 len = (use_len > 64) ? 64 : use_len;
444 memcpy(p, c, len);
445 use_len -= len;
446 p += len;
447 c += len;
448 *p++ = '\n';
451 memcpy(p, footer, strlen(footer));
452 p += strlen(footer);
454 *p++ = '\0';
455 *olen = p - buf;
457 /* Clean any remaining data previously written to the buffer */
458 memset(buf + *olen, 0, buf_len - *olen);
460 mbedtls_free(encode_buf);
461 return (0);
463 #endif /* MBEDTLS_PEM_WRITE_C */
464 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */