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