Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8774 | rgimad | 1 | /* |
2 | * PKCS#12 Personal Information Exchange Syntax |
||
3 | * |
||
4 | * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved |
||
5 | * SPDX-License-Identifier: GPL-2.0 |
||
6 | * |
||
7 | * This program is free software; you can redistribute it and/or modify |
||
8 | * it under the terms of the GNU General Public License as published by |
||
9 | * the Free Software Foundation; either version 2 of the License, or |
||
10 | * (at your option) any later version. |
||
11 | * |
||
12 | * This program is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | * GNU General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU General Public License along |
||
18 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
20 | * |
||
21 | * This file is part of mbed TLS (https://tls.mbed.org) |
||
22 | */ |
||
23 | /* |
||
24 | * The PKCS #12 Personal Information Exchange Syntax Standard v1.1 |
||
25 | * |
||
26 | * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf |
||
27 | * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn |
||
28 | */ |
||
29 | |||
30 | #if !defined(MBEDTLS_CONFIG_FILE) |
||
31 | #include "mbedtls/config.h" |
||
32 | #else |
||
33 | #include MBEDTLS_CONFIG_FILE |
||
34 | #endif |
||
35 | |||
36 | #if defined(MBEDTLS_PKCS12_C) |
||
37 | |||
38 | #include "mbedtls/pkcs12.h" |
||
39 | #include "mbedtls/asn1.h" |
||
40 | #include "mbedtls/cipher.h" |
||
41 | #include "mbedtls/platform_util.h" |
||
42 | |||
43 | #include |
||
44 | |||
45 | #if defined(MBEDTLS_ARC4_C) |
||
46 | #include "mbedtls/arc4.h" |
||
47 | #endif |
||
48 | |||
49 | #if defined(MBEDTLS_DES_C) |
||
50 | #include "mbedtls/des.h" |
||
51 | #endif |
||
52 | |||
53 | #if defined(MBEDTLS_ASN1_PARSE_C) |
||
54 | |||
55 | static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params, |
||
56 | mbedtls_asn1_buf *salt, int *iterations ) |
||
57 | { |
||
58 | int ret; |
||
59 | unsigned char **p = ¶ms->p; |
||
60 | const unsigned char *end = params->p + params->len; |
||
61 | |||
62 | /* |
||
63 | * pkcs-12PbeParams ::= SEQUENCE { |
||
64 | * salt OCTET STRING, |
||
65 | * iterations INTEGER |
||
66 | * } |
||
67 | * |
||
68 | */ |
||
69 | if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) |
||
70 | return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + |
||
71 | MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); |
||
72 | |||
73 | if( ( ret = mbedtls_asn1_get_tag( p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) |
||
74 | return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); |
||
75 | |||
76 | salt->p = *p; |
||
77 | *p += salt->len; |
||
78 | |||
79 | if( ( ret = mbedtls_asn1_get_int( p, end, iterations ) ) != 0 ) |
||
80 | return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); |
||
81 | |||
82 | if( *p != end ) |
||
83 | return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + |
||
84 | MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); |
||
85 | |||
86 | return( 0 ); |
||
87 | } |
||
88 | |||
89 | #define PKCS12_MAX_PWDLEN 128 |
||
90 | |||
91 | static int pkcs12_pbe_derive_key_iv( mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type, |
||
92 | const unsigned char *pwd, size_t pwdlen, |
||
93 | unsigned char *key, size_t keylen, |
||
94 | unsigned char *iv, size_t ivlen ) |
||
95 | { |
||
96 | int ret, iterations = 0; |
||
97 | mbedtls_asn1_buf salt; |
||
98 | size_t i; |
||
99 | unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2]; |
||
100 | |||
101 | if( pwdlen > PKCS12_MAX_PWDLEN ) |
||
102 | return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); |
||
103 | |||
104 | memset( &salt, 0, sizeof(mbedtls_asn1_buf) ); |
||
105 | memset( &unipwd, 0, sizeof(unipwd) ); |
||
106 | |||
107 | if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt, |
||
108 | &iterations ) ) != 0 ) |
||
109 | return( ret ); |
||
110 | |||
111 | for( i = 0; i < pwdlen; i++ ) |
||
112 | unipwd[i * 2 + 1] = pwd[i]; |
||
113 | |||
114 | if( ( ret = mbedtls_pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2, |
||
115 | salt.p, salt.len, md_type, |
||
116 | MBEDTLS_PKCS12_DERIVE_KEY, iterations ) ) != 0 ) |
||
117 | { |
||
118 | return( ret ); |
||
119 | } |
||
120 | |||
121 | if( iv == NULL || ivlen == 0 ) |
||
122 | return( 0 ); |
||
123 | |||
124 | if( ( ret = mbedtls_pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2, |
||
125 | salt.p, salt.len, md_type, |
||
126 | MBEDTLS_PKCS12_DERIVE_IV, iterations ) ) != 0 ) |
||
127 | { |
||
128 | return( ret ); |
||
129 | } |
||
130 | return( 0 ); |
||
131 | } |
||
132 | |||
133 | #undef PKCS12_MAX_PWDLEN |
||
134 | |||
135 | int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, |
||
136 | const unsigned char *pwd, size_t pwdlen, |
||
137 | const unsigned char *data, size_t len, |
||
138 | unsigned char *output ) |
||
139 | { |
||
140 | #if !defined(MBEDTLS_ARC4_C) |
||
141 | ((void) pbe_params); |
||
142 | ((void) mode); |
||
143 | ((void) pwd); |
||
144 | ((void) pwdlen); |
||
145 | ((void) data); |
||
146 | ((void) len); |
||
147 | ((void) output); |
||
148 | return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); |
||
149 | #else |
||
150 | int ret; |
||
151 | unsigned char key[16]; |
||
152 | mbedtls_arc4_context ctx; |
||
153 | ((void) mode); |
||
154 | |||
155 | mbedtls_arc4_init( &ctx ); |
||
156 | |||
157 | if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, MBEDTLS_MD_SHA1, |
||
158 | pwd, pwdlen, |
||
159 | key, 16, NULL, 0 ) ) != 0 ) |
||
160 | { |
||
161 | return( ret ); |
||
162 | } |
||
163 | |||
164 | mbedtls_arc4_setup( &ctx, key, 16 ); |
||
165 | if( ( ret = mbedtls_arc4_crypt( &ctx, len, data, output ) ) != 0 ) |
||
166 | goto exit; |
||
167 | |||
168 | exit: |
||
169 | mbedtls_platform_zeroize( key, sizeof( key ) ); |
||
170 | mbedtls_arc4_free( &ctx ); |
||
171 | |||
172 | return( ret ); |
||
173 | #endif /* MBEDTLS_ARC4_C */ |
||
174 | } |
||
175 | |||
176 | int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, |
||
177 | mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, |
||
178 | const unsigned char *pwd, size_t pwdlen, |
||
179 | const unsigned char *data, size_t len, |
||
180 | unsigned char *output ) |
||
181 | { |
||
182 | int ret, keylen = 0; |
||
183 | unsigned char key[32]; |
||
184 | unsigned char iv[16]; |
||
185 | const mbedtls_cipher_info_t *cipher_info; |
||
186 | mbedtls_cipher_context_t cipher_ctx; |
||
187 | size_t olen = 0; |
||
188 | |||
189 | cipher_info = mbedtls_cipher_info_from_type( cipher_type ); |
||
190 | if( cipher_info == NULL ) |
||
191 | return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); |
||
192 | |||
193 | keylen = cipher_info->key_bitlen / 8; |
||
194 | |||
195 | if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen, |
||
196 | key, keylen, |
||
197 | iv, cipher_info->iv_size ) ) != 0 ) |
||
198 | { |
||
199 | return( ret ); |
||
200 | } |
||
201 | |||
202 | mbedtls_cipher_init( &cipher_ctx ); |
||
203 | |||
204 | if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) |
||
205 | goto exit; |
||
206 | |||
207 | if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) |
||
208 | goto exit; |
||
209 | |||
210 | if( ( ret = mbedtls_cipher_set_iv( &cipher_ctx, iv, cipher_info->iv_size ) ) != 0 ) |
||
211 | goto exit; |
||
212 | |||
213 | if( ( ret = mbedtls_cipher_reset( &cipher_ctx ) ) != 0 ) |
||
214 | goto exit; |
||
215 | |||
216 | if( ( ret = mbedtls_cipher_update( &cipher_ctx, data, len, |
||
217 | output, &olen ) ) != 0 ) |
||
218 | { |
||
219 | goto exit; |
||
220 | } |
||
221 | |||
222 | if( ( ret = mbedtls_cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) |
||
223 | ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH; |
||
224 | |||
225 | exit: |
||
226 | mbedtls_platform_zeroize( key, sizeof( key ) ); |
||
227 | mbedtls_platform_zeroize( iv, sizeof( iv ) ); |
||
228 | mbedtls_cipher_free( &cipher_ctx ); |
||
229 | |||
230 | return( ret ); |
||
231 | } |
||
232 | |||
233 | #endif /* MBEDTLS_ASN1_PARSE_C */ |
||
234 | |||
235 | static void pkcs12_fill_buffer( unsigned char *data, size_t data_len, |
||
236 | const unsigned char *filler, size_t fill_len ) |
||
237 | { |
||
238 | unsigned char *p = data; |
||
239 | size_t use_len; |
||
240 | |||
241 | while( data_len > 0 ) |
||
242 | { |
||
243 | use_len = ( data_len > fill_len ) ? fill_len : data_len; |
||
244 | memcpy( p, filler, use_len ); |
||
245 | p += use_len; |
||
246 | data_len -= use_len; |
||
247 | } |
||
248 | } |
||
249 | |||
250 | int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, |
||
251 | const unsigned char *pwd, size_t pwdlen, |
||
252 | const unsigned char *salt, size_t saltlen, |
||
253 | mbedtls_md_type_t md_type, int id, int iterations ) |
||
254 | { |
||
255 | int ret; |
||
256 | unsigned int j; |
||
257 | |||
258 | unsigned char diversifier[128]; |
||
259 | unsigned char salt_block[128], pwd_block[128], hash_block[128]; |
||
260 | unsigned char hash_output[MBEDTLS_MD_MAX_SIZE]; |
||
261 | unsigned char *p; |
||
262 | unsigned char c; |
||
263 | |||
264 | size_t hlen, use_len, v, i; |
||
265 | |||
266 | const mbedtls_md_info_t *md_info; |
||
267 | mbedtls_md_context_t md_ctx; |
||
268 | |||
269 | // This version only allows max of 64 bytes of password or salt |
||
270 | if( datalen > 128 || pwdlen > 64 || saltlen > 64 ) |
||
271 | return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); |
||
272 | |||
273 | md_info = mbedtls_md_info_from_type( md_type ); |
||
274 | if( md_info == NULL ) |
||
275 | return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); |
||
276 | |||
277 | mbedtls_md_init( &md_ctx ); |
||
278 | |||
279 | if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) |
||
280 | return( ret ); |
||
281 | hlen = mbedtls_md_get_size( md_info ); |
||
282 | |||
283 | if( hlen <= 32 ) |
||
284 | v = 64; |
||
285 | else |
||
286 | v = 128; |
||
287 | |||
288 | memset( diversifier, (unsigned char) id, v ); |
||
289 | |||
290 | pkcs12_fill_buffer( salt_block, v, salt, saltlen ); |
||
291 | pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen ); |
||
292 | |||
293 | p = data; |
||
294 | while( datalen > 0 ) |
||
295 | { |
||
296 | // Calculate hash( diversifier || salt_block || pwd_block ) |
||
297 | if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 ) |
||
298 | goto exit; |
||
299 | |||
300 | if( ( ret = mbedtls_md_update( &md_ctx, diversifier, v ) ) != 0 ) |
||
301 | goto exit; |
||
302 | |||
303 | if( ( ret = mbedtls_md_update( &md_ctx, salt_block, v ) ) != 0 ) |
||
304 | goto exit; |
||
305 | |||
306 | if( ( ret = mbedtls_md_update( &md_ctx, pwd_block, v ) ) != 0 ) |
||
307 | goto exit; |
||
308 | |||
309 | if( ( ret = mbedtls_md_finish( &md_ctx, hash_output ) ) != 0 ) |
||
310 | goto exit; |
||
311 | |||
312 | // Perform remaining ( iterations - 1 ) recursive hash calculations |
||
313 | for( i = 1; i < (size_t) iterations; i++ ) |
||
314 | { |
||
315 | if( ( ret = mbedtls_md( md_info, hash_output, hlen, hash_output ) ) != 0 ) |
||
316 | goto exit; |
||
317 | } |
||
318 | |||
319 | use_len = ( datalen > hlen ) ? hlen : datalen; |
||
320 | memcpy( p, hash_output, use_len ); |
||
321 | datalen -= use_len; |
||
322 | p += use_len; |
||
323 | |||
324 | if( datalen == 0 ) |
||
325 | break; |
||
326 | |||
327 | // Concatenating copies of hash_output into hash_block (B) |
||
328 | pkcs12_fill_buffer( hash_block, v, hash_output, hlen ); |
||
329 | |||
330 | // B += 1 |
||
331 | for( i = v; i > 0; i-- ) |
||
332 | if( ++hash_block[i - 1] != 0 ) |
||
333 | break; |
||
334 | |||
335 | // salt_block += B |
||
336 | c = 0; |
||
337 | for( i = v; i > 0; i-- ) |
||
338 | { |
||
339 | j = salt_block[i - 1] + hash_block[i - 1] + c; |
||
340 | c = (unsigned char) (j >> 8); |
||
341 | salt_block[i - 1] = j & 0xFF; |
||
342 | } |
||
343 | |||
344 | // pwd_block += B |
||
345 | c = 0; |
||
346 | for( i = v; i > 0; i-- ) |
||
347 | { |
||
348 | j = pwd_block[i - 1] + hash_block[i - 1] + c; |
||
349 | c = (unsigned char) (j >> 8); |
||
350 | pwd_block[i - 1] = j & 0xFF; |
||
351 | } |
||
352 | } |
||
353 | |||
354 | ret = 0; |
||
355 | |||
356 | exit: |
||
357 | mbedtls_platform_zeroize( salt_block, sizeof( salt_block ) ); |
||
358 | mbedtls_platform_zeroize( pwd_block, sizeof( pwd_block ) ); |
||
359 | mbedtls_platform_zeroize( hash_block, sizeof( hash_block ) ); |
||
360 | mbedtls_platform_zeroize( hash_output, sizeof( hash_output ) ); |
||
361 | |||
362 | mbedtls_md_free( &md_ctx ); |
||
363 | |||
364 | return( ret ); |
||
365 | } |
||
366 | |||
367 | #endif /* MBEDTLS_PKCS12_C */>=>> |