1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
4 * Dan Williams <dcbw@redhat.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA.
21 * Copyright 2007 - 2011 Red Hat, Inc.
24 #include "nm-default.h"
34 _nm_crypto_error_quark (void)
38 if (G_UNLIKELY (!quark))
39 quark = g_quark_from_static_string ("nm-crypto-error-quark");
44 #define PEM_RSA_KEY_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
45 #define PEM_RSA_KEY_END "-----END RSA PRIVATE KEY-----"
47 #define PEM_DSA_KEY_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
48 #define PEM_DSA_KEY_END "-----END DSA PRIVATE KEY-----"
50 #define PEM_CERT_BEGIN "-----BEGIN CERTIFICATE-----"
51 #define PEM_CERT_END "-----END CERTIFICATE-----"
53 #define PEM_PKCS8_ENC_KEY_BEGIN "-----BEGIN ENCRYPTED PRIVATE KEY-----"
54 #define PEM_PKCS8_ENC_KEY_END "-----END ENCRYPTED PRIVATE KEY-----"
56 #define PEM_PKCS8_DEC_KEY_BEGIN "-----BEGIN PRIVATE KEY-----"
57 #define PEM_PKCS8_DEC_KEY_END "-----END PRIVATE KEY-----"
60 find_tag (const char *tag,
61 const GByteArray *array,
66 gsize len = array->len - start_at;
68 g_return_val_if_fail (out_pos != NULL, FALSE);
70 taglen = strlen (tag);
72 for (i = 0; i < len - taglen + 1; i++) {
73 if (memcmp (array->data + start_at + i, tag, taglen) == 0) {
74 *out_pos = start_at + i;
82 #define DEK_INFO_TAG "DEK-Info: "
83 #define PROC_TYPE_TAG "Proc-Type: "
86 parse_old_openssl_key_file (const GByteArray *contents,
92 GByteArray *bindata = NULL;
95 gsize start = 0, end = 0;
100 unsigned char *tmp = NULL;
102 const char *start_tag;
107 case NM_CRYPTO_KEY_TYPE_RSA:
108 start_tag = PEM_RSA_KEY_BEGIN;
109 end_tag = PEM_RSA_KEY_END;
111 case NM_CRYPTO_KEY_TYPE_DSA:
112 start_tag = PEM_DSA_KEY_BEGIN;
113 end_tag = PEM_DSA_KEY_END;
116 g_set_error (error, NM_CRYPTO_ERROR,
117 NM_CRYPTO_ERR_UNKNOWN_KEY_TYPE,
118 "Unknown key type %d",
120 g_assert_not_reached ();
124 if (!find_tag (start_tag, contents, 0, &start))
127 start += strlen (start_tag);
128 if (!find_tag (end_tag, contents, start, &end)) {
129 g_set_error (error, NM_CRYPTO_ERROR,
130 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
131 _("PEM key file had no end tag '%s'."),
136 save_end = contents->data[end];
137 contents->data[end] = '\0';
138 lines = g_strsplit ((const char *) (contents->data + start), "\n", 0);
139 contents->data[end] = save_end;
141 if (!lines || g_strv_length (lines) <= 1) {
142 g_set_error (error, NM_CRYPTO_ERROR,
143 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
144 _("Doesn't look like a PEM private key file."));
148 str = g_string_new_len (NULL, end - start);
149 for (ln = lines; *ln; ln++) {
152 /* Chug leading spaces */
157 if (!strncmp (p, PROC_TYPE_TAG, strlen (PROC_TYPE_TAG))) {
158 if (enc_tags++ != 0) {
159 g_set_error (error, NM_CRYPTO_ERROR,
160 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
161 _("Malformed PEM file: Proc-Type was not first tag."));
165 p += strlen (PROC_TYPE_TAG);
166 if (strcmp (p, "4,ENCRYPTED")) {
167 g_set_error (error, NM_CRYPTO_ERROR,
168 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
169 _("Malformed PEM file: unknown Proc-Type tag '%s'."),
173 } else if (!strncmp (p, DEK_INFO_TAG, strlen (DEK_INFO_TAG))) {
176 if (enc_tags++ != 1) {
177 g_set_error (error, NM_CRYPTO_ERROR,
178 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
179 _("Malformed PEM file: DEK-Info was not the second tag."));
183 p += strlen (DEK_INFO_TAG);
185 /* Grab the IV first */
186 comma = strchr (p, ',');
187 if (!comma || (*(comma + 1) == '\0')) {
188 g_set_error (error, NM_CRYPTO_ERROR,
189 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
190 _("Malformed PEM file: no IV found in DEK-Info tag."));
194 if (!g_ascii_isxdigit (*comma)) {
195 g_set_error (error, NM_CRYPTO_ERROR,
196 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
197 _("Malformed PEM file: invalid format of IV in DEK-Info tag."));
200 iv = g_strdup (comma);
202 /* Get the private key cipher */
203 if (!strcasecmp (p, "DES-EDE3-CBC")) {
204 cipher = g_strdup (p);
205 } else if (!strcasecmp (p, "DES-CBC")) {
206 cipher = g_strdup (p);
207 } else if (!strcasecmp (p, "AES-128-CBC")) {
208 cipher = g_strdup (p);
210 g_set_error (error, NM_CRYPTO_ERROR,
211 NM_CRYPTO_ERR_UNKNOWN_KEY_TYPE,
212 _("Malformed PEM file: unknown private key cipher '%s'."),
217 if ((enc_tags != 0) && (enc_tags != 2)) {
218 g_set_error (error, NM_CRYPTO_ERROR,
219 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
220 "Malformed PEM file: both Proc-Type and DEK-Info tags are required.");
223 g_string_append (str, p);
227 tmp = g_base64_decode (str->str, &tmp_len);
228 if (tmp == NULL || !tmp_len) {
229 g_set_error (error, NM_CRYPTO_ERROR,
230 NM_CRYPTO_ERR_DECODE_FAILED,
231 _("Could not decode private key."));
234 g_string_free (str, TRUE);
239 bindata = g_byte_array_sized_new (tmp_len);
240 g_byte_array_append (bindata, tmp, tmp_len);
244 *out_cipher = cipher;
252 g_string_free (str, TRUE);
259 parse_pkcs8_key_file (const GByteArray *contents,
260 gboolean *out_encrypted,
263 GByteArray *key = NULL;
264 gsize start = 0, end = 0;
265 unsigned char *der = NULL;
268 const char *start_tag = NULL, *end_tag = NULL;
269 gboolean encrypted = FALSE;
271 /* Try encrypted first, decrypted next */
272 if (find_tag (PEM_PKCS8_ENC_KEY_BEGIN, contents, 0, &start)) {
273 start_tag = PEM_PKCS8_ENC_KEY_BEGIN;
274 end_tag = PEM_PKCS8_ENC_KEY_END;
276 } else if (find_tag (PEM_PKCS8_DEC_KEY_BEGIN, contents, 0, &start)) {
277 start_tag = PEM_PKCS8_DEC_KEY_BEGIN;
278 end_tag = PEM_PKCS8_DEC_KEY_END;
281 g_set_error_literal (error, NM_CRYPTO_ERROR,
282 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
283 _("Failed to find expected PKCS#8 start tag."));
287 start += strlen (start_tag);
288 if (!find_tag (end_tag, contents, start, &end)) {
289 g_set_error (error, NM_CRYPTO_ERROR,
290 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
291 _("Failed to find expected PKCS#8 end tag '%s'."),
296 /* g_base64_decode() wants a NULL-terminated string */
297 save_end = contents->data[end];
298 contents->data[end] = '\0';
299 der = g_base64_decode ((const char *) (contents->data + start), &length);
300 contents->data[end] = save_end;
303 key = g_byte_array_sized_new (length);
304 g_byte_array_append (key, der, length);
305 g_assert (key->len == length);
306 *out_encrypted = encrypted;
308 g_set_error_literal (error, NM_CRYPTO_ERROR,
309 NM_CRYPTO_ERR_DECODE_FAILED,
310 _("Failed to decode PKCS#8 private key."));
318 file_to_g_byte_array (const char *filename, GError **error)
321 GByteArray *array = NULL;
324 if (g_file_get_contents (filename, &contents, &length, error)) {
325 array = g_byte_array_sized_new (length);
326 g_byte_array_append (array, (guint8 *) contents, length);
327 g_assert (array->len == length);
334 * Convert a hex string into bytes.
337 convert_iv (const char *src,
346 g_return_val_if_fail (src != NULL, NULL);
350 g_set_error (error, NM_CRYPTO_ERROR,
351 NM_CRYPTO_ERR_RAW_IV_INVALID,
352 _("IV must be an even number of bytes in length."));
357 c = g_malloc0 (num + 1);
360 for (i = 0; i < num; i++) {
361 conv[0] = src[(i * 2)];
362 conv[1] = src[(i * 2) + 1];
363 if (!g_ascii_isxdigit (conv[0]) || !g_ascii_isxdigit (conv[1])) {
364 g_set_error (error, NM_CRYPTO_ERROR,
365 NM_CRYPTO_ERR_RAW_IV_INVALID,
366 _("IV contains non-hexadecimal digits."));
370 c[i] = strtol(conv, NULL, 16);
381 make_des_aes_key (const char *cipher,
383 const gsize salt_len,
384 const char *password,
391 g_return_val_if_fail (cipher != NULL, NULL);
392 g_return_val_if_fail (salt != NULL, NULL);
393 g_return_val_if_fail (salt_len >= 8, NULL);
394 g_return_val_if_fail (password != NULL, NULL);
395 g_return_val_if_fail (out_len != NULL, NULL);
397 if (!strcmp (cipher, "DES-EDE3-CBC"))
399 else if (!strcmp (cipher, "DES-CBC"))
401 else if (!strcmp (cipher, "AES-128-CBC"))
404 g_set_error (error, NM_CRYPTO_ERROR,
405 NM_CRYPTO_ERR_UNKNOWN_CIPHER,
406 _("Private key cipher '%s' was unknown."),
411 if (password[0] == '\0')
414 key = g_malloc0 (digest_len + 1);
416 if (!crypto_md5_hash (salt,
425 *out_len = digest_len;
430 /* Don't leak stale key material */
431 memset (key, 0, digest_len);
438 decrypt_key (const char *cipher,
442 const char *password,
446 gsize bin_iv_len = 0;
450 gsize decrypted_len = 0;
451 GByteArray *decrypted = NULL;
453 g_return_val_if_fail (password != NULL, NULL);
455 bin_iv = convert_iv (iv, &bin_iv_len, error);
459 /* Convert the password and IV into a DES or AES key */
460 key = make_des_aes_key (cipher, bin_iv, bin_iv_len, password, &key_len, error);
461 if (!key || !key_len)
464 output = crypto_decrypt (cipher, key_type,
470 if (output && decrypted_len) {
471 decrypted = g_byte_array_sized_new (decrypted_len);
472 g_byte_array_append (decrypted, (guint8 *) output, decrypted_len);
476 /* Don't leak stale key material */
478 memset (key, 0, key_len);
487 crypto_decrypt_private_key_data (const GByteArray *contents,
488 const char *password,
489 NMCryptoKeyType *out_key_type,
492 GByteArray *decrypted = NULL;
493 NMCryptoKeyType key_type = NM_CRYPTO_KEY_TYPE_RSA;
498 g_return_val_if_fail (contents != NULL, NULL);
500 g_return_val_if_fail (*out_key_type == NM_CRYPTO_KEY_TYPE_UNKNOWN, NULL);
502 /* OpenSSL non-standard legacy PEM files */
504 /* Try RSA keys first */
505 data = parse_old_openssl_key_file (contents, key_type, &cipher, &iv, error);
507 g_clear_error (error);
510 key_type = NM_CRYPTO_KEY_TYPE_DSA;
511 data = parse_old_openssl_key_file (contents, key_type, &cipher, &iv, error);
513 g_clear_error (error);
514 g_set_error (error, NM_CRYPTO_ERROR,
515 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
516 _("Unable to determine private key type."));
521 /* return the key type even if decryption failed */
523 *out_key_type = key_type;
526 decrypted = decrypt_key (cipher,
533 g_byte_array_free (data, TRUE);
543 crypto_decrypt_private_key (const char *file,
544 const char *password,
545 NMCryptoKeyType *out_key_type,
548 GByteArray *contents;
549 GByteArray *key = NULL;
551 contents = file_to_g_byte_array (file, error);
553 key = crypto_decrypt_private_key_data (contents, password, out_key_type, error);
554 g_byte_array_free (contents, TRUE);
560 extract_pem_cert_data (GByteArray *contents, GError **error)
562 GByteArray *cert = NULL;
563 gsize start = 0, end = 0;
564 unsigned char *der = NULL;
568 if (!find_tag (PEM_CERT_BEGIN, contents, 0, &start)) {
569 g_set_error (error, NM_CRYPTO_ERROR,
570 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
571 _("PEM certificate had no start tag '%s'."),
576 start += strlen (PEM_CERT_BEGIN);
577 if (!find_tag (PEM_CERT_END, contents, start, &end)) {
578 g_set_error (error, NM_CRYPTO_ERROR,
579 NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
580 _("PEM certificate had no end tag '%s'."),
585 /* g_base64_decode() wants a NULL-terminated string */
586 save_end = contents->data[end];
587 contents->data[end] = '\0';
588 der = g_base64_decode ((const char *) (contents->data + start), &length);
589 contents->data[end] = save_end;
592 cert = g_byte_array_sized_new (length);
593 g_byte_array_append (cert, der, length);
594 g_assert (cert->len == length);
596 g_set_error (error, NM_CRYPTO_ERROR,
597 NM_CRYPTO_ERR_DECODE_FAILED,
598 _("Failed to decode certificate."));
607 crypto_load_and_verify_certificate (const char *file,
608 NMCryptoFileFormat *out_file_format,
611 GByteArray *array, *contents;
613 g_return_val_if_fail (file != NULL, NULL);
614 g_return_val_if_fail (out_file_format != NULL, NULL);
615 g_return_val_if_fail (*out_file_format == NM_CRYPTO_FILE_FORMAT_UNKNOWN, NULL);
617 contents = file_to_g_byte_array (file, error);
621 /* Check for PKCS#12 */
622 if (crypto_is_pkcs12_data (contents)) {
623 *out_file_format = NM_CRYPTO_FILE_FORMAT_PKCS12;
627 /* Check for plain DER format */
628 if (contents->len > 2 && contents->data[0] == 0x30 && contents->data[1] == 0x82) {
629 *out_file_format = crypto_verify_cert (contents->data, contents->len, error);
631 array = extract_pem_cert_data (contents, error);
633 g_byte_array_free (contents, TRUE);
637 *out_file_format = crypto_verify_cert (array->data, array->len, error);
638 g_byte_array_free (array, TRUE);
641 if (*out_file_format != NM_CRYPTO_FILE_FORMAT_X509) {
642 g_byte_array_free (contents, TRUE);
650 crypto_is_pkcs12_data (const GByteArray *data)
652 GError *error = NULL;
655 g_return_val_if_fail (data != NULL, FALSE);
657 success = crypto_verify_pkcs12 (data, NULL, &error);
658 if (success == FALSE) {
659 /* If the error was just a decryption error, then it's pkcs#12 */
661 if (g_error_matches (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED))
663 g_error_free (error);
670 crypto_is_pkcs12_file (const char *file, GError **error)
672 GByteArray *contents;
673 gboolean success = FALSE;
675 g_return_val_if_fail (file != NULL, FALSE);
677 contents = file_to_g_byte_array (file, error);
679 success = crypto_is_pkcs12_data (contents);
680 g_byte_array_free (contents, TRUE);
685 /* Verifies that a private key can be read, and if a password is given, that
686 * the private key can be decrypted with that password.
689 crypto_verify_private_key_data (const GByteArray *contents,
690 const char *password,
694 NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
695 NMCryptoKeyType ktype = NM_CRYPTO_KEY_TYPE_UNKNOWN;
696 gboolean is_encrypted = FALSE;
698 g_return_val_if_fail (contents != NULL, FALSE);
700 /* Check for PKCS#12 first */
701 if (crypto_is_pkcs12_data (contents)) {
702 if (!password || crypto_verify_pkcs12 (contents, password, error))
703 format = NM_CRYPTO_FILE_FORMAT_PKCS12;
705 /* Maybe it's PKCS#8 */
706 tmp = parse_pkcs8_key_file (contents, &is_encrypted, error);
708 if (crypto_verify_pkcs8 (tmp, is_encrypted, password, error))
709 format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
711 g_clear_error (error);
713 /* Or it's old-style OpenSSL */
714 tmp = crypto_decrypt_private_key_data (contents, password, &ktype, error);
716 format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
717 else if (!password && (ktype != NM_CRYPTO_KEY_TYPE_UNKNOWN))
718 format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
722 /* Don't leave decrypted key data around */
723 memset (tmp->data, 0, tmp->len);
724 g_byte_array_free (tmp, TRUE);
732 crypto_verify_private_key (const char *filename,
733 const char *password,
736 GByteArray *contents;
737 NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
739 g_return_val_if_fail (filename != NULL, FALSE);
741 contents = file_to_g_byte_array (filename, error);
743 format = crypto_verify_private_key_data (contents, password, error);
744 g_byte_array_free (contents, TRUE);