This Trac instance is not used for development anymore!

We migrated our development workflow to git and Gitea.
To test the future redirection, replace trac by ariadne in the page URL.

source: ps/trunk/build/premake/premake5/contrib/mbedtls/library/pem.c

Last change on this file was 20366, checked in by Itms, 7 years ago

Alpha 12 version of Premake 5, including prebuilt binary for Windows.
Directly taken from https://premake.github.io/.

Refs #3729.

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