/* In-process crypto implementation. Copyright 2010 Red Hat, Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Red Hat author: Miloslav Trmač */ #include #include #include #include #include #include #include #include "internal.h" /* Symmetric keys */ CK_RV ncr_symm_key_create (struct ncr_symm_key **key, CK_KEY_TYPE type, _Bool sensitive, const void *value, size_t value_size) { struct ncr_symm_key *k; g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); g_return_val_if_fail (value != NULL || value_size == 0, CKR_ARGUMENTS_BAD); /* FIXME? validate "type" */ /* FIXME: PKCS#11 modules should refuse keys with incorrect parity here */ k = malloc (sizeof (*k) + value_size); if (k == NULL) return CKR_HOST_MEMORY; k->type = type; k->sensitive = sensitive; k->size = value_size; memcpy (k->value, value, value_size); *key = k; return CKR_OK; } /* Return non-zero if the key is unusable */ #define DES_KEY_SIZE 8 static int des3_fixup_key (uint8_t value[static 3 * DES_KEY_SIZE]) { static const uint8_t weak_keys[][DES_KEY_SIZE] = { "\x01\x01\x01\x01\x01\x01\x01\x01", "\x1F\x1F\x1F\x1F\x0E\x0E\x0E\x0E", "\xE0\xE0\xE0\xE0\xF1\xF1\xF1\xF1", "\xFE\xFE\xFE\xFE\xFE\xFE\xFE\xFE", "\x01\xFE\x01\xFE\x01\xFE\x01\xFE", "\xFE\x01\xFE\x01\xFE\x01\xFE\x01", "\x1F\xE0\x1F\xE0\x0E\xF1\x0E\xF1", "\xE0\x1F\xE0\x1F\xF1\x0E\xF1\x0E", "\x01\xE0\x01\xE0\x01\xF1\x01\xF1", "\xE0\x01\xE0\x01\xF1\x01\xF1\x01", "\x1F\xFE\x1F\xFE\x0E\xFE\x0E\xFE", "\xFE\x1F\xFE\x1F\xFE\x0E\xFE\x0E", "\x01\x1F\x01\x1F\x01\x0E\x01\x0E", "\x1F\x01\x1F\x01\x0E\x01\x0E\x01", "\xE0\xFE\xE0\xFE\xF1\xFE\xF1\xFE", "\xFE\xE0\xFE\xE0\xFE\xF1\xFE\xF1" }; size_t i; for (i = 0; i < 3; i++) { uint8_t *key; size_t j; key = value + i * 8; for (j = 0; j < DES_KEY_SIZE; j++) { uint8_t v; v = key[i]; v ^= v >> 4; /* v & 0x0F has the same parity as key[i] */ v ^= v >> 2; /* v & 0x03 has the same parity as key[i] */ v ^= v >> 1; /* v & 0x01 has the same parity as key[i] */ key[i] ^= (v & 0x01) ^ 0x01; /* Ensure odd parity */ } for (j = 0; j < G_N_ELEMENTS (weak_keys); j++) { if (memcmp (key, weak_keys[j], DES_KEY_SIZE) == 0) return 1; } } return 0; } #undef DES_KEY_SIZE CK_RV ncr_symm_key_generate (struct ncr_symm_key **key, CK_MECHANISM_TYPE mech, _Bool sensitive, size_t value_size) { struct ncr_symm_key *k; CK_KEY_TYPE type; CK_RV res; g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); switch (mech) { case CKM_AES_KEY_GEN: type = CKK_AES; g_return_val_if_fail (value_size == 16 || value_size == 24 || value_size == 32, CKR_TEMPLATE_INCONSISTENT); break; case CKM_DES3_KEY_GEN: type = CKK_DES3; g_return_val_if_fail (value_size == 24 || value_size == 0, CKR_TEMPLATE_INCONSISTENT); value_size = 24; break; case CKM_GENERIC_SECRET_KEY_GEN: type = CKK_GENERIC_SECRET; g_return_val_if_fail (value_size <= SIZE_MAX - sizeof (*k), CKR_HOST_MEMORY); break; default: g_return_val_if_reached (CKR_MECHANISM_INVALID); } k = malloc (sizeof (*k) + value_size); if (k == NULL) return CKR_HOST_MEMORY; k->type = type; k->sensitive = sensitive; k->size = value_size; regenerate: res = ncr_get_random_bytes (k->value, value_size); if (res != CKR_OK) { ncr_symm_key_destroy (k); return res; } if (type == CKK_DES3) { if (des3_fixup_key (k->value) != 0) goto regenerate; } *key = k; return CKR_OK; } CK_RV ncr_symm_key_set_sensitive (struct ncr_symm_key *key) { g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); key->sensitive = true; return CKR_OK; } CK_RV ncr_symm_key_export (struct ncr_symm_key *key, void *dest, size_t *dest_size_ptr) { g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); g_return_val_if_fail (!key->sensitive, CKR_ATTRIBUTE_SENSITIVE); if (dest == NULL) { *dest_size_ptr = key->size; return CKR_OK; } if (*dest_size_ptr < key->size) { *dest_size_ptr = key->size; return CKR_BUFFER_TOO_SMALL; } memcpy (dest, key->value, key->size); *dest_size_ptr = key->size; return CKR_OK; } CK_RV ncr_symm_key_destroy (struct ncr_symm_key *key) { g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); memset (key->value, 0, key->size); /* FIXME: is this safe WRT optimization? */ free (key); return CKR_OK; }