1
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
78
81
84
87
90
91
95
96
97
98
101
104
107
110
113
116
117
118
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
148
149
152
153
154
155
156
157
158
159
160
161
162
165
166
167
168
169
170
171
172
173
174
175
178
179
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
210
211
214
215
216
217
218
219
220
221
222
223
224
225
227
228
229
230
231
232
233
234
235
236
237
238
240
241
243
245
246
249
250
251
252
255
256
257
258
261
262
263
266
269
274
275
276
277
280
283
286
287
288
289
290
291
292
293
294
295
296
299
304
305
306
307
308
309
310
311
314
315
316
317
318
319
320
323
324
325
326
327
328
329
330
341
342
343
346
347
348
349
350
351
354
355
358
363
364
365
367
368
369
372
373
374
375
378
379
382
383
388
389
390
391
392
393
394
395
396
397
398
399
400
401
407
408
409
417
418
422
423
429
434
435
438
440
441
442
443
444
445
446
447
448
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
476
477
481
482
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
/* ... */
#include "common.h"
#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
#include "mbedtls/pem.h"
#include "mbedtls/base64.h"
#include "mbedtls/des.h"
#include "mbedtls/aes.h"
#include "mbedtls/md5.h"
#include "mbedtls/cipher.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#include "mbedtls/platform.h"
10 includes
#if defined(MBEDTLS_PEM_PARSE_C)
void mbedtls_pem_init(mbedtls_pem_context *ctx)
{
memset(ctx, 0, sizeof(mbedtls_pem_context));
}{ ... }
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
(defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C))
/* ... */
static int pem_get_iv(const unsigned char *s, unsigned char *iv,
size_t iv_len)
{
size_t i, j, k;
memset(iv, 0, iv_len);
for (i = 0; i < iv_len * 2; i++, s++) {
if (*s >= '0' && *s <= '9') {
j = *s - '0';
}if (*s >= '0' && *s <= '9') { ... } else
if (*s >= 'A' && *s <= 'F') {
j = *s - '7';
}else if (*s >= 'A' && *s <= 'F') { ... } else
if (*s >= 'a' && *s <= 'f') {
j = *s - 'W';
}else if (*s >= 'a' && *s <= 'f') { ... } else {
return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
}else { ... }
k = ((i & 1) != 0) ? j : j << 4;
iv[i >> 1] = (unsigned char) (iv[i >> 1] | k);
}for (i = 0; i < iv_len * 2; i++, s++) { ... }
return 0;
}{ ... }
static int pem_pbkdf1(unsigned char *key, size_t keylen,
unsigned char *iv,
const unsigned char *pwd, size_t pwdlen)
{
mbedtls_md5_context md5_ctx;
unsigned char md5sum[16];
size_t use_len;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md5_init(&md5_ctx);
/* ... */
if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0) { ... }
if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0) { ... }
if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0) { ... }
if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0) { ... }
if (keylen <= 16) {
memcpy(key, md5sum, keylen);
goto exit;
}if (keylen <= 16) { ... }
memcpy(key, md5sum, 16);
/* ... */
if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0) { ... }
if ((ret = mbedtls_md5_update_ret(&md5_ctx, md5sum, 16)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_update_ret(&md5_ctx, md5sum, 16)) != 0) { ... }
if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0) { ... }
if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0) { ... }
if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0) {
goto exit;
}if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0) { ... }
use_len = 16;
if (keylen < 32) {
use_len = keylen - 16;
}if (keylen < 32) { ... }
memcpy(key + 16, md5sum, use_len);
exit:
mbedtls_md5_free(&md5_ctx);
mbedtls_platform_zeroize(md5sum, 16);
return ret;
}{ ... }
#if defined(MBEDTLS_DES_C)
/* ... */
static int pem_des_decrypt(unsigned char des_iv[8],
unsigned char *buf, size_t buflen,
const unsigned char *pwd, size_t pwdlen)
{
mbedtls_des_context des_ctx;
unsigned char des_key[8];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_des_init(&des_ctx);
if ((ret = pem_pbkdf1(des_key, 8, des_iv, pwd, pwdlen)) != 0) {
goto exit;
}if ((ret = pem_pbkdf1(des_key, 8, des_iv, pwd, pwdlen)) != 0) { ... }
if ((ret = mbedtls_des_setkey_dec(&des_ctx, des_key)) != 0) {
goto exit;
}if ((ret = mbedtls_des_setkey_dec(&des_ctx, des_key)) != 0) { ... }
ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_DECRYPT, buflen,
des_iv, buf, buf);
exit:
mbedtls_des_free(&des_ctx);
mbedtls_platform_zeroize(des_key, 8);
return ret;
}pem_des_decrypt (unsigned char des_iv[8], unsigned char *buf, size_t buflen, const unsigned char *pwd, size_t pwdlen) { ... }
/* ... */
static int pem_des3_decrypt(unsigned char des3_iv[8],
unsigned char *buf, size_t buflen,
const unsigned char *pwd, size_t pwdlen)
{
mbedtls_des3_context des3_ctx;
unsigned char des3_key[24];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_des3_init(&des3_ctx);
if ((ret = pem_pbkdf1(des3_key, 24, des3_iv, pwd, pwdlen)) != 0) {
goto exit;
}if ((ret = pem_pbkdf1(des3_key, 24, des3_iv, pwd, pwdlen)) != 0) { ... }
if ((ret = mbedtls_des3_set3key_dec(&des3_ctx, des3_key)) != 0) {
goto exit;
}if ((ret = mbedtls_des3_set3key_dec(&des3_ctx, des3_key)) != 0) { ... }
ret = mbedtls_des3_crypt_cbc(&des3_ctx, MBEDTLS_DES_DECRYPT, buflen,
des3_iv, buf, buf);
exit:
mbedtls_des3_free(&des3_ctx);
mbedtls_platform_zeroize(des3_key, 24);
return ret;
}pem_des3_decrypt (unsigned char des3_iv[8], unsigned char *buf, size_t buflen, const unsigned char *pwd, size_t pwdlen) { ... }
/* ... */#endif
#if defined(MBEDTLS_AES_C)
/* ... */
static int pem_aes_decrypt(unsigned char aes_iv[16], unsigned int keylen,
unsigned char *buf, size_t buflen,
const unsigned char *pwd, size_t pwdlen)
{
mbedtls_aes_context aes_ctx;
unsigned char aes_key[32];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_aes_init(&aes_ctx);
if ((ret = pem_pbkdf1(aes_key, keylen, aes_iv, pwd, pwdlen)) != 0) {
goto exit;
}if ((ret = pem_pbkdf1(aes_key, keylen, aes_iv, pwd, pwdlen)) != 0) { ... }
if ((ret = mbedtls_aes_setkey_dec(&aes_ctx, aes_key, keylen * 8)) != 0) {
goto exit;
}if ((ret = mbedtls_aes_setkey_dec(&aes_ctx, aes_key, keylen * 8)) != 0) { ... }
ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, buflen,
aes_iv, buf, buf);
exit:
mbedtls_aes_free(&aes_ctx);
mbedtls_platform_zeroize(aes_key, keylen);
return ret;
}{ ... }
#endif/* ... */
/* ... */
#endif
/* ... */
int mbedtls_pem_read_buffer(mbedtls_pem_context *ctx, const char *header, const char *footer,
const unsigned char *data, const unsigned char *pwd,
size_t pwdlen, size_t *use_len)
{
int ret, enc;
size_t len;
unsigned char *buf;
const unsigned char *s1, *s2, *end;
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
(defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C))
unsigned char pem_iv[16];
mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE;/* ... */
#else
((void) pwd);
((void) pwdlen);/* ... */
#endif
/* ... */
if (ctx == NULL) {
return MBEDTLS_ERR_PEM_BAD_INPUT_DATA;
}if (ctx == NULL) { ... }
s1 = (unsigned char *) strstr((const char *) data, header);
if (s1 == NULL) {
return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
}if (s1 == NULL) { ... }
s2 = (unsigned char *) strstr((const char *) data, footer);
if (s2 == NULL || s2 <= s1) {
return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
}if (s2 == NULL || s2 <= s1) { ... }
s1 += strlen(header);
if (*s1 == ' ') {
s1++;
}if (*s1 == ' ') { ... }
if (*s1 == '\r') {
s1++;
}if (*s1 == '\r') { ... }
if (*s1 == '\n') {
s1++;
}if (*s1 == '\n') { ... } else {
return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
}else { ... }
end = s2;
end += strlen(footer);
if (*end == ' ') {
end++;
}if (*end == ' ') { ... }
if (*end == '\r') {
end++;
}if (*end == '\r') { ... }
if (*end == '\n') {
end++;
}if (*end == '\n') { ... }
*use_len = end - data;
enc = 0;
if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) {
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
(defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C))
enc++;
s1 += 22;
if (*s1 == '\r') {
s1++;
}if (*s1 == '\r') { ... }
if (*s1 == '\n') {
s1++;
}if (*s1 == '\n') { ... } else {
return MBEDTLS_ERR_PEM_INVALID_DATA;
}else { ... }
#if defined(MBEDTLS_DES_C)
if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) {
enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC;
s1 += 23;
if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) {
return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
}if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { ... }
s1 += 16;
}if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) { ... } else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) {
enc_alg = MBEDTLS_CIPHER_DES_CBC;
s1 += 18;
if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) {
return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
}if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { ... }
s1 += 16;
}else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) { ... }
/* ... */#endif
#if defined(MBEDTLS_AES_C)
if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) {
if (s2 - s1 < 22) {
return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
}if (s2 - s1 < 22) { ... } else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0) {
enc_alg = MBEDTLS_CIPHER_AES_128_CBC;
}else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0) { ... } else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0) {
enc_alg = MBEDTLS_CIPHER_AES_192_CBC;
}else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0) { ... } else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0) {
enc_alg = MBEDTLS_CIPHER_AES_256_CBC;
}else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0) { ... } else {
return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
}else { ... }
s1 += 22;
if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0) {
return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
}if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0) { ... }
s1 += 32;
}if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) { ... }
/* ... */#endif
if (enc_alg == MBEDTLS_CIPHER_NONE) {
return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
}if (enc_alg == MBEDTLS_CIPHER_NONE) { ... }
if (*s1 == '\r') {
s1++;
}if (*s1 == '\r') { ... }
if (*s1 == '\n') {
s1++;
}if (*s1 == '\n') { ... } else {
return MBEDTLS_ERR_PEM_INVALID_DATA;
}else { ... }
/* ... */#else
return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE;
#endif
/* ... */
}if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) { ... }
if (s1 >= s2) {
return MBEDTLS_ERR_PEM_INVALID_DATA;
}if (s1 >= s2) { ... }
ret = mbedtls_base64_decode(NULL, 0, &len, s1, s2 - s1);
if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret);
}if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) { ... }
if ((buf = mbedtls_calloc(1, len)) == NULL) {
return MBEDTLS_ERR_PEM_ALLOC_FAILED;
}if ((buf = mbedtls_calloc(1, len)) == NULL) { ... }
if ((ret = mbedtls_base64_decode(buf, len, &len, s1, s2 - s1)) != 0) {
mbedtls_platform_zeroize(buf, len);
mbedtls_free(buf);
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret);
}if ((ret = mbedtls_base64_decode(buf, len, &len, s1, s2 - s1)) != 0) { ... }
if (enc != 0) {
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
(defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C))
if (pwd == NULL) {
mbedtls_platform_zeroize(buf, len);
mbedtls_free(buf);
return MBEDTLS_ERR_PEM_PASSWORD_REQUIRED;
}if (pwd == NULL) { ... }
ret = 0;
#if defined(MBEDTLS_DES_C)
if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC) {
ret = pem_des3_decrypt(pem_iv, buf, len, pwd, pwdlen);
}if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC) { ... } else if (enc_alg == MBEDTLS_CIPHER_DES_CBC) {
ret = pem_des_decrypt(pem_iv, buf, len, pwd, pwdlen);
}else if (enc_alg == MBEDTLS_CIPHER_DES_CBC) { ... }
/* ... */#endif
#if defined(MBEDTLS_AES_C)
if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC) {
ret = pem_aes_decrypt(pem_iv, 16, buf, len, pwd, pwdlen);
}if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC) { ... } else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC) {
ret = pem_aes_decrypt(pem_iv, 24, buf, len, pwd, pwdlen);
}else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC) { ... } else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC) {
ret = pem_aes_decrypt(pem_iv, 32, buf, len, pwd, pwdlen);
}else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC) { ... }
/* ... */#endif
if (ret != 0) {
mbedtls_free(buf);
return ret;
}if (ret != 0) { ... }
/* ... */
if (len <= 2 || buf[0] != 0x30 || buf[1] > 0x83) {
mbedtls_platform_zeroize(buf, len);
mbedtls_free(buf);
return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH;
}if (len <= 2 || buf[0] != 0x30 || buf[1] > 0x83) { ... }
/* ... */#else
mbedtls_platform_zeroize(buf, len);
mbedtls_free(buf);
return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE;/* ... */
#endif
/* ... */
}if (enc != 0) { ... }
ctx->buf = buf;
ctx->buflen = len;
return 0;
}{ ... }
void mbedtls_pem_free(mbedtls_pem_context *ctx)
{
if (ctx->buf != NULL) {
mbedtls_platform_zeroize(ctx->buf, ctx->buflen);
mbedtls_free(ctx->buf);
}if (ctx->buf != NULL) { ... }
mbedtls_free(ctx->info);
mbedtls_platform_zeroize(ctx, sizeof(mbedtls_pem_context));
}{ ... }
#endif/* ... */
#if defined(MBEDTLS_PEM_WRITE_C)
int mbedtls_pem_write_buffer(const char *header, const char *footer,
const unsigned char *der_data, size_t der_len,
unsigned char *buf, size_t buf_len, size_t *olen)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *encode_buf = NULL, *c, *p = buf;
size_t len = 0, use_len, add_len = 0;
mbedtls_base64_encode(NULL, 0, &use_len, der_data, der_len);
add_len = strlen(header) + strlen(footer) + (use_len / 64) + 1;
if (use_len + add_len > buf_len) {
*olen = use_len + add_len;
return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
}if (use_len + add_len > buf_len) { ... }
if (use_len != 0 &&
((encode_buf = mbedtls_calloc(1, use_len)) == NULL)) {
return MBEDTLS_ERR_PEM_ALLOC_FAILED;
}if (use_len != 0 && ((encode_buf = mbedtls_calloc(1, use_len)) == NULL)) { ... }
if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data,
der_len)) != 0) {
mbedtls_free(encode_buf);
return ret;
}if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data, der_len)) != 0) { ... }
memcpy(p, header, strlen(header));
p += strlen(header);
c = encode_buf;
while (use_len) {
len = (use_len > 64) ? 64 : use_len;
memcpy(p, c, len);
use_len -= len;
p += len;
c += len;
*p++ = '\n';
}while (use_len) { ... }
memcpy(p, footer, strlen(footer));
p += strlen(footer);
*p++ = '\0';
*olen = p - buf;
memset(buf + *olen, 0, buf_len - *olen);
mbedtls_free(encode_buf);
return 0;
}mbedtls_pem_write_buffer (const char *header, const char *footer, const unsigned char *der_data, size_t der_len, unsigned char *buf, size_t buf_len, size_t *olen) { ... }
/* ... */#endif /* ... */
#endif