blob: 2ee9c5ea2c62acf3b0b455783b1fd3c538f91575 [file] [log] [blame]
Paul Bakkercf6e95d2013-06-12 13:18:15 +02001/*
2 * PKCS#12 Personal Information Exchange Syntax
3 *
4 * Copyright (C) 2006-2013, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25/*
26 * The PKCS #12 Personal Information Exchange Syntax Standard v1.1
27 *
28 * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf
29 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn
30 */
31
32#include "polarssl/config.h"
33
34#if defined(POLARSSL_PKCS12_C)
35
36#include "polarssl/pkcs12.h"
37#include "polarssl/asn1.h"
Paul Bakker14a222c2013-06-18 16:35:48 +020038#include "polarssl/cipher.h"
Paul Bakkercf6e95d2013-06-12 13:18:15 +020039
40#if defined(POLARSSL_ARC4_C)
41#include "polarssl/arc4.h"
42#endif
43
44#if defined(POLARSSL_DES_C)
45#include "polarssl/des.h"
46#endif
47
48static int pkcs12_parse_pbe_params( unsigned char **p,
49 const unsigned char *end,
50 asn1_buf *salt, int *iterations )
51{
52 int ret;
53 size_t len = 0;
54
55 /*
56 * pkcs-12PbeParams ::= SEQUENCE {
57 * salt OCTET STRING,
58 * iterations INTEGER
59 * }
60 *
61 */
62 if( ( ret = asn1_get_tag( p, end, &len,
63 ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
64 {
65 return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
66 }
67
68 end = *p + len;
69
70 if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 )
71 return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
72
73 salt->p = *p;
74 *p += salt->len;
75
76 if( ( ret = asn1_get_int( p, end, iterations ) ) != 0 )
77 return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
78
79 if( *p != end )
80 return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT +
81 POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
82
83 return( 0 );
84}
85
Paul Bakker14a222c2013-06-18 16:35:48 +020086static int pkcs12_pbe_derive_key_iv( asn1_buf *pbe_params, md_type_t md_type,
Paul Bakkercf6e95d2013-06-12 13:18:15 +020087 const unsigned char *pwd, size_t pwdlen,
88 unsigned char *key, size_t keylen,
89 unsigned char *iv, size_t ivlen )
90{
91 int ret, iterations;
92 asn1_buf salt;
93 size_t i;
94 unsigned char *p, *end;
95 unsigned char unipwd[258];
96
97 memset(&salt, 0, sizeof(asn1_buf));
98 memset(&unipwd, 0, sizeof(unipwd));
99
100 p = pbe_params->p;
101 end = p + pbe_params->len;
102
103 if( ( ret = pkcs12_parse_pbe_params( &p, end, &salt, &iterations ) ) != 0 )
104 return( ret );
105
106 for(i = 0; i < pwdlen; i++)
107 unipwd[i * 2 + 1] = pwd[i];
108
109 if( ( ret = pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2,
Paul Bakker14a222c2013-06-18 16:35:48 +0200110 salt.p, salt.len, md_type,
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200111 PKCS12_DERIVE_KEY, iterations ) ) != 0 )
112 {
113 return( ret );
114 }
115
116 if( iv == NULL || ivlen == 0 )
117 return( 0 );
118
119 if( ( ret = pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2,
Paul Bakker14a222c2013-06-18 16:35:48 +0200120 salt.p, salt.len, md_type,
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200121 PKCS12_DERIVE_IV, iterations ) ) != 0 )
122 {
123 return( ret );
124 }
125 return( 0 );
126}
127
128int pkcs12_pbe_sha1_rc4_128( asn1_buf *pbe_params, int mode,
129 const unsigned char *pwd, size_t pwdlen,
130 const unsigned char *data, size_t len,
131 unsigned char *output )
132{
133#if !defined(POLARSSL_ARC4_C)
134 ((void) pbe_params);
135 ((void) mode);
136 ((void) pwd);
137 ((void) pwdlen);
138 ((void) data);
139 ((void) len);
140 ((void) output);
141 return( POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE );
142#else
143 int ret;
144 unsigned char key[16];
145 arc4_context ctx;
146 ((void) mode);
147
Paul Bakker14a222c2013-06-18 16:35:48 +0200148 if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, POLARSSL_MD_SHA1,
149 pwd, pwdlen,
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200150 key, 16, NULL, 0 ) ) != 0 )
151 {
152 return( ret );
153 }
154
155 arc4_setup( &ctx, key, 16 );
156 if( ( ret = arc4_crypt( &ctx, len, data, output ) ) != 0 )
157 return( ret );
158
159 return( 0 );
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200160#endif /* POLARSSL_ARC4_C */
Paul Bakker67812d32013-06-14 11:35:09 +0200161}
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200162
Paul Bakker14a222c2013-06-18 16:35:48 +0200163int pkcs12_pbe( asn1_buf *pbe_params, int mode,
164 cipher_type_t cipher_type, md_type_t md_type,
165 const unsigned char *pwd, size_t pwdlen,
166 const unsigned char *data, size_t len,
167 unsigned char *output )
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200168{
Paul Bakker14a222c2013-06-18 16:35:48 +0200169 int ret, keylen = 0;
170 unsigned char key[32];
171 unsigned char iv[16];
172 const cipher_info_t *cipher_info;
173 cipher_context_t cipher_ctx;
174 size_t olen = 0;
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200175
Paul Bakker14a222c2013-06-18 16:35:48 +0200176 cipher_info = cipher_info_from_type( cipher_type );
177 if( cipher_info == NULL )
178 return( POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE );
179
180 keylen = cipher_info->key_length / 8;
181
182 if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen,
183 key, keylen,
184 iv, cipher_info->iv_size ) ) != 0 )
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200185 {
186 return( ret );
187 }
188
Paul Bakker14a222c2013-06-18 16:35:48 +0200189 if( ( ret = cipher_init_ctx( &cipher_ctx, cipher_info ) ) != 0 )
190 return( ret );
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200191
Paul Bakker14a222c2013-06-18 16:35:48 +0200192 if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 )
193 return( ret );
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200194
Paul Bakker14a222c2013-06-18 16:35:48 +0200195 if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 )
196 return( ret );
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200197
Paul Bakker14a222c2013-06-18 16:35:48 +0200198 if( ( ret = cipher_update( &cipher_ctx, data, len,
199 output, &olen ) ) != 0 )
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200200 {
201 return( ret );
202 }
203
Paul Bakker14a222c2013-06-18 16:35:48 +0200204 if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 )
205 return( POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH );
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200206
207 return( 0 );
Paul Bakker67812d32013-06-14 11:35:09 +0200208}
Paul Bakkercf6e95d2013-06-12 13:18:15 +0200209
210static void pkcs12_fill_buffer( unsigned char *data, size_t data_len,
211 const unsigned char *filler, size_t fill_len )
212{
213 unsigned char *p = data;
214 size_t use_len;
215
216 while( data_len > 0 )
217 {
218 use_len = ( data_len > fill_len ) ? fill_len : data_len;
219 memcpy( p, filler, use_len );
220 p += use_len;
221 data_len -= use_len;
222 }
223}
224
225int pkcs12_derivation( unsigned char *data, size_t datalen,
226 const unsigned char *pwd, size_t pwdlen,
227 const unsigned char *salt, size_t saltlen,
228 md_type_t md_type, int id, int iterations )
229{
230 int ret, i;
231 unsigned int j;
232
233 unsigned char diversifier[128];
234 unsigned char salt_block[128], pwd_block[128], hash_block[128];
235 unsigned char hash_output[POLARSSL_MD_MAX_SIZE];
236 unsigned char *p;
237 unsigned char c;
238
239 size_t hlen, use_len, v;
240
241 const md_info_t *md_info;
242 md_context_t md_ctx;
243
244 // This version only allows max of 64 bytes of password or salt
245 if( datalen > 128 || pwdlen > 64 || saltlen > 64 )
246 return( POLARSSL_ERR_PKCS12_BAD_INPUT_DATA );
247
248 md_info = md_info_from_type( md_type );
249 if( md_info == NULL )
250 return( POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE );
251
252 if ( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
253 return( ret );
254 hlen = md_get_size( md_info );
255
256 if( hlen <= 32 )
257 v = 64;
258 else
259 v = 128;
260
261 memset( diversifier, (unsigned char) id, v );
262
263 pkcs12_fill_buffer( salt_block, v, salt, saltlen );
264 pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen );
265
266 p = data;
267 while( datalen > 0 )
268 {
269 // Calculate hash( diversifier || salt_block || pwd_block )
270 if( ( ret = md_starts( &md_ctx ) ) != 0 )
271 return( ret );
272
273 if( ( ret = md_update( &md_ctx, diversifier, v ) ) != 0 )
274 return( ret );
275
276 if( ( ret = md_update( &md_ctx, salt_block, v ) ) != 0 )
277 return( ret );
278
279 if( ( ret = md_update( &md_ctx, pwd_block, v ) ) != 0 )
280 return( ret );
281
282 if( ( ret = md_finish( &md_ctx, hash_output ) ) != 0 )
283 return( ret );
284
285 // Perform remaining ( iterations - 1 ) recursive hash calculations
286 for( i = 1; i < iterations; i++ )
287 {
288 if( ( ret = md( md_info, hash_output, hlen, hash_output ) ) != 0 )
289 return( ret );
290 }
291
292 use_len = ( datalen > hlen ) ? hlen : datalen;
293 memcpy( p, hash_output, use_len );
294 datalen -= use_len;
295 p += use_len;
296
297 if( datalen == 0 )
298 break;
299
300 // Concatenating copies of hash_output into hash_block (B)
301 pkcs12_fill_buffer( hash_block, v, hash_output, hlen );
302
303 // B += 1
304 for( i = v; i > 0; i-- )
305 if( ++hash_block[i - 1] != 0 )
306 break;
307
308 // salt_block += B
309 c = 0;
310 for( i = v; i > 0; i-- )
311 {
312 j = salt_block[i - 1] + hash_block[i - 1] + c;
313 c = (unsigned char) (j >> 8);
314 salt_block[i - 1] = j & 0xFF;
315 }
316
317 // pwd_block += B
318 c = 0;
319 for( i = v; i > 0; i-- )
320 {
321 j = pwd_block[i - 1] + hash_block[i - 1] + c;
322 c = (unsigned char) (j >> 8);
323 pwd_block[i - 1] = j & 0xFF;
324 }
325 }
326
327 return( 0 );
328}
329
330#endif /* POLARSSL_PKCS12_C */