lasso/lasso/id-ff/server.c

563 lines
17 KiB
C

/* $Id$
*
* Lasso - A free implementation of the Liberty Alliance specifications.
*
* Copyright (C) 2004 Entr'ouvert
* http://lasso.entrouvert.org
*
* Authors: Nicolas Clapies <nclapies@entrouvert.com>
* Valery Febvre <vfebvre@easter-eggs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include <xmlsec/base64.h>
#include <lasso/xml/errors.h>
#include <lasso/environs/server.h>
#define LASSO_SERVER_NODE "Server"
#define LASSO_SERVER_METADATA_NODE "ServerMetadata"
#define LASSO_SERVER_PROVIDERS_NODE "Providers"
#define LASSO_SERVER_PROVIDERID_NODE "ProviderID"
#define LASSO_SERVER_PRIVATE_KEY_NODE "PrivateKey"
#define LASSO_SERVER_CERTIFICATE_NODE "Certificate"
#define LASSO_SERVER_SIGNATURE_METHOD_NODE "SignatureMethod"
struct _LassoServerPrivate
{
gboolean dispose_has_run;
};
static GObjectClass *parent_class = NULL;
/*****************************************************************************/
/* private methods */
/*****************************************************************************/
static gint
lasso_server_add_lasso_provider(LassoServer *server,
LassoProvider *provider)
{
g_return_val_if_fail(LASSO_IS_SERVER(server), -1);
g_return_val_if_fail(LASSO_IS_PROVIDER(provider), -2);
g_ptr_array_add(server->providers, provider);
return 0;
}
/*****************************************************************************/
/* public methods */
/*****************************************************************************/
gint
lasso_server_add_provider(LassoServer *server,
gchar *metadata,
gchar *public_key,
gchar *ca_certificate)
{
LassoProvider *provider;
g_return_val_if_fail(LASSO_IS_SERVER(server), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
g_return_val_if_fail(metadata != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
provider = lasso_provider_new(metadata, public_key, ca_certificate);
if (provider != NULL) {
g_ptr_array_add(server->providers, provider);
}
else {
message(G_LOG_LEVEL_CRITICAL, "Failed to add new provider.\n");
return LASSO_SERVER_ERROR_ADD_PROVIDER_FAILED;
}
return 0;
}
LassoServer*
lasso_server_copy(LassoServer *server)
{
LassoServer *copy;
LassoProvider *p;
guint i;
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
copy = LASSO_SERVER(g_object_new(LASSO_TYPE_SERVER, NULL));
/* herited provider attrs */
LASSO_PROVIDER(copy)->metadata = lasso_node_copy(LASSO_PROVIDER(server)->metadata);
LASSO_PROVIDER(copy)->public_key = g_strdup(LASSO_PROVIDER(server)->public_key);
LASSO_PROVIDER(copy)->ca_certificate = g_strdup(LASSO_PROVIDER(server)->ca_certificate);
/* server attrs */
copy->providers = g_ptr_array_new();
for (i=0; i<server->providers->len; i++) {
p = g_ptr_array_index(server->providers, i);
g_ptr_array_add(copy->providers, lasso_provider_copy(p));
}
copy->providerID = g_strdup(server->providerID);
copy->private_key = g_strdup(server->private_key);
copy->certificate = g_strdup(server->certificate);
copy->signature_method = server->signature_method;
return copy;
}
void
lasso_server_destroy(LassoServer *server)
{
g_object_unref(G_OBJECT(server));
}
gchar *
lasso_server_dump(LassoServer *server)
{
LassoProvider *provider;
LassoNode *server_node, *providers_node, *provider_node, *metadata_copy, *metadata_node, *entity_node;
LassoNodeClass *metadata_class, *server_class, *providers_class;
xmlChar *signature_method_str, *dump;
gint i;
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
server_node = lasso_node_new();
server_class = LASSO_NODE_GET_CLASS(server_node);
server_class->set_name(server_node, LASSO_SERVER_NODE);
server_class->set_ns(server_node, lassoLassoHRef, NULL);
/* signature method */
signature_method_str = g_new(gchar, 6);
sprintf(signature_method_str, "%d", server->signature_method);
server_class->set_prop(server_node, LASSO_SERVER_SIGNATURE_METHOD_NODE, signature_method_str);
g_free(signature_method_str);
/* providerID */
if (server->providerID != NULL) {
server_class->set_prop(server_node, LASSO_SERVER_PROVIDERID_NODE, server->providerID);
}
/* private key */
if (server->private_key != NULL) {
server_class->set_prop(server_node, LASSO_SERVER_PRIVATE_KEY_NODE, server->private_key);
}
/* certificate */
if (server->certificate != NULL) {
server_class->set_prop(server_node, LASSO_SERVER_CERTIFICATE_NODE, server->certificate);
}
/* metadata */
provider = LASSO_PROVIDER(server);
if (provider->metadata != NULL) {
metadata_node = lasso_node_new();
metadata_class = LASSO_NODE_GET_CLASS(metadata_node);
metadata_class->set_name(metadata_node, LASSO_SERVER_METADATA_NODE);
metadata_class->set_ns(metadata_node, lassoLassoHRef, NULL);
metadata_copy = lasso_node_copy(provider->metadata);
metadata_class->add_child(metadata_node, metadata_copy, FALSE);
lasso_node_destroy(metadata_copy);
server_class->add_child(server_node, metadata_node, FALSE);
}
/* public key */
if (provider->public_key != NULL) {
server_class->set_prop(server_node, LASSO_PROVIDER_PUBLIC_KEY_NODE, provider->public_key);
}
/* ca_certificate */
if (provider->ca_certificate != NULL) {
server_class->set_prop(server_node, LASSO_PROVIDER_CA_CERTIFICATE_NODE, provider->ca_certificate);
}
/* providers */
providers_node = lasso_node_new();
providers_class = LASSO_NODE_GET_CLASS(providers_node);
providers_class->set_name(providers_node, LASSO_SERVER_PROVIDERS_NODE);
for (i = 0; i<server->providers->len; i++) {
dump = lasso_provider_dump(g_ptr_array_index(server->providers, i));
provider_node = lasso_node_new_from_dump(dump);
xmlFree(dump);
providers_class->add_child(providers_node, provider_node, TRUE);
lasso_node_destroy(provider_node);
}
server_class->add_child(server_node, providers_node, FALSE);
lasso_node_destroy(providers_node);
dump = lasso_node_export(server_node);
lasso_node_destroy(server_node);
return dump;
}
LassoProvider*
lasso_server_get_provider(LassoServer *server,
gchar *providerID,
GError **err)
{
LassoProvider *provider;
GError *tmp_err = NULL;
if (err != NULL && *err != NULL) {
g_set_error(err, g_quark_from_string("Lasso"),
LASSO_PARAM_ERROR_CHECK_FAILED,
lasso_strerror(LASSO_PARAM_ERROR_CHECK_FAILED));
g_return_val_if_fail (err == NULL || *err == NULL, NULL);
}
provider = lasso_server_get_provider_ref(server, providerID, &tmp_err);
if (provider != NULL) {
return lasso_provider_copy(provider);
}
else {
g_propagate_error (err, tmp_err);
}
return NULL;
}
LassoProvider*
lasso_server_get_provider_ref(LassoServer *server,
gchar *providerID,
GError **err)
{
LassoProvider *provider;
xmlChar *id;
int index, len;
if (err != NULL && *err != NULL) {
g_set_error(err, g_quark_from_string("Lasso"),
LASSO_PARAM_ERROR_CHECK_FAILED,
lasso_strerror(LASSO_PARAM_ERROR_CHECK_FAILED));
g_return_val_if_fail (err == NULL || *err == NULL, NULL);
}
if (LASSO_IS_SERVER(server) == FALSE) {
g_set_error(err, g_quark_from_string("Lasso"),
LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ,
lasso_strerror(LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ));
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
}
if (providerID == NULL) {
g_set_error(err, g_quark_from_string("Lasso"),
LASSO_PARAM_ERROR_INVALID_VALUE,
lasso_strerror(LASSO_PARAM_ERROR_INVALID_VALUE));
g_return_val_if_fail(providerID != NULL, NULL);
}
len = server->providers->len;
for (index = 0; index<len; index++) {
provider = g_ptr_array_index(server->providers, index);
id = lasso_provider_get_providerID(provider);
if (id != NULL) {
if (xmlStrEqual(providerID, id)) {
xmlFree(id);
return(provider);
}
xmlFree(id);
}
}
/* no provider was found */
g_set_error(err, g_quark_from_string("Lasso"),
LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND,
lasso_strerror(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND),
providerID);
/* print error msg here so that caller just check err->code */
message(G_LOG_LEVEL_CRITICAL, err[0]->message);
return NULL;
}
gchar *
lasso_server_get_providerID_from_hash(LassoServer *server,
gchar *b64_hash)
{
LassoProvider *provider;
xmlChar *providerID, *hash_providerID;
xmlChar *b64_hash_providerID;
int i;
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
g_return_val_if_fail(b64_hash != NULL, NULL);
for (i=0; i<server->providers->len; i++) {
provider = g_ptr_array_index(server->providers, i);
providerID = lasso_provider_get_providerID(provider);
if (providerID != NULL) {
hash_providerID = lasso_sha1(providerID);
b64_hash_providerID = xmlSecBase64Encode(hash_providerID, 20, 0);
xmlFree(hash_providerID);
if (xmlStrEqual(b64_hash_providerID, b64_hash)) {
xmlFree(b64_hash_providerID);
return(providerID);
}
else {
xmlFree(b64_hash_providerID);
xmlFree(providerID);
}
}
}
/* failed to get the providerID */
message(G_LOG_LEVEL_CRITICAL,
"Failed to get a providerID corresponding to the hash.\n")
return NULL;
}
/*****************************************************************************/
/* overrided parent class methods */
/*****************************************************************************/
static void
lasso_server_dispose(LassoServer *server)
{
guint i;
if (server->private->dispose_has_run == TRUE) {
return;
}
server->private->dispose_has_run = TRUE;
debug("Server object 0x%x disposed ...\n", server);
/* free allocated memory for providers array */
for (i=0; i<server->providers->len; i++) {
lasso_provider_destroy(server->providers->pdata[i]);
}
g_ptr_array_free(server->providers, TRUE);
parent_class->dispose(G_OBJECT(server));
}
static void
lasso_server_finalize(LassoServer *server)
{
debug("Server object 0x%x finalized ...\n", server);
g_free(server->providerID);
g_free(server->private_key);
g_free(server->certificate);
g_free(server->private);
parent_class->finalize(G_OBJECT(server));
}
/*****************************************************************************/
/* instance and class init functions */
/*****************************************************************************/
static void
lasso_server_instance_init(LassoServer *server)
{
server->private = g_new (LassoServerPrivate, 1);
server->private->dispose_has_run = FALSE;
server->providers = g_ptr_array_new();
server->providerID = NULL;
server->private_key = NULL;
server->certificate = NULL;
server->signature_method = lassoSignatureMethodRsaSha1;
}
static void
lasso_server_class_init(LassoServerClass *class) {
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
parent_class = g_type_class_peek_parent(class);
/* override parent class methods */
gobject_class->dispose = (void *)lasso_server_dispose;
gobject_class->finalize = (void *)lasso_server_finalize;
}
GType lasso_server_get_type() {
static GType this_type = 0;
if (!this_type) {
static const GTypeInfo this_info = {
sizeof (LassoServerClass),
NULL,
NULL,
(GClassInitFunc) lasso_server_class_init,
NULL,
NULL,
sizeof(LassoServer),
0,
(GInstanceInitFunc) lasso_server_instance_init,
};
this_type = g_type_register_static(LASSO_TYPE_PROVIDER,
"LassoServer",
&this_info, 0);
}
return this_type;
}
LassoServer *
lasso_server_new(gchar *metadata,
gchar *public_key,
gchar *private_key,
gchar *certificate,
lassoSignatureMethod signature_method)
{
LassoServer *server;
xmlDocPtr doc;
xmlNodePtr root;
LassoNode *md_node = NULL;
gchar *providerID = NULL;
GError *err = NULL;
/* metadata can be NULL (if server is a LECP) */
/* put server metadata in a LassoNode */
if (metadata) {
doc = xmlParseFile(metadata);
root = xmlCopyNode(xmlDocGetRootElement(doc), 1);
xmlFreeDoc(doc);
md_node = lasso_node_new();
LASSO_NODE_GET_CLASS(md_node)->set_xmlNode(md_node, root);
/* get ProviderID in metadata */
providerID = lasso_node_get_attr_value(md_node, "providerID", &err);
if (providerID == NULL) {
message(G_LOG_LEVEL_WARNING, err->message);
g_error_free(err);
lasso_node_destroy(md_node);
return NULL;
}
}
/* Ok, we can create server */
server = LASSO_SERVER(g_object_new(LASSO_TYPE_SERVER, NULL));
if (md_node != NULL) {
LASSO_PROVIDER(server)->metadata = md_node;
}
if (providerID != NULL) {
server->providerID = providerID;
}
server->private_key = g_strdup(private_key);
server->certificate = g_strdup(certificate);
server->signature_method = signature_method;
LASSO_PROVIDER(server)->public_key = g_strdup(public_key);
LASSO_PROVIDER(server)->ca_certificate = NULL;
return server;
}
LassoServer *
lasso_server_new_from_dump(gchar *dump)
{
LassoNodeClass *server_class, *providers_class;
LassoNode *server_node, *providers_node, *provider_node, *entity_node, *server_metadata_node;
LassoServer *server;
LassoProvider *provider;
xmlNodePtr providers_xmlNode, provider_xmlNode;
xmlChar *public_key, *ca_certificate, *signature_method;
server = LASSO_SERVER(g_object_new(LASSO_TYPE_SERVER, NULL));
server_node = lasso_node_new_from_dump(dump);
if (server_node == NULL) {
message(G_LOG_LEVEL_WARNING, "Error while loading server dump\n");
return NULL;
}
server_class = LASSO_NODE_GET_CLASS(server_node);
if (strcmp(server_class->get_name(server_node), LASSO_SERVER_NODE) != 0) {
message(G_LOG_LEVEL_WARNING, "XML is not a server dump\n");
lasso_node_destroy(server_node);
return NULL;
}
/* providerID */
server->providerID = lasso_node_get_attr_value(server_node, LASSO_SERVER_PROVIDERID_NODE, NULL);
/* private key */
server->private_key = lasso_node_get_attr_value(server_node, LASSO_SERVER_PRIVATE_KEY_NODE, NULL);
/* certificate */
server->certificate = lasso_node_get_attr_value(server_node, LASSO_SERVER_CERTIFICATE_NODE, NULL);
/* signature method */
signature_method = lasso_node_get_attr_value(server_node, LASSO_SERVER_SIGNATURE_METHOD_NODE, NULL);
if (signature_method != NULL) {
server->signature_method = atoi(signature_method);
xmlFree(signature_method);
}
/* metadata */
server_metadata_node = lasso_node_get_child(server_node, LASSO_SERVER_METADATA_NODE, NULL, NULL);
if (server_metadata_node != NULL) {
entity_node = lasso_node_get_child(server_metadata_node, "EntityDescriptor", NULL, NULL);
LASSO_PROVIDER(server)->metadata = lasso_node_copy(entity_node);
lasso_node_destroy(entity_node);
}
/* public key */
LASSO_PROVIDER(server)->public_key = lasso_node_get_attr_value(server_node, LASSO_PROVIDER_PUBLIC_KEY_NODE, NULL);
/* ca_certificate */
LASSO_PROVIDER(server)->ca_certificate = lasso_node_get_attr_value(server_node, LASSO_PROVIDER_CA_CERTIFICATE_NODE, NULL);
/* providers */
providers_node = lasso_node_get_child(server_node, LASSO_SERVER_PROVIDERS_NODE, lassoLassoHRef, NULL);
if (providers_node != NULL) {
providers_class = LASSO_NODE_GET_CLASS(providers_node);
providers_xmlNode = providers_class->get_xmlNode(providers_node);
provider_xmlNode = providers_xmlNode->children;
while (provider_xmlNode != NULL) {
if (provider_xmlNode->type == XML_ELEMENT_NODE && \
xmlStrEqual(provider_xmlNode->name, LASSO_PROVIDER_NODE)) {
/* provider node */
provider_node = lasso_node_new_from_xmlNode(provider_xmlNode);
/* metadata */
entity_node = lasso_node_get_child(provider_node, "EntityDescriptor", NULL, NULL);
/* public key */
public_key = lasso_node_get_attr_value(provider_node, LASSO_PROVIDER_PUBLIC_KEY_NODE, NULL);
/* ca certificate */
ca_certificate = lasso_node_get_attr_value(provider_node, LASSO_PROVIDER_CA_CERTIFICATE_NODE, NULL);
/* add provider */
provider = lasso_provider_new_from_metadata_node(entity_node);
lasso_node_destroy(entity_node);
if (public_key != NULL) {
lasso_provider_set_public_key(provider, public_key);
xmlFree(public_key);
}
if (ca_certificate != NULL) {
lasso_provider_set_ca_certificate(provider, ca_certificate);
xmlFree(ca_certificate);
}
lasso_server_add_lasso_provider(server, provider);
lasso_node_destroy(provider_node);
}
provider_xmlNode = provider_xmlNode->next;
}
lasso_node_destroy(providers_node);
}
lasso_node_destroy(server_node);
return server;
}