gboolean gkd_ssh_agent_proto_write_public_v1 (EggBuffer *resp, GckAttributes *attrs) { const GckAttribute *attr; gulong bits; g_assert (resp); g_assert (attrs); /* This is always an RSA key. */ /* Write out the number of bits of the key */ if (!gck_attributes_find_ulong (attrs, CKA_MODULUS_BITS, &bits)) g_return_val_if_reached (FALSE); egg_buffer_add_uint32 (resp, bits); /* Write out the exponent */ attr = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr)) return FALSE; /* Write out the modulus */ attr = gck_attributes_find (attrs, CKA_MODULUS); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr)) return FALSE; return TRUE; }
gboolean gkd_ssh_agent_proto_read_pair_v1 (EggBuffer *req, gsize *offset, GckAttributes *priv_attrs, GckAttributes *pub_attrs) { GckAttribute *attr; g_assert (req); g_assert (offset); g_assert (priv_attrs); g_assert (pub_attrs); if (!gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_MODULUS) || !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PUBLIC_EXPONENT) || !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PRIVATE_EXPONENT) || !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_COEFFICIENT) || !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PRIME_1) || !gkd_ssh_agent_proto_read_mpi_v1 (req, offset, priv_attrs, CKA_PRIME_2)) return FALSE; /* Copy attributes to the public key */ attr = gck_attributes_find (priv_attrs, CKA_MODULUS); gck_attributes_add (pub_attrs, attr); attr = gck_attributes_find (priv_attrs, CKA_PUBLIC_EXPONENT); gck_attributes_add (pub_attrs, attr); /* Add in your basic other required attributes */ gck_attributes_add_ulong (priv_attrs, CKA_CLASS, CKO_PRIVATE_KEY); gck_attributes_add_ulong (priv_attrs, CKA_KEY_TYPE, CKK_RSA); gck_attributes_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY); gck_attributes_add_ulong (pub_attrs, CKA_KEY_TYPE, CKK_RSA); return TRUE; }
gboolean gkd_ssh_agent_proto_write_public_dsa (EggBuffer *resp, GckAttributes *attrs) { const GckAttribute *attr; g_assert (resp); g_assert (attrs); attr = gck_attributes_find (attrs, CKA_PRIME); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi (resp, attr)) return FALSE; attr = gck_attributes_find (attrs, CKA_SUBPRIME); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi (resp, attr)) return FALSE; attr = gck_attributes_find (attrs, CKA_BASE); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi (resp, attr)) return FALSE; attr = gck_attributes_find (attrs, CKA_VALUE); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi (resp, attr)) return FALSE; return TRUE; }
gboolean gkd_ssh_agent_proto_read_pair_dsa (EggBuffer *req, gsize *offset, GckAttributes *priv_attrs, GckAttributes *pub_attrs) { GckAttribute *attr; g_assert (req); g_assert (offset); g_assert (priv_attrs); g_assert (pub_attrs); if (!gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_PRIME) || !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_SUBPRIME) || !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_BASE) || !gkd_ssh_agent_proto_read_mpi (req, offset, pub_attrs, CKA_VALUE) || !gkd_ssh_agent_proto_read_mpi (req, offset, priv_attrs, CKA_VALUE)) return FALSE; /* Copy attributes to the public key */ attr = gck_attributes_find (priv_attrs, CKA_PRIME); gck_attributes_add (pub_attrs, attr); attr = gck_attributes_find (priv_attrs, CKA_SUBPRIME); gck_attributes_add (pub_attrs, attr); attr = gck_attributes_find (priv_attrs, CKA_BASE); gck_attributes_add (pub_attrs, attr); /* Add in your basic other required attributes */ gck_attributes_add_ulong (priv_attrs, CKA_CLASS, CKO_PRIVATE_KEY); gck_attributes_add_ulong (priv_attrs, CKA_KEY_TYPE, CKK_DSA); gck_attributes_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY); gck_attributes_add_ulong (pub_attrs, CKA_KEY_TYPE, CKK_DSA); return TRUE; }
static gboolean rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn) { const GckAttribute *modulus; const GckAttribute *exponent; GNode *key_asn; GNode *params_asn; GBytes *key; GBytes *usg; modulus = gck_attributes_find (attrs, CKA_MODULUS); exponent = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT); if (modulus == NULL || gck_attribute_is_invalid (modulus) || exponent == NULL || gck_attribute_is_invalid (exponent)) return FALSE; key_asn = egg_asn1x_create (pk_asn1_tab, "RSAPublicKey"); g_return_val_if_fail (key_asn, FALSE); params_asn = egg_asn1x_create (pk_asn1_tab, "RSAParameters"); g_return_val_if_fail (params_asn, FALSE); usg = g_bytes_new_with_free_func (modulus->value, modulus->length, gck_attributes_unref, gck_attributes_ref (attrs)); egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL), usg); g_bytes_unref (usg); usg = g_bytes_new_with_free_func (exponent->value, exponent->length, gck_attributes_unref, gck_attributes_ref (attrs)); egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL), usg); g_bytes_unref (usg); key = egg_asn1x_encode (key_asn, NULL); egg_asn1x_destroy (key_asn); egg_asn1x_set_null (params_asn); egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL), key, g_bytes_get_size (key) * 8); egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA); egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn); egg_asn1x_destroy (params_asn); g_bytes_unref (key); return TRUE; }
static void imported_object (GckObject *object, const gchar *destination) { gulong attr_types[3]; GckAttributes *attrs; const GckAttribute *id; CK_OBJECT_CLASS klass; const gchar *message; GError *err = NULL; gchar *label, *hex; attr_types[0] = CKA_LABEL; attr_types[1] = CKA_CLASS; attr_types[2] = CKA_ID; attrs = gck_object_get_full (object, attr_types, G_N_ELEMENTS (attr_types), NULL, &err); if (attrs == NULL) { gkr_tool_handle_error (&err, "couldn't get imported object info"); return; } if (!gck_attributes_find_string (attrs, CKA_LABEL, &label)) label = g_strdup ("unknown"); if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass)) klass = CKO_DATA; id = gck_attributes_find (attrs, CKA_ID); switch (klass) { case CKO_CERTIFICATE: message = "%s: imported certificate: %s\n"; break; case CKO_DATA: message = "%s: imported data: %s\n"; break; case CKO_PRIVATE_KEY: message = "%s: imported private key: %s\n"; break; case CKO_PUBLIC_KEY: message = "%s: imported public key: %s\n"; break; case CKO_SECRET_KEY: message = "%s: imported secret key: %s\n"; break; default: message = "%s: imported object: %s\n"; break; }; g_print (message, destination, label); if (id) { hex = egg_hex_encode (id->value, id->length); g_print ("\tidentifier: %s\n", hex); g_free (hex); } gck_attributes_unref (attrs); g_free (label); }
static GNode * cert_subject_public_key_from_attributes (GckAttributes *attributes) { const GckAttribute *attr; GBytes *bytes; GNode *cert; GNode *asn; attr = gck_attributes_find (attributes, CKA_VALUE); if (attr == NULL || gck_attribute_is_invalid (attr)) { _gcr_debug ("no value attribute for certificate"); return NULL; } bytes = g_bytes_new_with_free_func (attr->value, attr->length, gck_attributes_unref, gck_attributes_ref (attributes)); cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes); g_bytes_unref (bytes); if (cert == NULL) { _gcr_debug ("couldn't parse certificate value"); return NULL; } asn = egg_asn1x_node (cert, "tbsCertificate", "subjectPublicKeyInfo", NULL); g_return_val_if_fail (asn != NULL, NULL); /* Remove the subject public key out of the certificate */ g_node_unlink (asn); egg_asn1x_destroy (cert); return asn; }
GckObject* gkd_secret_create_with_credential (GckSession *session, GckAttributes *attrs, GckObject *cred, GError **error) { GckAttributes *atts; GckAttribute *attr; GckObject *collection; gboolean token; atts = gck_attributes_new (); gck_attributes_add_ulong (atts, CKA_G_CREDENTIAL, gck_object_get_handle (cred)); gck_attributes_add_ulong (atts, CKA_CLASS, CKO_G_COLLECTION); attr = gck_attributes_find (attrs, CKA_LABEL); if (attr != NULL) gck_attributes_add (atts, attr); if (!gck_attributes_find_boolean (attrs, CKA_TOKEN, &token)) token = FALSE; gck_attributes_add_boolean (atts, CKA_TOKEN, token); collection = gck_session_create_object (session, atts, NULL, error); gck_attributes_unref (atts); return collection; }
static GckObject * lookup_public_key (GckObject *object, GCancellable *cancellable, GError **lerror) { GckBuilder builder = GCK_BUILDER_INIT; gulong attr_types[] = { CKA_ID }; GckAttributes *attrs; GError *error = NULL; GckSession *session; GckObject *result; const GckAttribute *id; GList *objects; attrs = gck_object_cache_lookup (object, attr_types, G_N_ELEMENTS (attr_types), cancellable, &error); if (error != NULL) { _gcr_debug ("couldn't load private key id: %s", error->message); g_propagate_error (lerror, error); return NULL; } id = gck_attributes_find (attrs, CKA_ID); if (id == NULL || gck_attribute_is_invalid (id)) { gck_attributes_unref (attrs); _gcr_debug ("couldn't load private key id"); g_set_error_literal (lerror, GCK_ERROR, CKR_ATTRIBUTE_TYPE_INVALID, gck_message_from_rv (CKR_ATTRIBUTE_TYPE_INVALID)); return NULL; } gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY); gck_builder_add_attribute (&builder, id); gck_attributes_unref (attrs); session = gck_object_get_session (object); objects = gck_session_find_objects (session, gck_builder_end (&builder), cancellable, &error); g_object_unref (session); if (error != NULL) { _gcr_debug ("couldn't lookup public key: %s", error->message); g_propagate_error (lerror, error); return NULL; } if (!objects) return NULL; result = g_object_ref (objects->data); gck_list_unref_free (objects); return result; }
gboolean gkd_ssh_agent_proto_write_public_rsa (EggBuffer *resp, GckAttributes *attrs) { const GckAttribute *attr; g_assert (resp); g_assert (attrs); attr = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi (resp, attr)) return FALSE; attr = gck_attributes_find (attrs, CKA_MODULUS); g_return_val_if_fail (attr, FALSE); if (!gkd_ssh_agent_proto_write_mpi (resp, attr)) return FALSE; return TRUE; }
/** * gck_attributes_find_date: * @attrs: The attributes array to search. * @attr_type: The type of attribute to find. * @value: The resulting GDate value. * * Find an attribute with the specified type in the array. * * The attribute (if found) must be of the right size to store * a date value (ie: CK_DATE). If the attribute is marked invalid * then it will be treated as not found. * * Return value: Whether a value was found or not. **/ gboolean gck_attributes_find_date (GckAttributes *attrs, gulong attr_type, GDate *value) { GckAttribute *attr; g_return_val_if_fail (value, FALSE); g_return_val_if_fail (!attrs->locked, FALSE); attr = gck_attributes_find (attrs, attr_type); if (!attr || gck_attribute_is_invalid (attr)) return FALSE; gck_attribute_get_date (attr, value); return TRUE; }
/** * gck_attributes_find_string: * @attrs: The attributes array to search. * @attr_type: The type of attribute to find. * @value: The resulting string value. * * Find an attribute with the specified type in the array. * * If the attribute is marked invalid then it will be treated as not found. * The resulting string will be null-terminated, and must be freed by the caller * using g_free(). * * Return value: Whether a value was found or not. **/ gboolean gck_attributes_find_string (GckAttributes *attrs, gulong attr_type, gchar **value) { GckAttribute *attr; g_return_val_if_fail (value, FALSE); g_return_val_if_fail (!attrs->locked, FALSE); attr = gck_attributes_find (attrs, attr_type); if (!attr || gck_attribute_is_invalid (attr)) return FALSE; *value = gck_attribute_get_string (attr); return TRUE; }
GckObject* gkd_secret_create_with_credential (GckSession *session, GckAttributes *attrs, GckObject *cred, GError **error) { GckBuilder builder = GCK_BUILDER_INIT; const GckAttribute *attr; gboolean token; gck_builder_add_ulong (&builder, CKA_G_CREDENTIAL, gck_object_get_handle (cred)); gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION); attr = gck_attributes_find (attrs, CKA_LABEL); if (attr != NULL) gck_builder_add_attribute (&builder, attr); if (!gck_attributes_find_boolean (attrs, CKA_TOKEN, &token)) token = FALSE; gck_builder_add_boolean (&builder, CKA_TOKEN, token); return gck_session_create_object (session, gck_builder_end (&builder), NULL, error); }
static gboolean collection_method_create_item (GkdExportedCollection *skeleton, GDBusMethodInvocation *invocation, GVariant *properties, GVariant *secret_variant, gboolean replace, GkdSecretObjects *self) { GckBuilder builder = GCK_BUILDER_INIT; GckSession *pkcs11_session = NULL; GkdSecretSecret *secret = NULL; GckAttributes *attrs = NULL; const GckAttribute *fields; GckObject *item = NULL; const gchar *base; GError *error = NULL; gchar *path = NULL; gchar *identifier; gboolean created = FALSE; GckObject *object; object = secret_objects_lookup_gck_object_for_invocation (self, invocation); if (!object) { return TRUE; } if (!gkd_secret_property_parse_all (properties, SECRET_ITEM_INTERFACE, &builder)) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid properties argument"); goto cleanup; } base = g_dbus_method_invocation_get_object_path (invocation); secret = gkd_secret_secret_parse (self->service, g_dbus_method_invocation_get_sender (invocation), secret_variant, &error); if (secret == NULL) { g_dbus_method_invocation_take_error (invocation, error); error = NULL; goto cleanup; } if (!gkd_secret_util_parse_path (base, &identifier, NULL)) g_return_val_if_reached (FALSE); g_return_val_if_fail (identifier, FALSE); pkcs11_session = gck_object_get_session (object); g_return_val_if_fail (pkcs11_session, FALSE); attrs = gck_attributes_ref_sink (gck_builder_end (&builder)); if (replace) { fields = gck_attributes_find (attrs, CKA_G_FIELDS); if (fields) item = collection_find_matching_item (self, pkcs11_session, identifier, fields); } /* Replace the item */ if (item) { if (!gck_object_set (item, attrs, NULL, &error)) goto cleanup; /* Create a new item */ } else { gck_builder_add_all (&builder, attrs); gck_builder_add_string (&builder, CKA_G_COLLECTION, identifier); gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY); item = gck_session_create_object (pkcs11_session, gck_builder_end (&builder), NULL, &error); if (item == NULL) goto cleanup; created = TRUE; } /* Set the secret */ if (!gkd_secret_session_set_item_secret (secret->session, item, secret, &error)) { if (created) /* If we created, then try to destroy on failure */ gck_object_destroy (item, NULL, NULL); goto cleanup; } path = object_path_for_item (base, item); gkd_secret_objects_emit_item_created (self, object, path); gkd_exported_collection_complete_create_item (skeleton, invocation, path, "/"); cleanup: if (error) { if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN)) g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR, GKD_SECRET_ERROR_IS_LOCKED, "Cannot create an item in a locked collection"); else g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Couldn't create item: %s", egg_error_message (error)); g_clear_error (&error); } gkd_secret_secret_free (secret); gck_attributes_unref (attrs); if (item) g_object_unref (item); if (pkcs11_session) g_object_unref (pkcs11_session); g_free (path); g_object_unref (object); return TRUE; }
static gboolean dsa_subject_public_key_from_attributes (GckAttributes *attrs, gulong klass, GNode *info_asn) { const GckAttribute *value, *g, *q, *p; GNode *key_asn, *params_asn; GBytes *key; p = gck_attributes_find (attrs, CKA_PRIME); q = gck_attributes_find (attrs, CKA_SUBPRIME); g = gck_attributes_find (attrs, CKA_BASE); value = gck_attributes_find (attrs, CKA_VALUE); if (p == NULL || gck_attribute_is_invalid (p) || q == NULL || gck_attribute_is_invalid (q) || g == NULL || gck_attribute_is_invalid (g) || value == NULL || gck_attribute_is_invalid (value)) return FALSE; key_asn = egg_asn1x_create (pk_asn1_tab, "DSAPublicPart"); g_return_val_if_fail (key_asn, FALSE); params_asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters"); g_return_val_if_fail (params_asn, FALSE); egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL), g_bytes_new_with_free_func (p->value, p->length, gck_attributes_unref, gck_attributes_ref (attrs))); egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL), g_bytes_new_with_free_func (q->value, q->length, gck_attributes_unref, gck_attributes_ref (attrs))); egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL), g_bytes_new_with_free_func (g->value, g->length, gck_attributes_unref, gck_attributes_ref (attrs))); /* Are these attributes for a public or private key? */ if (klass == CKO_PRIVATE_KEY) { /* We need to calculate the public from the private key */ if (!dsa_subject_public_key_from_private (key_asn, p, q, g, value)) g_return_val_if_reached (FALSE); } else if (klass == CKO_PUBLIC_KEY) { egg_asn1x_take_integer_as_usg (key_asn, g_bytes_new_with_free_func (value->value, value->length, gck_attributes_unref, gck_attributes_ref (attrs))); } else { g_assert_not_reached (); } key = egg_asn1x_encode (key_asn, NULL); egg_asn1x_destroy (key_asn); egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL), key, g_bytes_get_size (key) * 8); egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn); egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA); g_bytes_unref (key); egg_asn1x_destroy (params_asn); return TRUE; }