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