static void apartment_free (gpointer data) { Apartment *apt; GList *l; g_assert (data != NULL); apt = (Apartment*)data; g_return_if_fail (GKM_IS_MANAGER (apt->session_manager)); /* Unreference all the sessions */ for (l = apt->sessions; l; l = g_list_next (l)) { /* Some sanity checks to make sure things have remained as expected */ g_return_if_fail (GKM_IS_SESSION (l->data)); g_return_if_fail (gkm_session_get_apartment (l->data) == apt->apt_id); g_return_if_fail (gkm_session_get_manager (l->data) == apt->session_manager); g_return_if_fail (gkm_session_get_logged_in (l->data) == apt->logged_in); g_object_unref (l->data); } g_list_free (apt->sessions); g_object_unref (apt->session_manager); g_slice_free (Apartment, apt); }
CK_RV gkm_crypto_derive_key (GkmSession *session, CK_MECHANISM_PTR mech, GkmObject *base, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GkmObject **derived) { g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (GKM_IS_OBJECT (base), CKR_GENERAL_ERROR); g_return_val_if_fail (derived, CKR_GENERAL_ERROR); if (!gkm_object_has_attribute_ulong (base, session, CKA_ALLOWED_MECHANISMS, mech->mechanism)) return CKR_KEY_TYPE_INCONSISTENT; if (!gkm_object_has_attribute_boolean (base, session, CKA_DERIVE, TRUE)) return CKR_KEY_FUNCTION_NOT_PERMITTED; switch (mech->mechanism) { case CKM_DH_PKCS_DERIVE: return gkm_dh_mechanism_derive (session, mech, base, attrs, n_attrs, derived); case CKM_G_HKDF_SHA256_DERIVE: return gkm_hkdf_mechanism_derive (session, "sha256", mech, base, attrs, n_attrs, derived); default: return CKR_MECHANISM_INVALID; } }
CK_RV gkm_crypto_unwrap_key (GkmSession *session, CK_MECHANISM_PTR mech, GkmObject *wrapper, CK_VOID_PTR input, CK_ULONG n_input, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GkmObject **unwrapped) { g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (GKM_IS_OBJECT (wrapper), CKR_GENERAL_ERROR); g_return_val_if_fail (mech, CKR_GENERAL_ERROR); g_return_val_if_fail (unwrapped, CKR_GENERAL_ERROR); if (!gkm_object_has_attribute_ulong (wrapper, session, CKA_ALLOWED_MECHANISMS, mech->mechanism)) return CKR_KEY_TYPE_INCONSISTENT; if (!gkm_object_has_attribute_boolean (wrapper, session, CKA_UNWRAP, TRUE)) return CKR_KEY_FUNCTION_NOT_PERMITTED; switch (mech->mechanism) { case CKM_AES_CBC_PAD: return gkm_aes_mechanism_unwrap (session, mech, wrapper, input, n_input, attrs, n_attrs, unwrapped); case CKM_G_NULL: return gkm_null_mechanism_unwrap (session, mech, wrapper, input, n_input, attrs, n_attrs, unwrapped); default: return CKR_MECHANISM_INVALID; } }
gboolean gkm_object_has_attribute_ulong (GkmObject *self, GkmSession *session, CK_ATTRIBUTE_TYPE type, gulong value) { gulong *data; gsize n_data, i; g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE); g_return_val_if_fail (GKM_IS_SESSION (session), FALSE); data = gkm_object_get_attribute_data (self, session, type, &n_data); if (data == NULL) return FALSE; g_return_val_if_fail (n_data % sizeof (gulong) == 0, FALSE); for (i = 0; i < n_data / sizeof (gulong); ++i) { if (data[i] == value) { g_free (data); return TRUE; } } g_free (data); return FALSE; }
gboolean gkm_object_has_attribute_boolean (GkmObject *self, GkmSession *session, CK_ATTRIBUTE_TYPE type, gboolean value) { gboolean data; g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE); g_return_val_if_fail (GKM_IS_SESSION (session), FALSE); if (!gkm_object_get_attribute_boolean (self, session, type, &data)) return FALSE; return data == value; }
GkmSession* gkm_module_lookup_session (GkmModule *self, CK_SESSION_HANDLE handle) { GkmSession *session; g_return_val_if_fail (GKM_IS_MODULE (self), NULL); session = g_hash_table_lookup (self->pv->sessions_by_handle, &handle); if (!session) return NULL; g_return_val_if_fail (GKM_IS_SESSION (session), NULL); return session; }
CK_RV gkm_crypto_prepare (GkmSession *session, CK_MECHANISM_TYPE mech, GkmObject *key) { g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); switch (mech) { case CKM_RSA_PKCS: case CKM_RSA_X_509: case CKM_DSA: return gkm_crypto_prepare_xsa (session, mech, key); default: g_return_val_if_reached (CKR_GENERAL_ERROR); } }
void gkm_object_create_attributes (GkmObject *self, GkmSession *session, GkmTransaction *transaction, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs) { g_return_if_fail (GKM_IS_OBJECT (self)); g_return_if_fail (GKM_IS_TRANSACTION (transaction)); g_return_if_fail (!gkm_transaction_get_failed (transaction)); g_return_if_fail (GKM_IS_SESSION (session)); g_return_if_fail (attrs); g_assert (GKM_OBJECT_GET_CLASS (self)->create_attributes); /* Check that the value will actually change */ GKM_OBJECT_GET_CLASS (self)->create_attributes (self, session, transaction, attrs, n_attrs); }
CK_RV gkm_crypto_prepare_xsa (GkmSession *session, CK_MECHANISM_TYPE mech, GkmObject *key) { GkmSexp *sexp; g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (GKM_IS_SEXP_KEY (key), CKR_GENERAL_ERROR); /* Load up the actual sexp we're going to use */ sexp = gkm_sexp_key_acquire_crypto_sexp (GKM_SEXP_KEY (key), session); if (sexp == NULL) return CKR_USER_NOT_LOGGED_IN; gkm_session_set_crypto_state (session, sexp, gkm_sexp_unref); return CKR_OK; }
CK_RV gkm_crypto_generate_key_pair (GkmSession *session, CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_PTR pub_atts, CK_ULONG n_pub_atts, CK_ATTRIBUTE_PTR priv_atts, CK_ULONG n_priv_atts, GkmObject **pub_key, GkmObject **priv_key) { g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (pub_key, CKR_GENERAL_ERROR); g_return_val_if_fail (priv_key, CKR_GENERAL_ERROR); switch (mech) { case CKM_DH_PKCS_KEY_PAIR_GEN: return gkm_dh_mechanism_generate (session, pub_atts, n_pub_atts, priv_atts, n_priv_atts, pub_key, priv_key); default: return CKR_MECHANISM_INVALID; } }
CK_RV gkm_crypto_perform (GkmSession *session, CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TYPE method, CK_BYTE_PTR bufone, CK_ULONG n_bufone, CK_BYTE_PTR buftwo, CK_ULONG_PTR n_buftwo) { g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (method, CKR_GENERAL_ERROR); g_return_val_if_fail (n_buftwo, CKR_GENERAL_ERROR); switch (method) { case CKA_ENCRYPT: return gkm_crypto_encrypt (session, mech, bufone, n_bufone, buftwo, n_buftwo); case CKA_DECRYPT: return gkm_crypto_decrypt (session, mech, bufone, n_bufone, buftwo, n_buftwo); case CKA_SIGN: return gkm_crypto_sign (session, mech, bufone, n_bufone, buftwo, n_buftwo); case CKA_VERIFY: return gkm_crypto_verify (session, mech, bufone, n_bufone, buftwo, *n_buftwo); default: g_return_val_if_reached (CKR_GENERAL_ERROR); } }
gboolean gkm_credential_for_each (GkmSession *session, GkmObject *object, GkmCredentialFunc func, gpointer user_data) { CK_OBJECT_HANDLE handle; CK_OBJECT_CLASS klass; CK_ATTRIBUTE attrs[2]; GList *results, *l; GkmCredential *cred; gboolean ret; g_return_val_if_fail (GKM_IS_SESSION (session), FALSE); g_return_val_if_fail (GKM_IS_OBJECT (object), FALSE); g_return_val_if_fail (func, FALSE); /* Do we have one right on the session */ cred = gkm_session_get_credential (session); if (cred && gkm_credential_get_object (cred) == object) { g_object_ref (cred); ret = (func) (cred, object, user_data); g_object_unref (cred); if (ret) return TRUE; } klass = CKO_G_CREDENTIAL; attrs[0].type = CKA_CLASS; attrs[0].pValue = &klass; attrs[0].ulValueLen = sizeof (klass); handle = gkm_object_get_handle (object); attrs[1].type = CKA_G_OBJECT; attrs[1].pValue = &handle; attrs[1].ulValueLen = sizeof (handle); /* Find any on the session */ results = gkm_manager_find_by_attributes (gkm_session_get_manager (session), session, attrs, G_N_ELEMENTS (attrs)); for (l = results; l; l = g_list_next (l)) { g_object_ref (l->data); ret = (func) (l->data, object, user_data); g_object_unref (l->data); if (ret) break; } g_list_free (results); if (l != NULL) return TRUE; /* Find any in the token */ results = gkm_manager_find_by_attributes (gkm_module_get_manager (gkm_session_get_module (session)), session, attrs, G_N_ELEMENTS (attrs)); for (l = results; l; l = g_list_next (l)) { g_object_ref (l->data); ret = (func) (l->data, object, user_data); g_object_unref (l->data); if (ret) break; } g_list_free (results); return (l != NULL); }
CK_RV gkm_aes_mechanism_wrap (GkmSession *session, CK_MECHANISM_PTR mech, GkmObject *wrapper, GkmObject *wrapped, CK_BYTE_PTR output, CK_ULONG_PTR n_output) { gcry_cipher_hd_t cih; gcry_error_t gcry; GkmAesKey *key; gpointer value, padded; gsize n_value, n_padded; gsize block, pos; gboolean ret; CK_RV rv; g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (mech, CKR_GENERAL_ERROR); g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR); g_return_val_if_fail (GKM_IS_OBJECT (wrapped), CKR_GENERAL_ERROR); g_return_val_if_fail (n_output, CKR_GENERAL_ERROR); if (!GKM_IS_AES_KEY (wrapper)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; key = GKM_AES_KEY (wrapper); block = gkm_aes_key_get_block_size (key); g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR); /* They just want the length */ if (!output) { rv = retrieve_length (session, wrapped, &n_value); if (rv != CKR_OK) return rv; if (!egg_padding_pkcs7_pad (NULL, block, NULL, n_value, NULL, &n_padded)) return CKR_KEY_SIZE_RANGE; *n_output = n_padded; return CKR_OK; } cih = gkm_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC); if (cih == NULL) return CKR_FUNCTION_FAILED; if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) { gcry_cipher_close (cih); return CKR_MECHANISM_PARAM_INVALID; } rv = retrieve_value (session, wrapped, &value, &n_value); if (rv != CKR_OK) { gcry_cipher_close (cih); return rv; } ret = egg_padding_pkcs7_pad (egg_secure_realloc, block, value, n_value, &padded, &n_padded); egg_secure_free (value); if (ret == FALSE) { gcry_cipher_close (cih); return CKR_KEY_SIZE_RANGE; } /* In place encryption */ for (pos = 0; pos < n_padded; pos += block) { gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, block, NULL, 0); g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR); } gcry_cipher_close (cih); rv = gkm_util_return_data (output, n_output, padded, n_padded); egg_secure_free (padded); return rv; }
CK_RV gkm_aes_mechanism_unwrap (GkmSession *session, CK_MECHANISM_PTR mech, GkmObject *wrapper, CK_VOID_PTR input, CK_ULONG n_input, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GkmObject **unwrapped) { gcry_cipher_hd_t cih; gcry_error_t gcry; CK_ATTRIBUTE attr; GArray *array; GkmAesKey *key; gpointer padded, value; gsize n_padded, n_value; GkmTransaction *transaction; gsize block, pos; gboolean ret; g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (mech, CKR_GENERAL_ERROR); g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR); g_return_val_if_fail (GKM_IS_OBJECT (wrapper), CKR_GENERAL_ERROR); if (!GKM_IS_AES_KEY (wrapper)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; key = GKM_AES_KEY (wrapper); block = gkm_aes_key_get_block_size (key); g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR); if (n_input == 0 || n_input % block != 0) return CKR_WRAPPED_KEY_LEN_RANGE; cih = gkm_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC); if (cih == NULL) return CKR_FUNCTION_FAILED; if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) { gcry_cipher_close (cih); return CKR_MECHANISM_PARAM_INVALID; } padded = egg_secure_alloc (n_input); memcpy (padded, input, n_input); n_padded = n_input; /* In place decryption */ for (pos = 0; pos < n_padded; pos += block) { gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, block, NULL, 0); g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR); } gcry_cipher_close (cih); /* Unpad the resulting value */ ret = egg_padding_pkcs7_unpad (egg_secure_realloc, block, padded, n_padded, &value, &n_value); egg_secure_free (padded); /* TODO: This is dubious, there doesn't seem to be an rv for 'bad decrypt' */ if (ret == FALSE) return CKR_WRAPPED_KEY_INVALID; /* Now setup the attributes with our new value */ array = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE)); /* Prepend the value */ attr.type = CKA_VALUE; attr.pValue = value; attr.ulValueLen = n_value; g_array_append_val (array, attr); /* Add the remainder of the attributes */ g_array_append_vals (array, attrs, n_attrs); transaction = gkm_transaction_new (); /* Now create an object with these attributes */ *unwrapped = gkm_session_create_object_for_attributes (session, transaction, (CK_ATTRIBUTE_PTR)array->data, array->len); egg_secure_free (value); g_array_free (array, TRUE); return gkm_transaction_complete_and_unref (transaction); }