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