xref: /aosp_15_r20/external/mbedtls/library/pem.c (revision 62c56f9862f102b96d72393aff6076c951fb8148)
1*62c56f98SSadaf Ebrahimi /*
2*62c56f98SSadaf Ebrahimi  *  Privacy Enhanced Mail (PEM) decoding
3*62c56f98SSadaf Ebrahimi  *
4*62c56f98SSadaf Ebrahimi  *  Copyright The Mbed TLS Contributors
5*62c56f98SSadaf Ebrahimi  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6*62c56f98SSadaf Ebrahimi  */
7*62c56f98SSadaf Ebrahimi 
8*62c56f98SSadaf Ebrahimi #include "common.h"
9*62c56f98SSadaf Ebrahimi 
10*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
11*62c56f98SSadaf Ebrahimi 
12*62c56f98SSadaf Ebrahimi #include "mbedtls/pem.h"
13*62c56f98SSadaf Ebrahimi #include "mbedtls/base64.h"
14*62c56f98SSadaf Ebrahimi #include "mbedtls/des.h"
15*62c56f98SSadaf Ebrahimi #include "mbedtls/aes.h"
16*62c56f98SSadaf Ebrahimi #include "mbedtls/md.h"
17*62c56f98SSadaf Ebrahimi #include "mbedtls/cipher.h"
18*62c56f98SSadaf Ebrahimi #include "mbedtls/platform_util.h"
19*62c56f98SSadaf Ebrahimi #include "mbedtls/error.h"
20*62c56f98SSadaf Ebrahimi 
21*62c56f98SSadaf Ebrahimi #include <string.h>
22*62c56f98SSadaf Ebrahimi 
23*62c56f98SSadaf Ebrahimi #include "mbedtls/platform.h"
24*62c56f98SSadaf Ebrahimi 
25*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_USE_PSA_CRYPTO)
26*62c56f98SSadaf Ebrahimi #include "psa/crypto.h"
27*62c56f98SSadaf Ebrahimi #endif
28*62c56f98SSadaf Ebrahimi 
29*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_MD_CAN_MD5) &&  \
30*62c56f98SSadaf Ebrahimi     defined(MBEDTLS_CIPHER_MODE_CBC) &&                             \
31*62c56f98SSadaf Ebrahimi     (defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C))
32*62c56f98SSadaf Ebrahimi #define PEM_RFC1421
33*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_MD_CAN_MD5 &&
34*62c56f98SSadaf Ebrahimi           MBEDTLS_CIPHER_MODE_CBC &&
35*62c56f98SSadaf Ebrahimi           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
36*62c56f98SSadaf Ebrahimi 
37*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_init(mbedtls_pem_context * ctx)38*62c56f98SSadaf Ebrahimi void mbedtls_pem_init(mbedtls_pem_context *ctx)
39*62c56f98SSadaf Ebrahimi {
40*62c56f98SSadaf Ebrahimi     memset(ctx, 0, sizeof(mbedtls_pem_context));
41*62c56f98SSadaf Ebrahimi }
42*62c56f98SSadaf Ebrahimi 
43*62c56f98SSadaf Ebrahimi #if defined(PEM_RFC1421)
44*62c56f98SSadaf Ebrahimi /*
45*62c56f98SSadaf Ebrahimi  * Read a 16-byte hex string and convert it to binary
46*62c56f98SSadaf Ebrahimi  */
pem_get_iv(const unsigned char * s,unsigned char * iv,size_t iv_len)47*62c56f98SSadaf Ebrahimi static int pem_get_iv(const unsigned char *s, unsigned char *iv,
48*62c56f98SSadaf Ebrahimi                       size_t iv_len)
49*62c56f98SSadaf Ebrahimi {
50*62c56f98SSadaf Ebrahimi     size_t i, j, k;
51*62c56f98SSadaf Ebrahimi 
52*62c56f98SSadaf Ebrahimi     memset(iv, 0, iv_len);
53*62c56f98SSadaf Ebrahimi 
54*62c56f98SSadaf Ebrahimi     for (i = 0; i < iv_len * 2; i++, s++) {
55*62c56f98SSadaf Ebrahimi         if (*s >= '0' && *s <= '9') {
56*62c56f98SSadaf Ebrahimi             j = *s - '0';
57*62c56f98SSadaf Ebrahimi         } else
58*62c56f98SSadaf Ebrahimi         if (*s >= 'A' && *s <= 'F') {
59*62c56f98SSadaf Ebrahimi             j = *s - '7';
60*62c56f98SSadaf Ebrahimi         } else
61*62c56f98SSadaf Ebrahimi         if (*s >= 'a' && *s <= 'f') {
62*62c56f98SSadaf Ebrahimi             j = *s - 'W';
63*62c56f98SSadaf Ebrahimi         } else {
64*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
65*62c56f98SSadaf Ebrahimi         }
66*62c56f98SSadaf Ebrahimi 
67*62c56f98SSadaf Ebrahimi         k = ((i & 1) != 0) ? j : j << 4;
68*62c56f98SSadaf Ebrahimi 
69*62c56f98SSadaf Ebrahimi         iv[i >> 1] = (unsigned char) (iv[i >> 1] | k);
70*62c56f98SSadaf Ebrahimi     }
71*62c56f98SSadaf Ebrahimi 
72*62c56f98SSadaf Ebrahimi     return 0;
73*62c56f98SSadaf Ebrahimi }
74*62c56f98SSadaf Ebrahimi 
pem_pbkdf1(unsigned char * key,size_t keylen,unsigned char * iv,const unsigned char * pwd,size_t pwdlen)75*62c56f98SSadaf Ebrahimi static int pem_pbkdf1(unsigned char *key, size_t keylen,
76*62c56f98SSadaf Ebrahimi                       unsigned char *iv,
77*62c56f98SSadaf Ebrahimi                       const unsigned char *pwd, size_t pwdlen)
78*62c56f98SSadaf Ebrahimi {
79*62c56f98SSadaf Ebrahimi     mbedtls_md_context_t md5_ctx;
80*62c56f98SSadaf Ebrahimi     const mbedtls_md_info_t *md5_info;
81*62c56f98SSadaf Ebrahimi     unsigned char md5sum[16];
82*62c56f98SSadaf Ebrahimi     size_t use_len;
83*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
84*62c56f98SSadaf Ebrahimi 
85*62c56f98SSadaf Ebrahimi     mbedtls_md_init(&md5_ctx);
86*62c56f98SSadaf Ebrahimi 
87*62c56f98SSadaf Ebrahimi     /* Prepare the context. (setup() errors gracefully on NULL info.) */
88*62c56f98SSadaf Ebrahimi     md5_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
89*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_setup(&md5_ctx, md5_info, 0)) != 0) {
90*62c56f98SSadaf Ebrahimi         goto exit;
91*62c56f98SSadaf Ebrahimi     }
92*62c56f98SSadaf Ebrahimi 
93*62c56f98SSadaf Ebrahimi     /*
94*62c56f98SSadaf Ebrahimi      * key[ 0..15] = MD5(pwd || IV)
95*62c56f98SSadaf Ebrahimi      */
96*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_starts(&md5_ctx)) != 0) {
97*62c56f98SSadaf Ebrahimi         goto exit;
98*62c56f98SSadaf Ebrahimi     }
99*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_update(&md5_ctx, pwd, pwdlen)) != 0) {
100*62c56f98SSadaf Ebrahimi         goto exit;
101*62c56f98SSadaf Ebrahimi     }
102*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_update(&md5_ctx, iv,  8)) != 0) {
103*62c56f98SSadaf Ebrahimi         goto exit;
104*62c56f98SSadaf Ebrahimi     }
105*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_finish(&md5_ctx, md5sum)) != 0) {
106*62c56f98SSadaf Ebrahimi         goto exit;
107*62c56f98SSadaf Ebrahimi     }
108*62c56f98SSadaf Ebrahimi 
109*62c56f98SSadaf Ebrahimi     if (keylen <= 16) {
110*62c56f98SSadaf Ebrahimi         memcpy(key, md5sum, keylen);
111*62c56f98SSadaf Ebrahimi         goto exit;
112*62c56f98SSadaf Ebrahimi     }
113*62c56f98SSadaf Ebrahimi 
114*62c56f98SSadaf Ebrahimi     memcpy(key, md5sum, 16);
115*62c56f98SSadaf Ebrahimi 
116*62c56f98SSadaf Ebrahimi     /*
117*62c56f98SSadaf Ebrahimi      * key[16..23] = MD5(key[ 0..15] || pwd || IV])
118*62c56f98SSadaf Ebrahimi      */
119*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_starts(&md5_ctx)) != 0) {
120*62c56f98SSadaf Ebrahimi         goto exit;
121*62c56f98SSadaf Ebrahimi     }
122*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_update(&md5_ctx, md5sum, 16)) != 0) {
123*62c56f98SSadaf Ebrahimi         goto exit;
124*62c56f98SSadaf Ebrahimi     }
125*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_update(&md5_ctx, pwd, pwdlen)) != 0) {
126*62c56f98SSadaf Ebrahimi         goto exit;
127*62c56f98SSadaf Ebrahimi     }
128*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_update(&md5_ctx, iv, 8)) != 0) {
129*62c56f98SSadaf Ebrahimi         goto exit;
130*62c56f98SSadaf Ebrahimi     }
131*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_md_finish(&md5_ctx, md5sum)) != 0) {
132*62c56f98SSadaf Ebrahimi         goto exit;
133*62c56f98SSadaf Ebrahimi     }
134*62c56f98SSadaf Ebrahimi 
135*62c56f98SSadaf Ebrahimi     use_len = 16;
136*62c56f98SSadaf Ebrahimi     if (keylen < 32) {
137*62c56f98SSadaf Ebrahimi         use_len = keylen - 16;
138*62c56f98SSadaf Ebrahimi     }
139*62c56f98SSadaf Ebrahimi 
140*62c56f98SSadaf Ebrahimi     memcpy(key + 16, md5sum, use_len);
141*62c56f98SSadaf Ebrahimi 
142*62c56f98SSadaf Ebrahimi exit:
143*62c56f98SSadaf Ebrahimi     mbedtls_md_free(&md5_ctx);
144*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(md5sum, 16);
145*62c56f98SSadaf Ebrahimi 
146*62c56f98SSadaf Ebrahimi     return ret;
147*62c56f98SSadaf Ebrahimi }
148*62c56f98SSadaf Ebrahimi 
149*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_DES_C)
150*62c56f98SSadaf Ebrahimi /*
151*62c56f98SSadaf Ebrahimi  * Decrypt with DES-CBC, using PBKDF1 for key derivation
152*62c56f98SSadaf Ebrahimi  */
pem_des_decrypt(unsigned char des_iv[8],unsigned char * buf,size_t buflen,const unsigned char * pwd,size_t pwdlen)153*62c56f98SSadaf Ebrahimi static int pem_des_decrypt(unsigned char des_iv[8],
154*62c56f98SSadaf Ebrahimi                            unsigned char *buf, size_t buflen,
155*62c56f98SSadaf Ebrahimi                            const unsigned char *pwd, size_t pwdlen)
156*62c56f98SSadaf Ebrahimi {
157*62c56f98SSadaf Ebrahimi     mbedtls_des_context des_ctx;
158*62c56f98SSadaf Ebrahimi     unsigned char des_key[8];
159*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
160*62c56f98SSadaf Ebrahimi 
161*62c56f98SSadaf Ebrahimi     mbedtls_des_init(&des_ctx);
162*62c56f98SSadaf Ebrahimi 
163*62c56f98SSadaf Ebrahimi     if ((ret = pem_pbkdf1(des_key, 8, des_iv, pwd, pwdlen)) != 0) {
164*62c56f98SSadaf Ebrahimi         goto exit;
165*62c56f98SSadaf Ebrahimi     }
166*62c56f98SSadaf Ebrahimi 
167*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_des_setkey_dec(&des_ctx, des_key)) != 0) {
168*62c56f98SSadaf Ebrahimi         goto exit;
169*62c56f98SSadaf Ebrahimi     }
170*62c56f98SSadaf Ebrahimi     ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_DECRYPT, buflen,
171*62c56f98SSadaf Ebrahimi                                 des_iv, buf, buf);
172*62c56f98SSadaf Ebrahimi 
173*62c56f98SSadaf Ebrahimi exit:
174*62c56f98SSadaf Ebrahimi     mbedtls_des_free(&des_ctx);
175*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(des_key, 8);
176*62c56f98SSadaf Ebrahimi 
177*62c56f98SSadaf Ebrahimi     return ret;
178*62c56f98SSadaf Ebrahimi }
179*62c56f98SSadaf Ebrahimi 
180*62c56f98SSadaf Ebrahimi /*
181*62c56f98SSadaf Ebrahimi  * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
182*62c56f98SSadaf Ebrahimi  */
pem_des3_decrypt(unsigned char des3_iv[8],unsigned char * buf,size_t buflen,const unsigned char * pwd,size_t pwdlen)183*62c56f98SSadaf Ebrahimi static int pem_des3_decrypt(unsigned char des3_iv[8],
184*62c56f98SSadaf Ebrahimi                             unsigned char *buf, size_t buflen,
185*62c56f98SSadaf Ebrahimi                             const unsigned char *pwd, size_t pwdlen)
186*62c56f98SSadaf Ebrahimi {
187*62c56f98SSadaf Ebrahimi     mbedtls_des3_context des3_ctx;
188*62c56f98SSadaf Ebrahimi     unsigned char des3_key[24];
189*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
190*62c56f98SSadaf Ebrahimi 
191*62c56f98SSadaf Ebrahimi     mbedtls_des3_init(&des3_ctx);
192*62c56f98SSadaf Ebrahimi 
193*62c56f98SSadaf Ebrahimi     if ((ret = pem_pbkdf1(des3_key, 24, des3_iv, pwd, pwdlen)) != 0) {
194*62c56f98SSadaf Ebrahimi         goto exit;
195*62c56f98SSadaf Ebrahimi     }
196*62c56f98SSadaf Ebrahimi 
197*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_des3_set3key_dec(&des3_ctx, des3_key)) != 0) {
198*62c56f98SSadaf Ebrahimi         goto exit;
199*62c56f98SSadaf Ebrahimi     }
200*62c56f98SSadaf Ebrahimi     ret = mbedtls_des3_crypt_cbc(&des3_ctx, MBEDTLS_DES_DECRYPT, buflen,
201*62c56f98SSadaf Ebrahimi                                  des3_iv, buf, buf);
202*62c56f98SSadaf Ebrahimi 
203*62c56f98SSadaf Ebrahimi exit:
204*62c56f98SSadaf Ebrahimi     mbedtls_des3_free(&des3_ctx);
205*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(des3_key, 24);
206*62c56f98SSadaf Ebrahimi 
207*62c56f98SSadaf Ebrahimi     return ret;
208*62c56f98SSadaf Ebrahimi }
209*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_DES_C */
210*62c56f98SSadaf Ebrahimi 
211*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_AES_C)
212*62c56f98SSadaf Ebrahimi /*
213*62c56f98SSadaf Ebrahimi  * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
214*62c56f98SSadaf Ebrahimi  */
pem_aes_decrypt(unsigned char aes_iv[16],unsigned int keylen,unsigned char * buf,size_t buflen,const unsigned char * pwd,size_t pwdlen)215*62c56f98SSadaf Ebrahimi static int pem_aes_decrypt(unsigned char aes_iv[16], unsigned int keylen,
216*62c56f98SSadaf Ebrahimi                            unsigned char *buf, size_t buflen,
217*62c56f98SSadaf Ebrahimi                            const unsigned char *pwd, size_t pwdlen)
218*62c56f98SSadaf Ebrahimi {
219*62c56f98SSadaf Ebrahimi     mbedtls_aes_context aes_ctx;
220*62c56f98SSadaf Ebrahimi     unsigned char aes_key[32];
221*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
222*62c56f98SSadaf Ebrahimi 
223*62c56f98SSadaf Ebrahimi     mbedtls_aes_init(&aes_ctx);
224*62c56f98SSadaf Ebrahimi 
225*62c56f98SSadaf Ebrahimi     if ((ret = pem_pbkdf1(aes_key, keylen, aes_iv, pwd, pwdlen)) != 0) {
226*62c56f98SSadaf Ebrahimi         goto exit;
227*62c56f98SSadaf Ebrahimi     }
228*62c56f98SSadaf Ebrahimi 
229*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_aes_setkey_dec(&aes_ctx, aes_key, keylen * 8)) != 0) {
230*62c56f98SSadaf Ebrahimi         goto exit;
231*62c56f98SSadaf Ebrahimi     }
232*62c56f98SSadaf Ebrahimi     ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, buflen,
233*62c56f98SSadaf Ebrahimi                                 aes_iv, buf, buf);
234*62c56f98SSadaf Ebrahimi 
235*62c56f98SSadaf Ebrahimi exit:
236*62c56f98SSadaf Ebrahimi     mbedtls_aes_free(&aes_ctx);
237*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(aes_key, keylen);
238*62c56f98SSadaf Ebrahimi 
239*62c56f98SSadaf Ebrahimi     return ret;
240*62c56f98SSadaf Ebrahimi }
241*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_AES_C */
242*62c56f98SSadaf Ebrahimi 
243*62c56f98SSadaf Ebrahimi #endif /* PEM_RFC1421 */
244*62c56f98SSadaf Ebrahimi 
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)245*62c56f98SSadaf Ebrahimi int mbedtls_pem_read_buffer(mbedtls_pem_context *ctx, const char *header, const char *footer,
246*62c56f98SSadaf Ebrahimi                             const unsigned char *data, const unsigned char *pwd,
247*62c56f98SSadaf Ebrahimi                             size_t pwdlen, size_t *use_len)
248*62c56f98SSadaf Ebrahimi {
249*62c56f98SSadaf Ebrahimi     int ret, enc;
250*62c56f98SSadaf Ebrahimi     size_t len;
251*62c56f98SSadaf Ebrahimi     unsigned char *buf;
252*62c56f98SSadaf Ebrahimi     const unsigned char *s1, *s2, *end;
253*62c56f98SSadaf Ebrahimi #if defined(PEM_RFC1421)
254*62c56f98SSadaf Ebrahimi     unsigned char pem_iv[16];
255*62c56f98SSadaf Ebrahimi     mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE;
256*62c56f98SSadaf Ebrahimi #else
257*62c56f98SSadaf Ebrahimi     ((void) pwd);
258*62c56f98SSadaf Ebrahimi     ((void) pwdlen);
259*62c56f98SSadaf Ebrahimi #endif /* PEM_RFC1421 */
260*62c56f98SSadaf Ebrahimi 
261*62c56f98SSadaf Ebrahimi     if (ctx == NULL) {
262*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_BAD_INPUT_DATA;
263*62c56f98SSadaf Ebrahimi     }
264*62c56f98SSadaf Ebrahimi 
265*62c56f98SSadaf Ebrahimi     s1 = (unsigned char *) strstr((const char *) data, header);
266*62c56f98SSadaf Ebrahimi 
267*62c56f98SSadaf Ebrahimi     if (s1 == NULL) {
268*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
269*62c56f98SSadaf Ebrahimi     }
270*62c56f98SSadaf Ebrahimi 
271*62c56f98SSadaf Ebrahimi     s2 = (unsigned char *) strstr((const char *) data, footer);
272*62c56f98SSadaf Ebrahimi 
273*62c56f98SSadaf Ebrahimi     if (s2 == NULL || s2 <= s1) {
274*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
275*62c56f98SSadaf Ebrahimi     }
276*62c56f98SSadaf Ebrahimi 
277*62c56f98SSadaf Ebrahimi     s1 += strlen(header);
278*62c56f98SSadaf Ebrahimi     if (*s1 == ' ') {
279*62c56f98SSadaf Ebrahimi         s1++;
280*62c56f98SSadaf Ebrahimi     }
281*62c56f98SSadaf Ebrahimi     if (*s1 == '\r') {
282*62c56f98SSadaf Ebrahimi         s1++;
283*62c56f98SSadaf Ebrahimi     }
284*62c56f98SSadaf Ebrahimi     if (*s1 == '\n') {
285*62c56f98SSadaf Ebrahimi         s1++;
286*62c56f98SSadaf Ebrahimi     } else {
287*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
288*62c56f98SSadaf Ebrahimi     }
289*62c56f98SSadaf Ebrahimi 
290*62c56f98SSadaf Ebrahimi     end = s2;
291*62c56f98SSadaf Ebrahimi     end += strlen(footer);
292*62c56f98SSadaf Ebrahimi     if (*end == ' ') {
293*62c56f98SSadaf Ebrahimi         end++;
294*62c56f98SSadaf Ebrahimi     }
295*62c56f98SSadaf Ebrahimi     if (*end == '\r') {
296*62c56f98SSadaf Ebrahimi         end++;
297*62c56f98SSadaf Ebrahimi     }
298*62c56f98SSadaf Ebrahimi     if (*end == '\n') {
299*62c56f98SSadaf Ebrahimi         end++;
300*62c56f98SSadaf Ebrahimi     }
301*62c56f98SSadaf Ebrahimi     *use_len = end - data;
302*62c56f98SSadaf Ebrahimi 
303*62c56f98SSadaf Ebrahimi     enc = 0;
304*62c56f98SSadaf Ebrahimi 
305*62c56f98SSadaf Ebrahimi     if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) {
306*62c56f98SSadaf Ebrahimi #if defined(PEM_RFC1421)
307*62c56f98SSadaf Ebrahimi         enc++;
308*62c56f98SSadaf Ebrahimi 
309*62c56f98SSadaf Ebrahimi         s1 += 22;
310*62c56f98SSadaf Ebrahimi         if (*s1 == '\r') {
311*62c56f98SSadaf Ebrahimi             s1++;
312*62c56f98SSadaf Ebrahimi         }
313*62c56f98SSadaf Ebrahimi         if (*s1 == '\n') {
314*62c56f98SSadaf Ebrahimi             s1++;
315*62c56f98SSadaf Ebrahimi         } else {
316*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PEM_INVALID_DATA;
317*62c56f98SSadaf Ebrahimi         }
318*62c56f98SSadaf Ebrahimi 
319*62c56f98SSadaf Ebrahimi 
320*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_DES_C)
321*62c56f98SSadaf Ebrahimi         if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) {
322*62c56f98SSadaf Ebrahimi             enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC;
323*62c56f98SSadaf Ebrahimi 
324*62c56f98SSadaf Ebrahimi             s1 += 23;
325*62c56f98SSadaf Ebrahimi             if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) {
326*62c56f98SSadaf Ebrahimi                 return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
327*62c56f98SSadaf Ebrahimi             }
328*62c56f98SSadaf Ebrahimi 
329*62c56f98SSadaf Ebrahimi             s1 += 16;
330*62c56f98SSadaf Ebrahimi         } else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) {
331*62c56f98SSadaf Ebrahimi             enc_alg = MBEDTLS_CIPHER_DES_CBC;
332*62c56f98SSadaf Ebrahimi 
333*62c56f98SSadaf Ebrahimi             s1 += 18;
334*62c56f98SSadaf Ebrahimi             if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) {
335*62c56f98SSadaf Ebrahimi                 return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
336*62c56f98SSadaf Ebrahimi             }
337*62c56f98SSadaf Ebrahimi 
338*62c56f98SSadaf Ebrahimi             s1 += 16;
339*62c56f98SSadaf Ebrahimi         }
340*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_DES_C */
341*62c56f98SSadaf Ebrahimi 
342*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_AES_C)
343*62c56f98SSadaf Ebrahimi         if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) {
344*62c56f98SSadaf Ebrahimi             if (s2 - s1 < 22) {
345*62c56f98SSadaf Ebrahimi                 return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
346*62c56f98SSadaf Ebrahimi             } else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0) {
347*62c56f98SSadaf Ebrahimi                 enc_alg = MBEDTLS_CIPHER_AES_128_CBC;
348*62c56f98SSadaf Ebrahimi             } else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0) {
349*62c56f98SSadaf Ebrahimi                 enc_alg = MBEDTLS_CIPHER_AES_192_CBC;
350*62c56f98SSadaf Ebrahimi             } else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0) {
351*62c56f98SSadaf Ebrahimi                 enc_alg = MBEDTLS_CIPHER_AES_256_CBC;
352*62c56f98SSadaf Ebrahimi             } else {
353*62c56f98SSadaf Ebrahimi                 return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
354*62c56f98SSadaf Ebrahimi             }
355*62c56f98SSadaf Ebrahimi 
356*62c56f98SSadaf Ebrahimi             s1 += 22;
357*62c56f98SSadaf Ebrahimi             if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0) {
358*62c56f98SSadaf Ebrahimi                 return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
359*62c56f98SSadaf Ebrahimi             }
360*62c56f98SSadaf Ebrahimi 
361*62c56f98SSadaf Ebrahimi             s1 += 32;
362*62c56f98SSadaf Ebrahimi         }
363*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_AES_C */
364*62c56f98SSadaf Ebrahimi 
365*62c56f98SSadaf Ebrahimi         if (enc_alg == MBEDTLS_CIPHER_NONE) {
366*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
367*62c56f98SSadaf Ebrahimi         }
368*62c56f98SSadaf Ebrahimi 
369*62c56f98SSadaf Ebrahimi         if (*s1 == '\r') {
370*62c56f98SSadaf Ebrahimi             s1++;
371*62c56f98SSadaf Ebrahimi         }
372*62c56f98SSadaf Ebrahimi         if (*s1 == '\n') {
373*62c56f98SSadaf Ebrahimi             s1++;
374*62c56f98SSadaf Ebrahimi         } else {
375*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PEM_INVALID_DATA;
376*62c56f98SSadaf Ebrahimi         }
377*62c56f98SSadaf Ebrahimi #else
378*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE;
379*62c56f98SSadaf Ebrahimi #endif /* PEM_RFC1421 */
380*62c56f98SSadaf Ebrahimi     }
381*62c56f98SSadaf Ebrahimi 
382*62c56f98SSadaf Ebrahimi     if (s1 >= s2) {
383*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_INVALID_DATA;
384*62c56f98SSadaf Ebrahimi     }
385*62c56f98SSadaf Ebrahimi 
386*62c56f98SSadaf Ebrahimi     ret = mbedtls_base64_decode(NULL, 0, &len, s1, s2 - s1);
387*62c56f98SSadaf Ebrahimi 
388*62c56f98SSadaf Ebrahimi     if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) {
389*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret);
390*62c56f98SSadaf Ebrahimi     }
391*62c56f98SSadaf Ebrahimi 
392*62c56f98SSadaf Ebrahimi     if ((buf = mbedtls_calloc(1, len)) == NULL) {
393*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_ALLOC_FAILED;
394*62c56f98SSadaf Ebrahimi     }
395*62c56f98SSadaf Ebrahimi 
396*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_base64_decode(buf, len, &len, s1, s2 - s1)) != 0) {
397*62c56f98SSadaf Ebrahimi         mbedtls_zeroize_and_free(buf, len);
398*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret);
399*62c56f98SSadaf Ebrahimi     }
400*62c56f98SSadaf Ebrahimi 
401*62c56f98SSadaf Ebrahimi     if (enc != 0) {
402*62c56f98SSadaf Ebrahimi #if defined(PEM_RFC1421)
403*62c56f98SSadaf Ebrahimi         if (pwd == NULL) {
404*62c56f98SSadaf Ebrahimi             mbedtls_zeroize_and_free(buf, len);
405*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PEM_PASSWORD_REQUIRED;
406*62c56f98SSadaf Ebrahimi         }
407*62c56f98SSadaf Ebrahimi 
408*62c56f98SSadaf Ebrahimi         ret = 0;
409*62c56f98SSadaf Ebrahimi 
410*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_DES_C)
411*62c56f98SSadaf Ebrahimi         if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC) {
412*62c56f98SSadaf Ebrahimi             ret = pem_des3_decrypt(pem_iv, buf, len, pwd, pwdlen);
413*62c56f98SSadaf Ebrahimi         } else if (enc_alg == MBEDTLS_CIPHER_DES_CBC) {
414*62c56f98SSadaf Ebrahimi             ret = pem_des_decrypt(pem_iv, buf, len, pwd, pwdlen);
415*62c56f98SSadaf Ebrahimi         }
416*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_DES_C */
417*62c56f98SSadaf Ebrahimi 
418*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_AES_C)
419*62c56f98SSadaf Ebrahimi         if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC) {
420*62c56f98SSadaf Ebrahimi             ret = pem_aes_decrypt(pem_iv, 16, buf, len, pwd, pwdlen);
421*62c56f98SSadaf Ebrahimi         } else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC) {
422*62c56f98SSadaf Ebrahimi             ret = pem_aes_decrypt(pem_iv, 24, buf, len, pwd, pwdlen);
423*62c56f98SSadaf Ebrahimi         } else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC) {
424*62c56f98SSadaf Ebrahimi             ret = pem_aes_decrypt(pem_iv, 32, buf, len, pwd, pwdlen);
425*62c56f98SSadaf Ebrahimi         }
426*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_AES_C */
427*62c56f98SSadaf Ebrahimi 
428*62c56f98SSadaf Ebrahimi         if (ret != 0) {
429*62c56f98SSadaf Ebrahimi             mbedtls_free(buf);
430*62c56f98SSadaf Ebrahimi             return ret;
431*62c56f98SSadaf Ebrahimi         }
432*62c56f98SSadaf Ebrahimi 
433*62c56f98SSadaf Ebrahimi         /*
434*62c56f98SSadaf Ebrahimi          * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
435*62c56f98SSadaf Ebrahimi          * length bytes (allow 4 to be sure) in all known use cases.
436*62c56f98SSadaf Ebrahimi          *
437*62c56f98SSadaf Ebrahimi          * Use that as a heuristic to try to detect password mismatches.
438*62c56f98SSadaf Ebrahimi          */
439*62c56f98SSadaf Ebrahimi         if (len <= 2 || buf[0] != 0x30 || buf[1] > 0x83) {
440*62c56f98SSadaf Ebrahimi             mbedtls_zeroize_and_free(buf, len);
441*62c56f98SSadaf Ebrahimi             return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH;
442*62c56f98SSadaf Ebrahimi         }
443*62c56f98SSadaf Ebrahimi #else
444*62c56f98SSadaf Ebrahimi         mbedtls_zeroize_and_free(buf, len);
445*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE;
446*62c56f98SSadaf Ebrahimi #endif /* PEM_RFC1421 */
447*62c56f98SSadaf Ebrahimi     }
448*62c56f98SSadaf Ebrahimi 
449*62c56f98SSadaf Ebrahimi     ctx->buf = buf;
450*62c56f98SSadaf Ebrahimi     ctx->buflen = len;
451*62c56f98SSadaf Ebrahimi 
452*62c56f98SSadaf Ebrahimi     return 0;
453*62c56f98SSadaf Ebrahimi }
454*62c56f98SSadaf Ebrahimi 
mbedtls_pem_free(mbedtls_pem_context * ctx)455*62c56f98SSadaf Ebrahimi void mbedtls_pem_free(mbedtls_pem_context *ctx)
456*62c56f98SSadaf Ebrahimi {
457*62c56f98SSadaf Ebrahimi     if (ctx->buf != NULL) {
458*62c56f98SSadaf Ebrahimi         mbedtls_zeroize_and_free(ctx->buf, ctx->buflen);
459*62c56f98SSadaf Ebrahimi     }
460*62c56f98SSadaf Ebrahimi     mbedtls_free(ctx->info);
461*62c56f98SSadaf Ebrahimi 
462*62c56f98SSadaf Ebrahimi     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_pem_context));
463*62c56f98SSadaf Ebrahimi }
464*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_PEM_PARSE_C */
465*62c56f98SSadaf Ebrahimi 
466*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_PEM_WRITE_C)
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)467*62c56f98SSadaf Ebrahimi int mbedtls_pem_write_buffer(const char *header, const char *footer,
468*62c56f98SSadaf Ebrahimi                              const unsigned char *der_data, size_t der_len,
469*62c56f98SSadaf Ebrahimi                              unsigned char *buf, size_t buf_len, size_t *olen)
470*62c56f98SSadaf Ebrahimi {
471*62c56f98SSadaf Ebrahimi     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
472*62c56f98SSadaf Ebrahimi     unsigned char *encode_buf = NULL, *c, *p = buf;
473*62c56f98SSadaf Ebrahimi     size_t len = 0, use_len, add_len = 0;
474*62c56f98SSadaf Ebrahimi 
475*62c56f98SSadaf Ebrahimi     mbedtls_base64_encode(NULL, 0, &use_len, der_data, der_len);
476*62c56f98SSadaf Ebrahimi     add_len = strlen(header) + strlen(footer) + (((use_len > 2) ? (use_len - 2) : 0) / 64) + 1;
477*62c56f98SSadaf Ebrahimi 
478*62c56f98SSadaf Ebrahimi     if (use_len + add_len > buf_len) {
479*62c56f98SSadaf Ebrahimi         *olen = use_len + add_len;
480*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
481*62c56f98SSadaf Ebrahimi     }
482*62c56f98SSadaf Ebrahimi 
483*62c56f98SSadaf Ebrahimi     if (use_len != 0 &&
484*62c56f98SSadaf Ebrahimi         ((encode_buf = mbedtls_calloc(1, use_len)) == NULL)) {
485*62c56f98SSadaf Ebrahimi         return MBEDTLS_ERR_PEM_ALLOC_FAILED;
486*62c56f98SSadaf Ebrahimi     }
487*62c56f98SSadaf Ebrahimi 
488*62c56f98SSadaf Ebrahimi     if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data,
489*62c56f98SSadaf Ebrahimi                                      der_len)) != 0) {
490*62c56f98SSadaf Ebrahimi         mbedtls_free(encode_buf);
491*62c56f98SSadaf Ebrahimi         return ret;
492*62c56f98SSadaf Ebrahimi     }
493*62c56f98SSadaf Ebrahimi 
494*62c56f98SSadaf Ebrahimi     memcpy(p, header, strlen(header));
495*62c56f98SSadaf Ebrahimi     p += strlen(header);
496*62c56f98SSadaf Ebrahimi     c = encode_buf;
497*62c56f98SSadaf Ebrahimi 
498*62c56f98SSadaf Ebrahimi     while (use_len) {
499*62c56f98SSadaf Ebrahimi         len = (use_len > 64) ? 64 : use_len;
500*62c56f98SSadaf Ebrahimi         memcpy(p, c, len);
501*62c56f98SSadaf Ebrahimi         use_len -= len;
502*62c56f98SSadaf Ebrahimi         p += len;
503*62c56f98SSadaf Ebrahimi         c += len;
504*62c56f98SSadaf Ebrahimi         *p++ = '\n';
505*62c56f98SSadaf Ebrahimi     }
506*62c56f98SSadaf Ebrahimi 
507*62c56f98SSadaf Ebrahimi     memcpy(p, footer, strlen(footer));
508*62c56f98SSadaf Ebrahimi     p += strlen(footer);
509*62c56f98SSadaf Ebrahimi 
510*62c56f98SSadaf Ebrahimi     *p++ = '\0';
511*62c56f98SSadaf Ebrahimi     *olen = p - buf;
512*62c56f98SSadaf Ebrahimi 
513*62c56f98SSadaf Ebrahimi     /* Clean any remaining data previously written to the buffer */
514*62c56f98SSadaf Ebrahimi     memset(buf + *olen, 0, buf_len - *olen);
515*62c56f98SSadaf Ebrahimi 
516*62c56f98SSadaf Ebrahimi     mbedtls_free(encode_buf);
517*62c56f98SSadaf Ebrahimi     return 0;
518*62c56f98SSadaf Ebrahimi }
519*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_PEM_WRITE_C */
520*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */
521