corrected typos
[gnutls.git] / lib / x509 / privkey_openssl.c
blob8d3094cd0874f4824b6abf34f2e587c32b88b836
1 /*
2 * Copyright (C) 2012 Free Software Foundation, Inc.
4 * Author: David Woodhouse
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <gnutls_int.h>
25 #include <gnutls_datum.h>
26 #include <gnutls_global.h>
27 #include <gnutls_errors.h>
28 #include <gnutls_rsa_export.h>
29 #include <common.h>
30 #include <gnutls_x509.h>
31 #include <x509_b64.h>
32 #include "x509_int.h"
33 #include <algorithms.h>
34 #include <gnutls_num.h>
35 #include <random.h>
36 #include <pbkdf2-sha1.h>
38 static int
39 openssl_hash_password (const char *pass, gnutls_datum_t * key, gnutls_datum_t * salt)
41 unsigned char md5[16];
42 gnutls_hash_hd_t hash;
43 unsigned int count = 0;
44 int err;
46 while (count < key->size)
48 err = gnutls_hash_init (&hash, GNUTLS_DIG_MD5);
49 if (err)
51 gnutls_assert ();
52 return err;
54 if (count)
56 err = gnutls_hash (hash, md5, sizeof (md5));
57 if (err)
59 hash_err:
60 gnutls_hash_deinit (hash, NULL);
61 gnutls_assert();
62 return err;
65 if (pass)
67 err = gnutls_hash (hash, pass, strlen (pass));
68 if (err)
70 gnutls_assert();
71 goto hash_err;
74 err = gnutls_hash (hash, salt->data, 8);
75 if (err)
77 gnutls_assert();
78 goto hash_err;
81 gnutls_hash_deinit (hash, md5);
83 if (key->size - count <= sizeof (md5))
85 memcpy (&key->data[count], md5, key->size - count);
86 break;
89 memcpy (&key->data[count], md5, sizeof (md5));
90 count += sizeof (md5);
93 return 0;
96 static const struct pem_cipher {
97 const char *name;
98 gnutls_cipher_algorithm_t cipher;
99 } pem_ciphers[] = {
100 { "DES-CBC", GNUTLS_CIPHER_DES_CBC },
101 { "DES-EDE3-CBC", GNUTLS_CIPHER_3DES_CBC },
102 { "AES-128-CBC", GNUTLS_CIPHER_AES_128_CBC },
103 { "AES-192-CBC", GNUTLS_CIPHER_AES_192_CBC },
104 { "AES-256-CBC", GNUTLS_CIPHER_AES_256_CBC },
105 { "CAMELLIA-128-CBC", GNUTLS_CIPHER_CAMELLIA_128_CBC },
106 { "CAMELLIA-192-CBC", GNUTLS_CIPHER_CAMELLIA_192_CBC },
107 { "CAMELLIA-256-CBC", GNUTLS_CIPHER_CAMELLIA_256_CBC },
111 * gnutls_x509_privkey_import_openssl:
112 * @key: The structure to store the parsed key
113 * @data: The DER or PEM encoded key.
114 * @password: the password to decrypt the key (if it is encrypted).
116 * This function will convert the given PEM encrypted to
117 * the native gnutls_x509_privkey_t format. The
118 * output will be stored in @key.
120 * The @password should be in ASCII. If the password is not provided
121 * or wrong then %GNUTLS_E_DECRYPTION_FAILED will be returned.
123 * If the Certificate is PEM encoded it should have a header of
124 * "PRIVATE KEY" and the "DEK-Info" header.
126 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
127 * negative error value.
130 gnutls_x509_privkey_import_openssl (gnutls_x509_privkey_t key,
131 const gnutls_datum_t *data, const char* password)
133 gnutls_cipher_hd_t handle;
134 gnutls_cipher_algorithm_t cipher = GNUTLS_CIPHER_UNKNOWN;
135 gnutls_datum_t b64_data;
136 gnutls_datum_t salt, enc_key;
137 unsigned char *key_data;
138 const char *pem_header = (void*)data->data;
139 const char *pem_header_start = (void*)data->data;
140 ssize_t pem_header_size;
141 int ret;
142 unsigned int i, iv_size, l;
144 pem_header_size = data->size;
146 pem_header = memmem(pem_header, pem_header_size, "PRIVATE KEY---", 14);
147 if (pem_header == NULL)
149 gnutls_assert();
150 return GNUTLS_E_PARSING_ERROR;
153 pem_header_size -= (ptrdiff_t)(pem_header-pem_header_start);
155 pem_header = memmem(pem_header, pem_header_size, "DEK-Info: ", 10);
156 if (pem_header == NULL)
158 gnutls_assert();
159 return GNUTLS_E_PARSING_ERROR;
162 pem_header_size = data->size - (ptrdiff_t)(pem_header-pem_header_start) - 10;
163 pem_header += 10;
165 for (i = 0; i < sizeof(pem_ciphers)/sizeof(pem_ciphers[0]); i++)
167 l = strlen(pem_ciphers[i].name);
168 if (!strncmp(pem_header, pem_ciphers[i].name, l) &&
169 pem_header[l] == ',')
171 pem_header += l + 1;
172 cipher = pem_ciphers[i].cipher;
173 break;
177 if (cipher == GNUTLS_CIPHER_UNKNOWN)
179 _gnutls_debug_log ("Unsupported PEM encryption type: %.10s\n", pem_header);
180 gnutls_assert();
181 return GNUTLS_E_INVALID_REQUEST;
184 iv_size = _gnutls_cipher_get_iv_size(cipher);
185 salt.size = iv_size;
186 salt.data = gnutls_malloc (salt.size);
187 if (!salt.data)
188 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
190 for (i = 0; i < salt.size * 2; i++)
192 unsigned char x;
193 const char *c = &pem_header[i];
195 if (*c >= '0' && *c <= '9')
196 x = (*c) - '0';
197 else if (*c >= 'A' && *c <= 'F')
198 x = (*c) - 'A' + 10;
199 else
201 gnutls_assert();
202 /* Invalid salt in encrypted PEM file */
203 ret = GNUTLS_E_INVALID_REQUEST;
204 goto out_salt;
206 if (i & 1)
207 salt.data[i / 2] |= x;
208 else
209 salt.data[i / 2] = x << 4;
212 pem_header += salt.size * 2;
213 if (*pem_header != '\r' && *pem_header != '\n')
215 gnutls_assert();
216 ret = GNUTLS_E_INVALID_REQUEST;
217 goto out_salt;
219 while (*pem_header == '\n' || *pem_header == '\r')
220 pem_header++;
222 ret = _gnutls_base64_decode((const void*)pem_header, pem_header_size, &b64_data);
223 if (ret < 0)
225 gnutls_assert();
226 goto out_salt;
229 if (b64_data.size < 16)
231 /* Just to be sure our parsing is OK */
232 gnutls_assert();
233 ret = GNUTLS_E_PARSING_ERROR;
234 goto out_b64;
237 ret = GNUTLS_E_MEMORY_ERROR;
238 enc_key.size = gnutls_cipher_get_key_size (cipher);
239 enc_key.data = gnutls_malloc (enc_key.size);
240 if (!enc_key.data)
242 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
243 goto out_b64;
246 key_data = gnutls_malloc (b64_data.size);
247 if (!key_data)
249 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
250 goto out_enc_key;
253 while (1)
255 memcpy (key_data, b64_data.data, b64_data.size);
257 ret = openssl_hash_password (password, &enc_key, &salt);
258 if (ret < 0)
260 gnutls_assert();
261 goto out;
264 ret = gnutls_cipher_init (&handle, cipher, &enc_key, &salt);
265 if (ret < 0)
267 gnutls_assert();
268 gnutls_cipher_deinit (handle);
269 goto out;
272 ret = gnutls_cipher_decrypt (handle, key_data, b64_data.size);
273 gnutls_cipher_deinit (handle);
275 if (ret < 0)
277 gnutls_assert();
278 goto out;
281 /* We have to strip any padding to accept it.
282 So a bit more ASN.1 parsing for us.*/
283 if (key_data[0] == 0x30)
285 gnutls_datum_t key_datum;
286 unsigned int blocksize = gnutls_cipher_get_block_size (cipher);
287 unsigned int keylen = key_data[1];
288 unsigned int ofs = 2;
290 if (keylen & 0x80)
292 int lenlen = keylen & 0x7f;
293 keylen = 0;
295 if (lenlen > 3)
297 gnutls_assert();
298 goto fail;
301 while (lenlen)
303 keylen <<= 8;
304 keylen |= key_data[ofs++];
305 lenlen--;
308 keylen += ofs;
310 /* If there appears to be more padding than required, fail */
311 if (b64_data.size - keylen > blocksize)
313 gnutls_assert();
314 goto fail;
317 /* If the padding bytes aren't all equal to the amount of padding, fail */
318 ofs = keylen;
319 while (ofs < b64_data.size)
321 if (key_data[ofs] != b64_data.size - keylen)
323 gnutls_assert();
324 goto fail;
326 ofs++;
329 key_datum.data = key_data;
330 key_datum.size = keylen;
331 ret =
332 gnutls_x509_privkey_import (key, &key_datum,
333 GNUTLS_X509_FMT_DER);
334 if (ret == 0)
335 goto out;
337 fail:
338 ret = GNUTLS_E_DECRYPTION_FAILED;
339 goto out;
341 out:
342 gnutls_free (key_data);
343 out_enc_key:
344 gnutls_free (enc_key.data);
345 out_b64:
346 gnutls_free (b64_data.data);
347 out_salt:
348 gnutls_free (salt.data);
349 return ret;