merged the modularization branch (credentials) back to trunk
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-aes.la
|
||||
|
||||
libstrongswan_aes_la_SOURCES = aes_plugin.h aes_plugin.c aes_crypter.c aes_crypter.h
|
||||
libstrongswan_aes_la_LDFLAGS = -module
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup aes_crypter aes_crypter
|
||||
* @{ @ingroup aes_p
|
||||
*/
|
||||
|
||||
#ifndef AES_CRYPTER_H_
|
||||
#define AES_CRYPTER_H_
|
||||
|
||||
typedef struct aes_crypter_t aes_crypter_t;
|
||||
|
||||
#include <crypto/crypters/crypter.h>
|
||||
|
||||
/**
|
||||
* Class implementing the AES encryption algorithm.
|
||||
*/
|
||||
struct aes_crypter_t {
|
||||
|
||||
/**
|
||||
* The crypter_t interface.
|
||||
*/
|
||||
crypter_t crypter_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor to create aes_crypter_t objects.
|
||||
*
|
||||
* @param key_size key size in bytes
|
||||
* @param algo algorithm to implement
|
||||
* @return aes_crypter_t object, NULL if not supported
|
||||
*/
|
||||
aes_crypter_t *aes_crypter_create(encryption_algorithm_t algo,
|
||||
size_t key_size);
|
||||
|
||||
#endif /* AES_CRYPTER_H_ @}*/
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "aes_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "aes_crypter.h"
|
||||
|
||||
typedef struct private_aes_plugin_t private_aes_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of aes_plugin
|
||||
*/
|
||||
struct private_aes_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
aes_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of aes_plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_aes_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_crypter(lib->crypto,
|
||||
(crypter_constructor_t)aes_crypter_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_aes_plugin_t *this = malloc_thing(private_aes_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_crypter(lib->crypto, ENCR_AES_CBC,
|
||||
(crypter_constructor_t)aes_crypter_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup aes_p aes
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup aes_plugin aes_plugin
|
||||
* @{ @ingroup aes_p
|
||||
*/
|
||||
|
||||
#ifndef AES_PLUGIN_H_
|
||||
#define AES_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct aes_plugin_t aes_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing AES based algorithms in software.
|
||||
*/
|
||||
struct aes_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a aes_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* AES_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-curl.la
|
||||
|
||||
libstrongswan_curl_la_SOURCES = curl_plugin.h curl_plugin.c curl_fetcher.c curl_fetcher.h
|
||||
libstrongswan_curl_la_LDFLAGS = -module
|
||||
libstrongswan_curl_la_LIBADD = -lcurl
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Copyright (C) 2007 Andreas Steffen
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "curl_fetcher.h"
|
||||
|
||||
#define DEFAULT_TIMEOUT 10
|
||||
|
||||
typedef struct private_curl_fetcher_t private_curl_fetcher_t;
|
||||
|
||||
/**
|
||||
* private data of a curl_fetcher_t object.
|
||||
*/
|
||||
struct private_curl_fetcher_t {
|
||||
/**
|
||||
* Public data
|
||||
*/
|
||||
curl_fetcher_t public;
|
||||
|
||||
/**
|
||||
* CURL handle
|
||||
*/
|
||||
CURL* curl;
|
||||
|
||||
/**
|
||||
* request type, as set with FETCH_REQUEST_TYPE
|
||||
*/
|
||||
char *request_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* writes data into a dynamically resizeable chunk_t
|
||||
*/
|
||||
static size_t append(void *ptr, size_t size, size_t nmemb, chunk_t *data)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
|
||||
data->ptr = (u_char*)realloc(data->ptr, data->len + realsize);
|
||||
if (data->ptr)
|
||||
{
|
||||
memcpy(&data->ptr[data->len], ptr, realsize);
|
||||
data->len += realsize;
|
||||
}
|
||||
return realsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements fetcher_t.fetch.
|
||||
*/
|
||||
static status_t fetch(private_curl_fetcher_t *this, char *uri, chunk_t *result)
|
||||
{
|
||||
struct curl_slist *headers = NULL;
|
||||
char error[CURL_ERROR_SIZE];
|
||||
char buf[256];;
|
||||
status_t status;
|
||||
|
||||
*result = chunk_empty;
|
||||
|
||||
if (curl_easy_setopt(this->curl, CURLOPT_URL, uri) != CURLE_OK)
|
||||
{ /* URL type not supported by curl */
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, error);
|
||||
curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE);
|
||||
curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE);
|
||||
curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, DEFAULT_TIMEOUT);
|
||||
curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, (void*)append);
|
||||
curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void*)result);
|
||||
if (this->request_type)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "Content-Type: %s", this->request_type);
|
||||
headers = curl_slist_append(headers, buf);
|
||||
curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
|
||||
DBG2("sending http request to '%s'...", uri);
|
||||
switch (curl_easy_perform(this->curl))
|
||||
{
|
||||
case CURLE_UNSUPPORTED_PROTOCOL:
|
||||
status = NOT_SUPPORTED;
|
||||
break;
|
||||
case CURLE_OK:
|
||||
status = SUCCESS;
|
||||
break;
|
||||
default:
|
||||
DBG1("libcurl http request failed: %s", error);
|
||||
status = FAILED;
|
||||
break;
|
||||
}
|
||||
curl_slist_free_all(headers);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of fetcher_t.set_option.
|
||||
*/
|
||||
static bool set_option(private_curl_fetcher_t *this, fetcher_option_t option, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, option);
|
||||
switch (option)
|
||||
{
|
||||
case FETCH_REQUEST_DATA:
|
||||
{
|
||||
chunk_t data = va_arg(args, chunk_t);
|
||||
curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, data.ptr);
|
||||
curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, data.len);
|
||||
return TRUE;
|
||||
}
|
||||
case FETCH_REQUEST_TYPE:
|
||||
{
|
||||
this->request_type = va_arg(args, char*);
|
||||
return TRUE;
|
||||
}
|
||||
case FETCH_TIMEOUT:
|
||||
{
|
||||
curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT,
|
||||
va_arg(args, u_int));
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements fetcher_t.destroy
|
||||
*/
|
||||
static void destroy(private_curl_fetcher_t *this)
|
||||
{
|
||||
curl_easy_cleanup(this->curl);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
curl_fetcher_t *curl_fetcher_create()
|
||||
{
|
||||
private_curl_fetcher_t *this = malloc_thing(private_curl_fetcher_t);
|
||||
|
||||
this->curl = curl_easy_init();
|
||||
if (this->curl == NULL)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
this->request_type = NULL;
|
||||
|
||||
this->public.interface.fetch = (status_t(*)(fetcher_t*,char*,chunk_t*))fetch;
|
||||
this->public.interface.set_option = (bool(*)(fetcher_t*, fetcher_option_t option, ...))set_option;
|
||||
this->public.interface.destroy = (void (*)(fetcher_t*))destroy;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup curl_fetcher curl_fetcher
|
||||
* @{ @ingroup curl_p
|
||||
*/
|
||||
|
||||
#ifndef CURL_FETCHER_H_
|
||||
#define CURL_FETCHER_H_
|
||||
|
||||
typedef struct curl_fetcher_t curl_fetcher_t;
|
||||
|
||||
/**
|
||||
* Fetcher implementation using libcurl
|
||||
*/
|
||||
struct curl_fetcher_t {
|
||||
|
||||
/**
|
||||
* Implements fetcher interface
|
||||
*/
|
||||
fetcher_t interface;
|
||||
|
||||
/**
|
||||
* Destroy a curl_fetcher instance.
|
||||
*/
|
||||
void (*destroy)(curl_fetcher_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a curl_fetcher instance.
|
||||
*/
|
||||
curl_fetcher_t *curl_fetcher_create();
|
||||
|
||||
#endif /* CURL_FETCHER_H_ @}*/
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "curl_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include "curl_fetcher.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
typedef struct private_curl_plugin_t private_curl_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of curl_plugin
|
||||
*/
|
||||
struct private_curl_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
curl_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of curl_plugin_t.curltroy
|
||||
*/
|
||||
static void destroy(private_curl_plugin_t *this)
|
||||
{
|
||||
lib->fetcher->remove_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)curl_fetcher_create);
|
||||
curl_global_cleanup();
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
CURLcode res;
|
||||
private_curl_plugin_t *this = malloc_thing(private_curl_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
res = curl_global_init(CURL_GLOBAL_NOTHING);
|
||||
if (res == CURLE_OK)
|
||||
{
|
||||
lib->fetcher->add_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)curl_fetcher_create, "file://");
|
||||
lib->fetcher->add_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)curl_fetcher_create, "http://");
|
||||
lib->fetcher->add_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)curl_fetcher_create, "https://");
|
||||
lib->fetcher->add_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)curl_fetcher_create, "ftp://");
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("global libcurl initializing failed: %s, curl disabled",
|
||||
curl_easy_strerror(res));
|
||||
}
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup curl_p curl
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup curl_plugin curl_plugin
|
||||
* @{ @ingroup curl_p
|
||||
*/
|
||||
|
||||
#ifndef CURL_PLUGIN_H_
|
||||
#define CURL_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct curl_plugin_t curl_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing fetcher interface using libcurl http library.
|
||||
*/
|
||||
struct curl_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a curl_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* CURL_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-des.la
|
||||
|
||||
libstrongswan_des_la_SOURCES = des_plugin.h des_plugin.c des_crypter.c des_crypter.h
|
||||
libstrongswan_des_la_LDFLAGS = -module
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup des_crypter des_crypter
|
||||
* @{ @ingroup des_p
|
||||
*/
|
||||
|
||||
#ifndef DES_CRYPTER_H_
|
||||
#define DES_CRYPTER_H_
|
||||
|
||||
typedef struct des_crypter_t des_crypter_t;
|
||||
|
||||
#include <crypto/crypters/crypter.h>
|
||||
|
||||
|
||||
/**
|
||||
* Class implementing the DES and 3DES encryption algorithms.
|
||||
*/
|
||||
struct des_crypter_t {
|
||||
|
||||
/**
|
||||
* The crypter_t interface.
|
||||
*/
|
||||
crypter_t crypter_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor to create des_crypter_t objects.
|
||||
*
|
||||
* @param algo ENCR_DES for single DES, ENCR_3DES for triple DES
|
||||
* @return des_crypter_t object, NULL if algo not supported
|
||||
*/
|
||||
des_crypter_t *des_crypter_create(encryption_algorithm_t algo);
|
||||
|
||||
|
||||
#endif /* DES_CRYPTER_H_ @}*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "des_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "des_crypter.h"
|
||||
|
||||
typedef struct private_des_plugin_t private_des_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of des_plugin
|
||||
*/
|
||||
struct private_des_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
des_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of des_plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_des_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_crypter(lib->crypto,
|
||||
(crypter_constructor_t)des_crypter_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_des_plugin_t *this = malloc_thing(private_des_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_crypter(lib->crypto, ENCR_DES,
|
||||
(crypter_constructor_t)des_crypter_create);
|
||||
lib->crypto->add_crypter(lib->crypto, ENCR_3DES,
|
||||
(crypter_constructor_t)des_crypter_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup des_p des
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup des_plugin des_plugin
|
||||
* @{ @ingroup des_p
|
||||
*/
|
||||
|
||||
#ifndef DES_PLUGIN_H_
|
||||
#define DES_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct des_plugin_t des_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing DES based algorithms in software.
|
||||
*/
|
||||
struct des_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a des_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* DES_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-fips-prf.la
|
||||
|
||||
libstrongswan_fips_prf_la_SOURCES = fips_prf_plugin.h fips_prf_plugin.c fips_prf.c fips_prf.h
|
||||
libstrongswan_fips_prf_la_LDFLAGS = -module
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "fips_prf.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
typedef struct private_fips_prf_t private_fips_prf_t;
|
||||
|
||||
/**
|
||||
* Private data of a fips_prf_t object.
|
||||
*/
|
||||
struct private_fips_prf_t {
|
||||
/**
|
||||
* Public fips_prf_t interface.
|
||||
*/
|
||||
fips_prf_t public;
|
||||
|
||||
/**
|
||||
* key of prf function, "b" long
|
||||
*/
|
||||
u_int8_t *key;
|
||||
|
||||
/**
|
||||
* size of "b" in bytes
|
||||
*/
|
||||
size_t b;
|
||||
|
||||
/**
|
||||
* associated hasher when using SHA1 mode
|
||||
*/
|
||||
hasher_t *hasher;
|
||||
|
||||
/**
|
||||
* G function, either SHA1 or DES
|
||||
*/
|
||||
void (*g)(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[]);
|
||||
};
|
||||
|
||||
/**
|
||||
* t used in G(), equals to initial SHA1 value
|
||||
*/
|
||||
static u_int8_t t[] = {
|
||||
0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA,
|
||||
0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* sum = (a + b) mod 2 ^ (length * 8)
|
||||
*/
|
||||
static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[])
|
||||
{
|
||||
int i, c = 0;
|
||||
|
||||
for(i = length - 1; i >= 0; i--)
|
||||
{
|
||||
u_int32_t tmp;
|
||||
|
||||
tmp = a[i] + b[i] + c;
|
||||
sum[i] = 0xff & tmp;
|
||||
c = tmp >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate "chunk mod 2^(length*8)" and save it into buffer
|
||||
*/
|
||||
static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[])
|
||||
{
|
||||
if (chunk.len < length)
|
||||
{
|
||||
/* apply seed as least significant bits, others are zero */
|
||||
memset(buffer, 0, length - chunk.len);
|
||||
memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* use least significant bytes from seed, as we use mod 2^b */
|
||||
memcpy(buffer, chunk.ptr + chunk.len - length, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_bytes.
|
||||
*
|
||||
* Test vector:
|
||||
*
|
||||
* key:
|
||||
* 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
|
||||
* 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
|
||||
* 0xeb, 0x5a, 0x38, 0xb6
|
||||
*
|
||||
* seed:
|
||||
* 0x00
|
||||
*
|
||||
* result:
|
||||
* 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
|
||||
* 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
|
||||
* 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
|
||||
* 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
|
||||
* 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
|
||||
*/
|
||||
static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[])
|
||||
{
|
||||
int i;
|
||||
u_int8_t xval[this->b];
|
||||
u_int8_t xseed[this->b];
|
||||
u_int8_t sum[this->b];
|
||||
u_int8_t *xkey = this->key;
|
||||
u_int8_t one[this->b];
|
||||
chunk_t xval_chunk = chunk_from_buf(xval);
|
||||
|
||||
memset(one, 0, this->b);
|
||||
one[this->b - 1] = 0x01;
|
||||
|
||||
/* 3.1 */
|
||||
chunk_mod(this->b, seed, xseed);
|
||||
|
||||
/* 3.2 */
|
||||
for (i = 0; i < 2; i++) /* twice */
|
||||
{
|
||||
/* a. XVAL = (XKEY + XSEED j) mod 2^b */
|
||||
add_mod(this->b, xkey, xseed, xval);
|
||||
DBG3("XVAL %b", xval, this->b);
|
||||
/* b. wi = G(t, XVAL ) */
|
||||
this->g(this, t, xval_chunk, &w[i * this->b]);
|
||||
DBG3("w[%d] %b", i, &w[i * this->b], this->b);
|
||||
/* c. XKEY = (1 + XKEY + wi) mod 2b */
|
||||
add_mod(this->b, xkey, &w[i * this->b], sum);
|
||||
add_mod(this->b, sum, one, xkey);
|
||||
DBG3("XKEY %b", xkey, this->b);
|
||||
}
|
||||
|
||||
/* 3.3 done already, mod q not used */
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_block_size.
|
||||
*/
|
||||
static size_t get_block_size(private_fips_prf_t *this)
|
||||
{
|
||||
return 2 * this->b;
|
||||
}
|
||||
/**
|
||||
* Implementation of prf_t.allocate_bytes.
|
||||
*/
|
||||
static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk)
|
||||
{
|
||||
*chunk = chunk_alloc(get_block_size(this));
|
||||
get_bytes(this, seed, chunk->ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_key_size.
|
||||
*/
|
||||
static size_t get_key_size(private_fips_prf_t *this)
|
||||
{
|
||||
return this->b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.set_key.
|
||||
*/
|
||||
static void set_key(private_fips_prf_t *this, chunk_t key)
|
||||
{
|
||||
/* save key as "key mod 2^b" */
|
||||
chunk_mod(this->b, key, this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the G() function based on SHA1
|
||||
*/
|
||||
void g_sha1(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[])
|
||||
{
|
||||
u_int8_t buf[64];
|
||||
|
||||
if (c.len < sizeof(buf))
|
||||
{
|
||||
/* pad c with zeros */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, c.ptr, c.len);
|
||||
c.ptr = buf;
|
||||
c.len = sizeof(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not more than 512 bits can be G()-ed */
|
||||
c.len = sizeof(buf);
|
||||
}
|
||||
|
||||
/* calculate the special (HASH_SHA1_STATE) hash*/
|
||||
this->hasher->get_hash(this->hasher, c, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.destroy.
|
||||
*/
|
||||
static void destroy(private_fips_prf_t *this)
|
||||
{
|
||||
this->hasher->destroy(this->hasher);
|
||||
free(this->key);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
fips_prf_t *fips_prf_create(pseudo_random_function_t algo)
|
||||
{
|
||||
private_fips_prf_t *this = malloc_thing(private_fips_prf_t);
|
||||
|
||||
this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
|
||||
this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
|
||||
this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
|
||||
this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
|
||||
this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
|
||||
this->public.prf_interface.destroy = (void (*) (prf_t *))destroy;
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case PRF_FIPS_SHA1_160:
|
||||
{
|
||||
this->g = g_sha1;
|
||||
this->b = 20;
|
||||
this->hasher = lib->crypto->create_hasher(lib->crypto,
|
||||
HASH_SHA1_NOFINAL);
|
||||
if (this->hasher == NULL)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRF_FIPS_DES:
|
||||
/* not implemented yet */
|
||||
default:
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
this->key = malloc(this->b);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup fips_prf fips_prf
|
||||
* @{ @ingroup fips_prf_p
|
||||
*/
|
||||
|
||||
#ifndef FIPS_PRF_H_
|
||||
#define FIPS_PRF_H_
|
||||
|
||||
typedef struct fips_prf_t fips_prf_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <crypto/prfs/prf.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* Implementation of prf_t using the FIPS 186-2-change1 standard.
|
||||
*
|
||||
* FIPS defines a "General Purpose Random Number Generator" (Revised
|
||||
* Algorithm for Computing m values of x (Appendix 3.1 of FIPS 186-2)). This
|
||||
* implementation is not intended for private key generation and therefore does
|
||||
* not include the "mod q" operation (see FIPS 186-2-change1 p74).
|
||||
* The FIPS PRF is stateful; the key changes every time when bytes are acquired.
|
||||
*/
|
||||
struct fips_prf_t {
|
||||
|
||||
/**
|
||||
* Generic prf_t interface for this fips_prf_t class.
|
||||
*/
|
||||
prf_t prf_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new fips_prf_t object.
|
||||
*
|
||||
* FIPS 186-2 defines G() functions used in the PRF function. It can
|
||||
* be implemented either based on SHA1 or DES.
|
||||
* The G() function is selected using the algo parameter.
|
||||
*
|
||||
* @param algo specific FIPS PRF implementation, specifies G() function
|
||||
* @return fips_prf_t object, NULL if not supported.
|
||||
*/
|
||||
fips_prf_t *fips_prf_create(pseudo_random_function_t algo);
|
||||
|
||||
#endif /* FIPS_PRF_H_ @}*/
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "fips_prf_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "fips_prf.h"
|
||||
|
||||
typedef struct private_fips_prf_plugin_t private_fips_prf_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of fips_prf_plugin
|
||||
*/
|
||||
struct private_fips_prf_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
fips_prf_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of fips_prf_plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_fips_prf_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_prf(lib->crypto,
|
||||
(prf_constructor_t)fips_prf_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_fips_prf_plugin_t *this = malloc_thing(private_fips_prf_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_prf(lib->crypto, PRF_FIPS_SHA1_160,
|
||||
(prf_constructor_t)fips_prf_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup fips_prf_p fips_prf
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup fips_prf_plugin fips_prf_plugin
|
||||
* @{ @ingroup fips_prf_p
|
||||
*/
|
||||
|
||||
#ifndef FIPS_PRF_PLUGIN_H_
|
||||
#define FIPS_PRF_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct fips_prf_plugin_t fips_prf_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing the fips_prf algorithm in software.
|
||||
*/
|
||||
struct fips_prf_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a fips_prf_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* FIPS_PRF_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-gmp.la
|
||||
|
||||
libstrongswan_gmp_la_SOURCES = gmp_plugin.h gmp_plugin.c \
|
||||
gmp_diffie_hellman.c gmp_diffie_hellman.h \
|
||||
gmp_rsa_private_key.c gmp_rsa_private_key.h \
|
||||
gmp_rsa_public_key.c gmp_rsa_public_key.h
|
||||
libstrongswan_gmp_la_LDFLAGS = -module
|
||||
libstrongswan_gmp_la_LIBADD = -lgmp
|
||||
|
||||
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
|
||||
* Copyright (C) 1999, 2000, 2001 Henry Spencer.
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <gmp.h>
|
||||
|
||||
#include "gmp_diffie_hellman.h"
|
||||
|
||||
#include <utils/randomizer.h>
|
||||
#include <debug.h>
|
||||
|
||||
|
||||
/**
|
||||
* Modulus of Group 1 (MODP_768_BIT).
|
||||
*/
|
||||
static u_int8_t group1_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* Modulus of Group 2 (MODP_1024_BIT).
|
||||
*/
|
||||
static u_int8_t group2_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
|
||||
0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* Modulus of Group 5 (MODP_1536_BIT).
|
||||
*/
|
||||
static u_int8_t group5_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
|
||||
0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
|
||||
0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
||||
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
|
||||
0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
|
||||
0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
/**
|
||||
* Modulus of Group 14 (MODP_2048_BIT).
|
||||
*/
|
||||
static u_int8_t group14_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
|
||||
0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
|
||||
0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
||||
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
|
||||
0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
|
||||
0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
|
||||
0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
|
||||
0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
|
||||
0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
|
||||
0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* Modulus of Group 15 (MODP_3072_BIT).
|
||||
*/
|
||||
static u_int8_t group15_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
|
||||
0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
|
||||
0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
||||
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
|
||||
0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
|
||||
0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
|
||||
0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
|
||||
0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
|
||||
0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
|
||||
0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
|
||||
0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
|
||||
0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
|
||||
0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
|
||||
0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
|
||||
0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
|
||||
0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
|
||||
0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
|
||||
0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* Modulus of Group 16 (MODP_4096_BIT).
|
||||
*/
|
||||
static u_int8_t group16_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
|
||||
0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
|
||||
0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
||||
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
|
||||
0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
|
||||
0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
|
||||
0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
|
||||
0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
|
||||
0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
|
||||
0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
|
||||
0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
|
||||
0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
|
||||
0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
|
||||
0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
|
||||
0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
|
||||
0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
|
||||
0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
|
||||
0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
|
||||
0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C,
|
||||
0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,
|
||||
0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
|
||||
0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2,
|
||||
0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,
|
||||
0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
|
||||
0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F,
|
||||
0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* Modulus of Group 17 (MODP_6144_BIT).
|
||||
*/
|
||||
static u_int8_t group17_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
|
||||
0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
|
||||
0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
||||
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
|
||||
0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
|
||||
0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
|
||||
0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
|
||||
0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
|
||||
0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
|
||||
0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
|
||||
0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
|
||||
0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
|
||||
0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
|
||||
0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
|
||||
0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
|
||||
0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
|
||||
0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
|
||||
0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
|
||||
0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C,
|
||||
0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,
|
||||
0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
|
||||
0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2,
|
||||
0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,
|
||||
0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
|
||||
0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F,
|
||||
0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,
|
||||
0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,
|
||||
0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE,
|
||||
0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,
|
||||
0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,
|
||||
0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42,
|
||||
0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,
|
||||
0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,
|
||||
0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E,
|
||||
0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,
|
||||
0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,
|
||||
0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0,
|
||||
0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,
|
||||
0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
|
||||
0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68,
|
||||
0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,
|
||||
0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* Modulus of Group 18 (MODP_8192_BIT).
|
||||
*/
|
||||
static u_int8_t group18_modulus[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34,
|
||||
0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,
|
||||
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
|
||||
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
|
||||
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
|
||||
0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,
|
||||
0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
||||
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
|
||||
0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
|
||||
0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
|
||||
0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
|
||||
0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
|
||||
0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
|
||||
0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33,
|
||||
0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,
|
||||
0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
|
||||
0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D,
|
||||
0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,
|
||||
0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
|
||||
0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
|
||||
0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
|
||||
0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
|
||||
0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C,
|
||||
0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,
|
||||
0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
|
||||
0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2,
|
||||
0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,
|
||||
0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
|
||||
0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F,
|
||||
0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,
|
||||
0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,
|
||||
0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE,
|
||||
0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,
|
||||
0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,
|
||||
0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42,
|
||||
0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,
|
||||
0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,
|
||||
0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E,
|
||||
0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,
|
||||
0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,
|
||||
0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0,
|
||||
0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,
|
||||
0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
|
||||
0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68,
|
||||
0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,
|
||||
0xE6,0x94,0xF9,0x1E,0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4,
|
||||
0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,0x73,0xB9,0x31,0xBA,
|
||||
0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED,
|
||||
0x25,0x76,0xF6,0x93,0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68,
|
||||
0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,0xE3,0x9D,0x65,0x2D,
|
||||
0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07,
|
||||
0x13,0xEB,0x57,0xA8,0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B,
|
||||
0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,0xA2,0xC0,0x87,0xE8,
|
||||
0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6,
|
||||
0x6D,0x2A,0x13,0xF8,0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36,
|
||||
0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,0x08,0x46,0x85,0x1D,
|
||||
0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73,
|
||||
0xFA,0xF3,0x6B,0xC3,0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92,
|
||||
0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,0xD5,0xEE,0x38,0x2B,
|
||||
0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA,
|
||||
0x9E,0x30,0x50,0xE2,0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71,
|
||||
0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
};
|
||||
|
||||
typedef struct modulus_entry_t modulus_entry_t;
|
||||
|
||||
/**
|
||||
* Entry of the modulus list.
|
||||
*/
|
||||
struct modulus_entry_t {
|
||||
/**
|
||||
* Group number as it is defined in file transform_substructure.h.
|
||||
*/
|
||||
diffie_hellman_group_t group;
|
||||
|
||||
/**
|
||||
* Pointer to first byte of modulus (network order).
|
||||
*/
|
||||
u_int8_t *modulus;
|
||||
|
||||
/*
|
||||
* Length of modulus in bytes.
|
||||
*/
|
||||
size_t modulus_len;
|
||||
|
||||
/*
|
||||
* Generator value.
|
||||
*/
|
||||
u_int16_t generator;
|
||||
};
|
||||
|
||||
/**
|
||||
* All supported modulus values.
|
||||
*/
|
||||
static modulus_entry_t modulus_entries[] = {
|
||||
{MODP_768_BIT, group1_modulus, sizeof(group1_modulus), 2},
|
||||
{MODP_1024_BIT, group2_modulus, sizeof(group2_modulus), 2},
|
||||
{MODP_1536_BIT, group5_modulus, sizeof(group5_modulus), 2},
|
||||
{MODP_2048_BIT, group14_modulus, sizeof(group14_modulus), 2},
|
||||
{MODP_3072_BIT, group15_modulus, sizeof(group15_modulus), 2},
|
||||
{MODP_4096_BIT, group16_modulus, sizeof(group16_modulus), 2},
|
||||
{MODP_6144_BIT, group17_modulus, sizeof(group17_modulus), 2},
|
||||
{MODP_8192_BIT, group18_modulus, sizeof(group18_modulus), 2},
|
||||
};
|
||||
|
||||
typedef struct private_gmp_diffie_hellman_t private_gmp_diffie_hellman_t;
|
||||
|
||||
/**
|
||||
* Private data of an gmp_diffie_hellman_t object.
|
||||
*/
|
||||
struct private_gmp_diffie_hellman_t {
|
||||
/**
|
||||
* Public gmp_diffie_hellman_t interface.
|
||||
*/
|
||||
gmp_diffie_hellman_t public;
|
||||
|
||||
/**
|
||||
* Diffie Hellman group number.
|
||||
*/
|
||||
u_int16_t group;
|
||||
|
||||
/*
|
||||
* Generator value.
|
||||
*/
|
||||
mpz_t g;
|
||||
|
||||
/**
|
||||
* My private value.
|
||||
*/
|
||||
mpz_t xa;
|
||||
|
||||
/**
|
||||
* My public value.
|
||||
*/
|
||||
mpz_t ya;
|
||||
|
||||
/**
|
||||
* Other public value.
|
||||
*/
|
||||
mpz_t yb;
|
||||
|
||||
/**
|
||||
* Shared secret.
|
||||
*/
|
||||
mpz_t zz;
|
||||
|
||||
/**
|
||||
* Modulus.
|
||||
*/
|
||||
mpz_t p;
|
||||
|
||||
/**
|
||||
* Modulus length.
|
||||
*/
|
||||
size_t p_len;
|
||||
|
||||
/**
|
||||
* True if shared secret is computed and stored in my_public_value.
|
||||
*/
|
||||
bool computed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of gmp_diffie_hellman_t.set_other_public_value.
|
||||
*/
|
||||
static void set_other_public_value(private_gmp_diffie_hellman_t *this, chunk_t value)
|
||||
{
|
||||
mpz_t p_min_1;
|
||||
|
||||
mpz_init(p_min_1);
|
||||
mpz_sub_ui(p_min_1, this->p, 1);
|
||||
|
||||
mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr);
|
||||
|
||||
/* check public value:
|
||||
* 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1
|
||||
* 2. a public value larger or equal the modulus is invalid */
|
||||
if (mpz_cmp_ui(this->yb, 1) > 0 ||
|
||||
mpz_cmp(this->yb, p_min_1) < 0)
|
||||
{
|
||||
#ifdef EXTENDED_DH_TEST
|
||||
/* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */
|
||||
mpz_t q, one;
|
||||
|
||||
mpz_init(q);
|
||||
mpz_init(one);
|
||||
mpz_fdiv_q_2exp(q, p_min_1, 1);
|
||||
mpz_powm(one, this->yb, q, this->p);
|
||||
mpz_clear(q);
|
||||
if (mpz_cmp_ui(one, 1) == 0)
|
||||
{
|
||||
mpz_powm(this->zz, this->yb, this->xa, this->p);
|
||||
this->computed = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("public DH value verification failed: y ^ q mod p != 1");
|
||||
}
|
||||
mpz_clear(one);
|
||||
#else
|
||||
mpz_powm(this->zz, this->yb, this->xa, this->p);
|
||||
this->computed = TRUE;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("public DH value verification failed: y < 2 || y > p - 1 ");
|
||||
}
|
||||
mpz_clear(p_min_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_diffie_hellman_t.get_other_public_value.
|
||||
*/
|
||||
static status_t get_other_public_value(private_gmp_diffie_hellman_t *this,
|
||||
chunk_t *value)
|
||||
{
|
||||
if (!this->computed)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
value->len = this->p_len;
|
||||
value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->yb);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_diffie_hellman_t.get_my_public_value.
|
||||
*/
|
||||
static void get_my_public_value(private_gmp_diffie_hellman_t *this,chunk_t *value)
|
||||
{
|
||||
value->len = this->p_len;
|
||||
value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_diffie_hellman_t.get_shared_secret.
|
||||
*/
|
||||
static status_t get_shared_secret(private_gmp_diffie_hellman_t *this, chunk_t *secret)
|
||||
{
|
||||
if (!this->computed)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
secret->len = this->p_len;
|
||||
secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_diffie_hellman_t.get_dh_group.
|
||||
*/
|
||||
static diffie_hellman_group_t get_dh_group(private_gmp_diffie_hellman_t *this)
|
||||
{
|
||||
return this->group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the modulus in modulo table
|
||||
*/
|
||||
static status_t set_modulus(private_gmp_diffie_hellman_t *this)
|
||||
{
|
||||
int i;
|
||||
status_t status = NOT_FOUND;
|
||||
|
||||
for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++)
|
||||
{
|
||||
if (modulus_entries[i].group == this->group)
|
||||
{
|
||||
chunk_t chunk;
|
||||
chunk.ptr = modulus_entries[i].modulus;
|
||||
chunk.len = modulus_entries[i].modulus_len;
|
||||
mpz_import(this->p, chunk.len, 1, 1, 1, 0, chunk.ptr);
|
||||
this->p_len = chunk.len;
|
||||
mpz_set_ui(this->g, modulus_entries[i].generator);
|
||||
status = SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_diffie_hellman_t.destroy.
|
||||
*/
|
||||
static void destroy(private_gmp_diffie_hellman_t *this)
|
||||
{
|
||||
mpz_clear(this->p);
|
||||
mpz_clear(this->xa);
|
||||
mpz_clear(this->ya);
|
||||
mpz_clear(this->yb);
|
||||
mpz_clear(this->zz);
|
||||
mpz_clear(this->g);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group)
|
||||
{
|
||||
private_gmp_diffie_hellman_t *this = malloc_thing(private_gmp_diffie_hellman_t);
|
||||
randomizer_t *randomizer;
|
||||
chunk_t random;
|
||||
status_t status;
|
||||
|
||||
/* public functions */
|
||||
this->public.dh.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret;
|
||||
this->public.dh.set_other_public_value = (void (*)(diffie_hellman_t *, chunk_t )) set_other_public_value;
|
||||
this->public.dh.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value;
|
||||
this->public.dh.get_my_public_value = (void (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value;
|
||||
this->public.dh.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group;
|
||||
this->public.dh.destroy = (void (*)(diffie_hellman_t *)) destroy;
|
||||
|
||||
/* private variables */
|
||||
this->group = group;
|
||||
mpz_init(this->p);
|
||||
mpz_init(this->yb);
|
||||
mpz_init(this->ya);
|
||||
mpz_init(this->xa);
|
||||
mpz_init(this->zz);
|
||||
mpz_init(this->g);
|
||||
|
||||
this->computed = FALSE;
|
||||
|
||||
/* find a modulus according to group */
|
||||
if (set_modulus(this) != SUCCESS)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
randomizer = randomizer_create();
|
||||
status = randomizer->allocate_pseudo_random_bytes(
|
||||
randomizer, this->p_len, &random);
|
||||
randomizer->destroy(randomizer);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr);
|
||||
chunk_free(&random);
|
||||
|
||||
mpz_powm(this->ya, this->g, this->xa, this->p);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup gmp_diffie_hellman gmp_diffie_hellman
|
||||
* @{ @ingroup gmp_p
|
||||
*/
|
||||
|
||||
#ifndef GMP_DIFFIE_HELLMAN_H_
|
||||
#define GMP_DIFFIE_HELLMAN_H_
|
||||
|
||||
typedef struct gmp_diffie_hellman_t gmp_diffie_hellman_t;
|
||||
|
||||
#include <library.h>
|
||||
|
||||
/**
|
||||
* Implementation of the Diffie-Hellman algorithm, as in RFC2631. Uses libgmp.
|
||||
*/
|
||||
struct gmp_diffie_hellman_t {
|
||||
|
||||
/**
|
||||
* Implements diffie_hellman_t interface.
|
||||
*/
|
||||
diffie_hellman_t dh;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new gmp_diffie_hellman_t object.
|
||||
*
|
||||
* @param group Diffie Hellman group number to use
|
||||
* @return gmp_diffie_hellman_t object, NULL if not supported
|
||||
*/
|
||||
gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group);
|
||||
|
||||
#endif /*GMP_DIFFIE_HELLMAN_H_ @}*/
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "gmp_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "gmp_diffie_hellman.h"
|
||||
#include "gmp_rsa_private_key.h"
|
||||
#include "gmp_rsa_public_key.h"
|
||||
|
||||
typedef struct private_gmp_plugin_t private_gmp_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of gmp_plugin
|
||||
*/
|
||||
struct private_gmp_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
gmp_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of gmp_plugin_t.gmptroy
|
||||
*/
|
||||
static void destroy(private_gmp_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_dh(lib->crypto,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->creds->remove_builder(lib->creds,
|
||||
(builder_constructor_t)gmp_rsa_private_key_builder);
|
||||
lib->creds->remove_builder(lib->creds,
|
||||
(builder_constructor_t)gmp_rsa_public_key_builder);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_gmp_plugin_t *this = malloc_thing(private_gmp_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_dh(lib->crypto, MODP_768_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->crypto->add_dh(lib->crypto, MODP_1024_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->crypto->add_dh(lib->crypto, MODP_1536_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->crypto->add_dh(lib->crypto, MODP_2048_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->crypto->add_dh(lib->crypto, MODP_3072_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->crypto->add_dh(lib->crypto, MODP_4096_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->crypto->add_dh(lib->crypto, MODP_6144_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
lib->crypto->add_dh(lib->crypto, MODP_8192_BIT,
|
||||
(dh_constructor_t)gmp_diffie_hellman_create);
|
||||
|
||||
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||
(builder_constructor_t)gmp_rsa_private_key_builder);
|
||||
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
|
||||
(builder_constructor_t)gmp_rsa_public_key_builder);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup gmp_p gmp
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup gmp_plugin gmp_plugin
|
||||
* @{ @ingroup gmp_p
|
||||
*/
|
||||
|
||||
#ifndef GMP_PLUGIN_H_
|
||||
#define GMP_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct gmp_plugin_t gmp_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing asymmetric crypto algorithms using the GNU MP library.
|
||||
*/
|
||||
struct gmp_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a gmp_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* GMP_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <gmp.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gmp_rsa_private_key.h"
|
||||
#include "gmp_rsa_public_key.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <utils/randomizer.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* Public exponent to use for key generation.
|
||||
*/
|
||||
#define PUBLIC_EXPONENT 0x10001
|
||||
|
||||
typedef struct private_gmp_rsa_private_key_t private_gmp_rsa_private_key_t;
|
||||
|
||||
/**
|
||||
* Private data of a gmp_rsa_private_key_t object.
|
||||
*/
|
||||
struct private_gmp_rsa_private_key_t {
|
||||
/**
|
||||
* Public interface for this signer.
|
||||
*/
|
||||
gmp_rsa_private_key_t public;
|
||||
|
||||
/**
|
||||
* Version of key, as encoded in PKCS#1
|
||||
*/
|
||||
u_int version;
|
||||
|
||||
/**
|
||||
* Public modulus.
|
||||
*/
|
||||
mpz_t n;
|
||||
|
||||
/**
|
||||
* Public exponent.
|
||||
*/
|
||||
mpz_t e;
|
||||
|
||||
/**
|
||||
* Private prime 1.
|
||||
*/
|
||||
mpz_t p;
|
||||
|
||||
/**
|
||||
* Private Prime 2.
|
||||
*/
|
||||
mpz_t q;
|
||||
|
||||
/**
|
||||
* Private exponent.
|
||||
*/
|
||||
mpz_t d;
|
||||
|
||||
/**
|
||||
* Private exponent 1.
|
||||
*/
|
||||
mpz_t exp1;
|
||||
|
||||
/**
|
||||
* Private exponent 2.
|
||||
*/
|
||||
mpz_t exp2;
|
||||
|
||||
/**
|
||||
* Private coefficient.
|
||||
*/
|
||||
mpz_t coeff;
|
||||
|
||||
/**
|
||||
* Keysize in bytes.
|
||||
*/
|
||||
size_t k;
|
||||
|
||||
/**
|
||||
* Keyid formed as a SHA-1 hash of a publicKey object
|
||||
*/
|
||||
identification_t* keyid;
|
||||
|
||||
/**
|
||||
* Keyid formed as a SHA-1 hash of a publicKeyInfo object
|
||||
*/
|
||||
identification_t* keyid_info;
|
||||
|
||||
/**
|
||||
* reference count
|
||||
*/
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
/* ASN.1 definition of a PKCS#1 RSA private key */
|
||||
static const asn1Object_t privkey_objects[] = {
|
||||
{ 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
|
||||
{ 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
|
||||
{ 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */
|
||||
{ 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */
|
||||
{ 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */
|
||||
{ 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */
|
||||
{ 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */
|
||||
{ 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */
|
||||
{ 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */
|
||||
{ 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 10 */
|
||||
{ 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
|
||||
{ 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */
|
||||
{ 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */
|
||||
{ 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */
|
||||
{ 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */
|
||||
};
|
||||
|
||||
#define PRIV_KEY_VERSION 1
|
||||
#define PRIV_KEY_MODULUS 2
|
||||
#define PRIV_KEY_PUB_EXP 3
|
||||
#define PRIV_KEY_PRIV_EXP 4
|
||||
#define PRIV_KEY_PRIME1 5
|
||||
#define PRIV_KEY_PRIME2 6
|
||||
#define PRIV_KEY_EXP1 7
|
||||
#define PRIV_KEY_EXP2 8
|
||||
#define PRIV_KEY_COEFF 9
|
||||
#define PRIV_KEY_ROOF 16
|
||||
|
||||
/**
|
||||
* defined in rsa_public_key.c
|
||||
*/
|
||||
bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid,
|
||||
identification_t **keyid_info);
|
||||
|
||||
/**
|
||||
* Auxiliary function overwriting private key material with
|
||||
* pseudo-random bytes before releasing it
|
||||
*/
|
||||
static void mpz_clear_randomized(mpz_t z)
|
||||
{
|
||||
size_t len = mpz_size(z) * GMP_LIMB_BITS / BITS_PER_BYTE;
|
||||
u_int8_t *random_bytes = alloca(len);
|
||||
|
||||
randomizer_t *randomizer = randomizer_create();
|
||||
|
||||
randomizer->get_pseudo_random_bytes(randomizer, len, random_bytes);
|
||||
|
||||
/* overwrite mpz_t with pseudo-random bytes before clearing it */
|
||||
mpz_import(z, len, 1, 1, 1, 0, random_bytes);
|
||||
mpz_clear(z);
|
||||
|
||||
randomizer->destroy(randomizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mpz prime of at least prime_size
|
||||
*/
|
||||
static status_t compute_prime(private_gmp_rsa_private_key_t *this,
|
||||
size_t prime_size, mpz_t *prime)
|
||||
{
|
||||
randomizer_t *randomizer;
|
||||
chunk_t random_bytes;
|
||||
status_t status;
|
||||
|
||||
randomizer = randomizer_create();
|
||||
mpz_init(*prime);
|
||||
|
||||
do
|
||||
{
|
||||
status = randomizer->allocate_random_bytes(randomizer, prime_size,
|
||||
&random_bytes);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
randomizer->destroy(randomizer);
|
||||
mpz_clear(*prime);
|
||||
return FAILED;
|
||||
}
|
||||
/* make sure most significant bit is set */
|
||||
random_bytes.ptr[0] = random_bytes.ptr[0] | 0x80;
|
||||
|
||||
mpz_import(*prime, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr);
|
||||
mpz_nextprime (*prime, *prime);
|
||||
chunk_free_randomized(&random_bytes);
|
||||
}
|
||||
/* check if it isn't too large */
|
||||
while (((mpz_sizeinbase(*prime, 2) + 7) / 8) > prime_size);
|
||||
|
||||
randomizer->destroy(randomizer);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#1 RSADP function
|
||||
*/
|
||||
static chunk_t rsadp(private_gmp_rsa_private_key_t *this, chunk_t data)
|
||||
{
|
||||
mpz_t t1, t2;
|
||||
chunk_t decrypted;
|
||||
|
||||
mpz_init(t1);
|
||||
mpz_init(t2);
|
||||
|
||||
mpz_import(t1, data.len, 1, 1, 1, 0, data.ptr);
|
||||
|
||||
mpz_powm(t2, t1, this->exp1, this->p); /* m1 = c^dP mod p */
|
||||
mpz_powm(t1, t1, this->exp2, this->q); /* m2 = c^dQ mod Q */
|
||||
mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
|
||||
mpz_mod(t2, t2, this->p);
|
||||
mpz_mul(t2, t2, this->coeff);
|
||||
mpz_mod(t2, t2, this->p);
|
||||
|
||||
mpz_mul(t2, t2, this->q); /* m = m2 + h q */
|
||||
mpz_add(t1, t1, t2);
|
||||
|
||||
decrypted.len = this->k;
|
||||
decrypted.ptr = mpz_export(NULL, NULL, 1, decrypted.len, 1, 0, t1);
|
||||
|
||||
mpz_clear_randomized(t1);
|
||||
mpz_clear_randomized(t2);
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#1 RSASP1 function
|
||||
*/
|
||||
static chunk_t rsasp1(private_gmp_rsa_private_key_t *this, chunk_t data)
|
||||
{
|
||||
return rsadp(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key_t.build_emsa_pkcs1_signature.
|
||||
*/
|
||||
static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this,
|
||||
hash_algorithm_t hash_algorithm,
|
||||
chunk_t data, chunk_t *signature)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t em, digestInfo, hash;
|
||||
int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
|
||||
|
||||
if (hash_oid == OID_UNKNOWN)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* get hasher */
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
|
||||
if (hasher == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* build hash */
|
||||
hasher->allocate_hash(hasher, data, &hash);
|
||||
hasher->destroy(hasher);
|
||||
|
||||
/* build DER-encoded digestInfo */
|
||||
digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
|
||||
asn1_algorithmIdentifier(hash_oid),
|
||||
asn1_simple_object(ASN1_OCTET_STRING, hash)
|
||||
);
|
||||
chunk_free(&hash);
|
||||
|
||||
/* build chunk to rsa-decrypt:
|
||||
* EM = 0x00 || 0x01 || PS || 0x00 || T.
|
||||
* PS = 0xFF padding, with length to fill em
|
||||
* T = encoded_hash
|
||||
*/
|
||||
em.len = this->k;
|
||||
em.ptr = malloc(em.len);
|
||||
|
||||
/* fill em with padding */
|
||||
memset(em.ptr, 0xFF, em.len);
|
||||
/* set magic bytes */
|
||||
*(em.ptr) = 0x00;
|
||||
*(em.ptr+1) = 0x01;
|
||||
*(em.ptr + em.len - digestInfo.len - 1) = 0x00;
|
||||
/* set DER-encoded hash */
|
||||
memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len);
|
||||
|
||||
/* build signature */
|
||||
*signature = rsasp1(this, em);
|
||||
|
||||
free(digestInfo.ptr);
|
||||
free(em.ptr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static key_type_t get_type(private_gmp_rsa_private_key_t *this)
|
||||
{
|
||||
return KEY_RSA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme,
|
||||
chunk_t data, chunk_t *signature)
|
||||
{
|
||||
switch (scheme)
|
||||
{
|
||||
case SIGN_DEFAULT:
|
||||
/* default is EMSA-PKCS1 using SHA1 */
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA1:
|
||||
return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA256:
|
||||
return build_emsa_pkcs1_signature(this, HASH_SHA256, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA384:
|
||||
return build_emsa_pkcs1_signature(this, HASH_SHA384, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA512:
|
||||
return build_emsa_pkcs1_signature(this, HASH_SHA512, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_MD5:
|
||||
return build_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
|
||||
default:
|
||||
DBG1("signature scheme %N not supported in RSA",
|
||||
signature_scheme_names, scheme);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static bool decrypt(private_gmp_rsa_private_key_t *this,
|
||||
chunk_t crypto, chunk_t *plain)
|
||||
{
|
||||
DBG1("RSA private key decryption not implemented");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static size_t get_keysize(private_gmp_rsa_private_key_t *this)
|
||||
{
|
||||
return this->k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static identification_t* get_id(private_gmp_rsa_private_key_t *this,
|
||||
id_type_t type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ID_PUBKEY_INFO_SHA1:
|
||||
return this->keyid_info;
|
||||
case ID_PUBKEY_SHA1:
|
||||
return this->keyid;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static gmp_rsa_public_key_t* get_public_key(private_gmp_rsa_private_key_t *this)
|
||||
{
|
||||
DBG1("creating RSA public key from private key not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public)
|
||||
{
|
||||
identification_t *keyid;
|
||||
|
||||
if (public->get_type(public) != KEY_RSA)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
keyid = public->get_id(public, ID_PUBKEY_SHA1);
|
||||
if (keyid && keyid->equals(keyid, this->keyid))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
|
||||
if (keyid && keyid->equals(keyid, this->keyid_info))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a MP integer into a DER coded ASN.1 object
|
||||
*/
|
||||
chunk_t gmp_mpz_to_asn1(const mpz_t value)
|
||||
{
|
||||
size_t bits = mpz_sizeinbase(value, 2); /* size in bits */
|
||||
chunk_t n;
|
||||
|
||||
n.len = 1 + bits / 8; /* size in bytes */
|
||||
n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value);
|
||||
|
||||
return asn1_wrap(ASN1_INTEGER, "m", n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of private_key_t.get_encoding.
|
||||
*/
|
||||
static chunk_t get_encoding(private_gmp_rsa_private_key_t *this)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm",
|
||||
ASN1_INTEGER_0,
|
||||
gmp_mpz_to_asn1(this->n),
|
||||
gmp_mpz_to_asn1(this->e),
|
||||
gmp_mpz_to_asn1(this->d),
|
||||
gmp_mpz_to_asn1(this->p),
|
||||
gmp_mpz_to_asn1(this->q),
|
||||
gmp_mpz_to_asn1(this->exp1),
|
||||
gmp_mpz_to_asn1(this->exp2),
|
||||
gmp_mpz_to_asn1(this->coeff));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static private_gmp_rsa_private_key_t* get_ref(private_gmp_rsa_private_key_t *this)
|
||||
{
|
||||
ref_get(&this->ref);
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_private_key.destroy.
|
||||
*/
|
||||
static void destroy(private_gmp_rsa_private_key_t *this)
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
mpz_clear_randomized(this->n);
|
||||
mpz_clear_randomized(this->e);
|
||||
mpz_clear_randomized(this->p);
|
||||
mpz_clear_randomized(this->q);
|
||||
mpz_clear_randomized(this->d);
|
||||
mpz_clear_randomized(this->exp1);
|
||||
mpz_clear_randomized(this->exp2);
|
||||
mpz_clear_randomized(this->coeff);
|
||||
DESTROY_IF(this->keyid);
|
||||
DESTROY_IF(this->keyid_info);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the loaded key if it is valid and usable
|
||||
*/
|
||||
static status_t check(private_gmp_rsa_private_key_t *this)
|
||||
{
|
||||
mpz_t t, u, q1;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
/* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
|
||||
* We actually require more (for security).
|
||||
*/
|
||||
if (this->k < 512/8)
|
||||
{
|
||||
DBG1("key shorter than 512 bits");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* we picked a max modulus size to simplify buffer allocation */
|
||||
if (this->k > 8192/8)
|
||||
{
|
||||
DBG1("key larger thant 8192 bits");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
mpz_init(t);
|
||||
mpz_init(u);
|
||||
mpz_init(q1);
|
||||
|
||||
/* check that n == p * q */
|
||||
mpz_mul(u, this->p, this->q);
|
||||
if (mpz_cmp(u, this->n) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that e divides neither p-1 nor q-1 */
|
||||
mpz_sub_ui(t, this->p, 1);
|
||||
mpz_mod(t, t, this->e);
|
||||
if (mpz_cmp_ui(t, 0) == 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
mpz_sub_ui(t, this->q, 1);
|
||||
mpz_mod(t, t, this->e);
|
||||
if (mpz_cmp_ui(t, 0) == 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that d is e^-1 (mod lcm(p-1, q-1)) */
|
||||
/* see PKCS#1v2, aka RFC 2437, for the "lcm" */
|
||||
mpz_sub_ui(q1, this->q, 1);
|
||||
mpz_sub_ui(u, this->p, 1);
|
||||
mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */
|
||||
mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */
|
||||
mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */
|
||||
|
||||
mpz_mul(t, this->d, this->e);
|
||||
mpz_mod(t, t, u);
|
||||
if (mpz_cmp_ui(t, 1) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that exp1 is d mod (p-1) */
|
||||
mpz_sub_ui(u, this->p, 1);
|
||||
mpz_mod(t, this->d, u);
|
||||
if (mpz_cmp(t, this->exp1) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that exp2 is d mod (q-1) */
|
||||
mpz_sub_ui(u, this->q, 1);
|
||||
mpz_mod(t, this->d, u);
|
||||
if (mpz_cmp(t, this->exp2) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that coeff is (q^-1) mod p */
|
||||
mpz_mul(t, this->coeff, this->q);
|
||||
mpz_mod(t, t, this->p);
|
||||
if (mpz_cmp_ui(t, 1) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
mpz_clear_randomized(t);
|
||||
mpz_clear_randomized(u);
|
||||
mpz_clear_randomized(q1);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
DBG1("key integrity tests failed");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal generic constructor
|
||||
*/
|
||||
static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void)
|
||||
{
|
||||
private_gmp_rsa_private_key_t *this = malloc_thing(private_gmp_rsa_private_key_t);
|
||||
|
||||
this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
|
||||
this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
|
||||
this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
|
||||
this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
|
||||
this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
|
||||
this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
|
||||
this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
|
||||
this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
|
||||
this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
|
||||
this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
|
||||
|
||||
this->keyid = NULL;
|
||||
this->keyid_info = NULL;
|
||||
this->ref = 1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an RSA key of specified key size
|
||||
*/
|
||||
static gmp_rsa_private_key_t *generate(size_t key_size)
|
||||
{
|
||||
mpz_t p, q, n, e, d, exp1, exp2, coeff;
|
||||
mpz_t m, q1, t;
|
||||
private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty();
|
||||
|
||||
key_size = key_size / 8;
|
||||
|
||||
/* Get values of primes p and q */
|
||||
if (compute_prime(this, key_size/2, &p) != SUCCESS)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
if (compute_prime(this, key_size/2, &q) != SUCCESS)
|
||||
{
|
||||
mpz_clear(p);
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mpz_init(t);
|
||||
mpz_init(n);
|
||||
mpz_init(d);
|
||||
mpz_init(exp1);
|
||||
mpz_init(exp2);
|
||||
mpz_init(coeff);
|
||||
|
||||
/* Swapping Primes so p is larger then q */
|
||||
if (mpz_cmp(p, q) < 0)
|
||||
{
|
||||
mpz_swap(p, q);
|
||||
}
|
||||
|
||||
mpz_mul(n, p, q); /* n = p*q */
|
||||
mpz_init_set_ui(e, PUBLIC_EXPONENT); /* assign public exponent */
|
||||
mpz_init_set(m, p); /* m = p */
|
||||
mpz_sub_ui(m, m, 1); /* m = m -1 */
|
||||
mpz_init_set(q1, q); /* q1 = q */
|
||||
mpz_sub_ui(q1, q1, 1); /* q1 = q1 -1 */
|
||||
mpz_gcd(t, m, q1); /* t = gcd(p-1, q-1) */
|
||||
mpz_mul(m, m, q1); /* m = (p-1)*(q-1) */
|
||||
mpz_divexact(m, m, t); /* m = m / t */
|
||||
mpz_gcd(t, m, e); /* t = gcd(m, e) */
|
||||
|
||||
mpz_invert(d, e, m); /* e has an inverse mod m */
|
||||
if (mpz_cmp_ui(d, 0) < 0) /* make sure d is positive */
|
||||
{
|
||||
mpz_add(d, d, m);
|
||||
}
|
||||
mpz_sub_ui(t, p, 1); /* t = p-1 */
|
||||
mpz_mod(exp1, d, t); /* exp1 = d mod p-1 */
|
||||
mpz_sub_ui(t, q, 1); /* t = q-1 */
|
||||
mpz_mod(exp2, d, t); /* exp2 = d mod q-1 */
|
||||
|
||||
mpz_invert(coeff, q, p); /* coeff = q^-1 mod p */
|
||||
if (mpz_cmp_ui(coeff, 0) < 0) /* make coeff d is positive */
|
||||
{
|
||||
mpz_add(coeff, coeff, p);
|
||||
}
|
||||
|
||||
mpz_clear_randomized(q1);
|
||||
mpz_clear_randomized(m);
|
||||
mpz_clear_randomized(t);
|
||||
|
||||
/* apply values */
|
||||
*(this->p) = *p;
|
||||
*(this->q) = *q;
|
||||
*(this->n) = *n;
|
||||
*(this->e) = *e;
|
||||
*(this->d) = *d;
|
||||
*(this->exp1) = *exp1;
|
||||
*(this->exp2) = *exp2;
|
||||
*(this->coeff) = *coeff;
|
||||
|
||||
/* set key size in bytes */
|
||||
this->k = key_size;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* load private key from a ASN1 encoded blob
|
||||
*/
|
||||
static gmp_rsa_private_key_t *load(chunk_t blob)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty();
|
||||
|
||||
mpz_init(this->n);
|
||||
mpz_init(this->e);
|
||||
mpz_init(this->p);
|
||||
mpz_init(this->q);
|
||||
mpz_init(this->d);
|
||||
mpz_init(this->exp1);
|
||||
mpz_init(this->exp2);
|
||||
mpz_init(this->coeff);
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE, TRUE);
|
||||
|
||||
while (objectID < PRIV_KEY_ROOF)
|
||||
{
|
||||
if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
chunk_free_randomized(&blob);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case PRIV_KEY_VERSION:
|
||||
if (object.len > 0 && *object.ptr != 0)
|
||||
{
|
||||
chunk_free_randomized(&blob);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case PRIV_KEY_MODULUS:
|
||||
mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PRIV_KEY_PUB_EXP:
|
||||
mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PRIV_KEY_PRIV_EXP:
|
||||
mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PRIV_KEY_PRIME1:
|
||||
mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PRIV_KEY_PRIME2:
|
||||
mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PRIV_KEY_EXP1:
|
||||
mpz_import(this->exp1, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PRIV_KEY_EXP2:
|
||||
mpz_import(this->exp2, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PRIV_KEY_COEFF:
|
||||
mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
chunk_free_randomized(&blob);
|
||||
|
||||
this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
|
||||
if (!gmp_rsa_public_key_build_id(this->n, this->e,
|
||||
&this->keyid, &this->keyid_info))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (check(this) != SUCCESS)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
typedef struct private_builder_t private_builder_t;
|
||||
/**
|
||||
* Builder implementation for key loading/generation
|
||||
*/
|
||||
struct private_builder_t {
|
||||
/** implements the builder interface */
|
||||
builder_t public;
|
||||
/** loaded/generated private key */
|
||||
gmp_rsa_private_key_t *key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.build
|
||||
*/
|
||||
static gmp_rsa_private_key_t *build(private_builder_t *this)
|
||||
{
|
||||
gmp_rsa_private_key_t *key = this->key;
|
||||
|
||||
free(this);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.add
|
||||
*/
|
||||
static void add(private_builder_t *this, builder_part_t part, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (this->key)
|
||||
{
|
||||
DBG1("ignoring surplus build part %N", builder_part_names, part);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (part)
|
||||
{
|
||||
case BUILD_BLOB_ASN1_DER:
|
||||
{
|
||||
va_start(args, part);
|
||||
this->key = load(va_arg(args, chunk_t));
|
||||
va_end(args);
|
||||
break;
|
||||
}
|
||||
case BUILD_KEY_SIZE:
|
||||
{
|
||||
va_start(args, part);
|
||||
this->key = generate(va_arg(args, u_int));
|
||||
va_end(args);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1("ignoring unsupported build part %N", builder_part_names, part);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder construction function
|
||||
*/
|
||||
builder_t *gmp_rsa_private_key_builder(key_type_t type)
|
||||
{
|
||||
private_builder_t *this;
|
||||
|
||||
if (type != KEY_RSA)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_builder_t);
|
||||
|
||||
this->key = NULL;
|
||||
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||
this->public.build = (void*(*)(builder_t *this))build;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup gmp_rsa_private_key gmp_rsa_private_key
|
||||
* @{ @ingroup gmp_p
|
||||
*/
|
||||
|
||||
#ifndef GMP_RSA_PRIVATE_KEY_H_
|
||||
#define GMP_RSA_PRIVATE_KEY_H_
|
||||
|
||||
#include <credentials/keys/private_key.h>
|
||||
|
||||
typedef struct gmp_rsa_private_key_t gmp_rsa_private_key_t;
|
||||
|
||||
/**
|
||||
* Private_key_t implementation of RSA algorithm using libgmp.
|
||||
*/
|
||||
struct gmp_rsa_private_key_t {
|
||||
|
||||
/**
|
||||
* Implements private_key_t interface
|
||||
*/
|
||||
private_key_t interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the builder for a private key.
|
||||
*
|
||||
* @param type type of the key, must be KEY_RSA
|
||||
* @return builder instance
|
||||
*/
|
||||
builder_t *gmp_rsa_private_key_builder(key_type_t type);
|
||||
|
||||
#endif /*GMP_RSA_PRIVATE_KEY_H_ @}*/
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <gmp.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gmp_rsa_public_key.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/pem.h>
|
||||
|
||||
/**
|
||||
* defined in gmp_rsa_private_key.c
|
||||
*/
|
||||
extern chunk_t gmp_mpz_to_asn1(const mpz_t value);
|
||||
|
||||
/**
|
||||
* ASN.1 definition of a subjectPublicKeyInfo structure
|
||||
*/
|
||||
static const asn1Object_t pkinfoObjects[] = {
|
||||
{ 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
|
||||
{ 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 2 */
|
||||
{ 2, "RSAPublicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 3 */
|
||||
};
|
||||
#define PKINFO 0
|
||||
#define PKINFO_SUBJECT_PK_ALGORITHM 1
|
||||
#define PKINFO_SUBJECT_PK 2
|
||||
#define PKINFO_gmp_rsa_public_key 3
|
||||
#define PKINFO_ROOF 4
|
||||
|
||||
/* ASN.1 definition of RSApublicKey */
|
||||
static const asn1Object_t pubkeyObjects[] = {
|
||||
{ 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */
|
||||
{ 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */
|
||||
};
|
||||
|
||||
#define PUB_KEY_gmp_rsa_public_key 0
|
||||
#define PUB_KEY_MODULUS 1
|
||||
#define PUB_KEY_EXPONENT 2
|
||||
#define PUB_KEY_ROOF 3
|
||||
|
||||
/* ASN.1 definition of digestInfo */
|
||||
static const asn1Object_t digestInfoObjects[] = {
|
||||
{ 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
|
||||
{ 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
|
||||
};
|
||||
|
||||
#define DIGEST_INFO 0
|
||||
#define DIGEST_INFO_ALGORITHM 1
|
||||
#define DIGEST_INFO_DIGEST 2
|
||||
#define DIGEST_INFO_ROOF 3
|
||||
|
||||
typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
|
||||
|
||||
/**
|
||||
* Private data structure with signing context.
|
||||
*/
|
||||
struct private_gmp_rsa_public_key_t {
|
||||
/**
|
||||
* Public interface for this signer.
|
||||
*/
|
||||
gmp_rsa_public_key_t public;
|
||||
|
||||
/**
|
||||
* Public modulus.
|
||||
*/
|
||||
mpz_t n;
|
||||
|
||||
/**
|
||||
* Public exponent.
|
||||
*/
|
||||
mpz_t e;
|
||||
|
||||
/**
|
||||
* Keysize in bytes.
|
||||
*/
|
||||
size_t k;
|
||||
|
||||
/**
|
||||
* Keyid formed as a SHA-1 hash of a publicKeyInfo object
|
||||
*/
|
||||
identification_t *keyid_info;
|
||||
|
||||
/**
|
||||
* Keyid formed as a SHA-1 hash of a publicKey object
|
||||
*/
|
||||
identification_t *keyid;
|
||||
|
||||
/**
|
||||
* reference counter
|
||||
*/
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* RSAEP algorithm specified in PKCS#1.
|
||||
*/
|
||||
static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data)
|
||||
{
|
||||
mpz_t m, c;
|
||||
chunk_t encrypted;
|
||||
|
||||
mpz_init(c);
|
||||
mpz_init(m);
|
||||
|
||||
mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
|
||||
|
||||
mpz_powm(c, m, this->e, this->n);
|
||||
|
||||
encrypted.len = this->k;
|
||||
encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
|
||||
|
||||
mpz_clear(c);
|
||||
mpz_clear(m);
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* RSAVP1 algorithm specified in PKCS#1.
|
||||
*/
|
||||
static chunk_t rsavp1(private_gmp_rsa_public_key_t *this, chunk_t data)
|
||||
{
|
||||
return rsaep(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification of an EMPSA PKCS1 signature described in PKCS#1
|
||||
*/
|
||||
static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
|
||||
hash_algorithm_t algorithm,
|
||||
chunk_t data, chunk_t signature)
|
||||
{
|
||||
chunk_t em_ori, em;
|
||||
bool res = FALSE;
|
||||
|
||||
/* remove any preceding 0-bytes from signature */
|
||||
while (signature.len && *(signature.ptr) == 0x00)
|
||||
{
|
||||
signature.len -= 1;
|
||||
signature.ptr++;
|
||||
}
|
||||
|
||||
if (signature.len > this->k)
|
||||
{
|
||||
return INVALID_ARG;
|
||||
}
|
||||
|
||||
/* unpack signature */
|
||||
em_ori = em = rsavp1(this, signature);
|
||||
|
||||
/* result should look like this:
|
||||
* EM = 0x00 || 0x01 || PS || 0x00 || T.
|
||||
* PS = 0xFF padding, with length to fill em
|
||||
* T = oid || hash
|
||||
*/
|
||||
|
||||
/* check magic bytes */
|
||||
if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
em.ptr += 2;
|
||||
em.len -= 2;
|
||||
|
||||
/* find magic 0x00 */
|
||||
while (em.len > 0)
|
||||
{
|
||||
if (*em.ptr == 0x00)
|
||||
{
|
||||
/* found magic byte, stop */
|
||||
em.ptr++;
|
||||
em.len--;
|
||||
break;
|
||||
}
|
||||
else if (*em.ptr != 0xFF)
|
||||
{
|
||||
/* bad padding, decryption failed ?!*/
|
||||
goto end;
|
||||
}
|
||||
em.ptr++;
|
||||
em.len--;
|
||||
}
|
||||
|
||||
if (em.len == 0)
|
||||
{
|
||||
/* no digestInfo found */
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* parse ASN.1-based digestInfo */
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
|
||||
|
||||
asn1_init(&ctx, em, 0, FALSE, FALSE);
|
||||
|
||||
while (objectID < DIGEST_INFO_ROOF)
|
||||
{
|
||||
if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case DIGEST_INFO:
|
||||
{
|
||||
if (em.len > object.len)
|
||||
{
|
||||
DBG1("digestInfo field in signature is followed by %u surplus bytes",
|
||||
em.len - object.len);
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIGEST_INFO_ALGORITHM:
|
||||
{
|
||||
int hash_oid = parse_algorithmIdentifier(object, level+1, NULL);
|
||||
|
||||
hash_algorithm = hasher_algorithm_from_oid(hash_oid);
|
||||
if (hash_algorithm == HASH_UNKNOWN ||
|
||||
(algorithm != HASH_UNKNOWN && hash_algorithm != algorithm))
|
||||
{
|
||||
DBG1("wrong hash algorithm used in signature");
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIGEST_INFO_DIGEST:
|
||||
{
|
||||
chunk_t hash;
|
||||
hasher_t *hasher;
|
||||
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
|
||||
if (hasher == NULL)
|
||||
{
|
||||
DBG1("hash algorithm %N not supported",
|
||||
hash_algorithm_names, hash_algorithm);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (object.len != hasher->get_hash_size(hasher))
|
||||
{
|
||||
DBG1("hash size in signature is %u bytes instead of %u "
|
||||
"bytes", object.len, hasher->get_hash_size(hasher));
|
||||
hasher->destroy(hasher);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* build our own hash and compare */
|
||||
hasher->allocate_hash(hasher, data, &hash);
|
||||
hasher->destroy(hasher);
|
||||
res = memeq(object.ptr, hash.ptr, hash.len);
|
||||
free(hash.ptr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
free(em_ori.ptr);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of public_key_t.get_type.
|
||||
*/
|
||||
static key_type_t get_type(private_gmp_rsa_public_key_t *this)
|
||||
{
|
||||
return KEY_RSA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of public_key_t.verify.
|
||||
*/
|
||||
static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme,
|
||||
chunk_t data, chunk_t signature)
|
||||
{
|
||||
switch (scheme)
|
||||
{
|
||||
case SIGN_DEFAULT: /* default is EMSA-PKCS1 using included OID */
|
||||
return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_MD5:
|
||||
return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA1:
|
||||
return verify_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA256:
|
||||
return verify_emsa_pkcs1_signature(this, HASH_SHA256, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA384:
|
||||
return verify_emsa_pkcs1_signature(this, HASH_SHA384, data, signature);
|
||||
case SIGN_RSA_EMSA_PKCS1_SHA512:
|
||||
return verify_emsa_pkcs1_signature(this, HASH_SHA512, data, signature);
|
||||
default:
|
||||
DBG1("signature scheme %N not supported in RSA",
|
||||
signature_scheme_names, scheme);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of public_key_t.get_keysize.
|
||||
*/
|
||||
static bool encrypt(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t *plain)
|
||||
{
|
||||
DBG1("RSA public key encryption not implemented");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of public_key_t.get_keysize.
|
||||
*/
|
||||
static size_t get_keysize(private_gmp_rsa_public_key_t *this)
|
||||
{
|
||||
return this->k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of public_key_t.get_id.
|
||||
*/
|
||||
static identification_t *get_id(private_gmp_rsa_public_key_t *this,
|
||||
id_type_t type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ID_PUBKEY_INFO_SHA1:
|
||||
return this->keyid_info;
|
||||
case ID_PUBKEY_SHA1:
|
||||
return this->keyid;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of public_key_t.get_encoding.
|
||||
*/
|
||||
static chunk_t get_encoding(private_gmp_rsa_public_key_t *this)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||
gmp_mpz_to_asn1(this->n),
|
||||
gmp_mpz_to_asn1(this->e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of public_key_t.get_ref.
|
||||
*/
|
||||
static private_gmp_rsa_public_key_t* get_ref(private_gmp_rsa_public_key_t *this)
|
||||
{
|
||||
ref_get(&this->ref);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of gmp_rsa_public_key.destroy.
|
||||
*/
|
||||
static void destroy(private_gmp_rsa_public_key_t *this)
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
mpz_clear(this->n);
|
||||
mpz_clear(this->e);
|
||||
DESTROY_IF(this->keyid);
|
||||
DESTROY_IF(this->keyid_info);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic private constructor
|
||||
*/
|
||||
static private_gmp_rsa_public_key_t *gmp_rsa_public_key_create_empty()
|
||||
{
|
||||
private_gmp_rsa_public_key_t *this = malloc_thing(private_gmp_rsa_public_key_t);
|
||||
|
||||
this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
|
||||
this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
|
||||
this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt;
|
||||
this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
|
||||
this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id;
|
||||
this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding;
|
||||
this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref;
|
||||
this->public.interface.destroy = (void (*)(public_key_t *this))destroy;
|
||||
|
||||
this->keyid = NULL;
|
||||
this->keyid_info = NULL;
|
||||
this->ref = 1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info).
|
||||
* Also used in rsa_private_key.c.
|
||||
*/
|
||||
bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid,
|
||||
identification_t **keyid_info)
|
||||
{
|
||||
chunk_t publicKeyInfo, publicKey, hash;
|
||||
hasher_t *hasher;
|
||||
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||
if (hasher == NULL)
|
||||
{
|
||||
DBG1("SHA1 hash algorithm not supported, unable to use RSA");
|
||||
return FALSE;
|
||||
}
|
||||
publicKey = asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||
gmp_mpz_to_asn1(n),
|
||||
gmp_mpz_to_asn1(e));
|
||||
hasher->allocate_hash(hasher, publicKey, &hash);
|
||||
*keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
|
||||
chunk_free(&hash);
|
||||
|
||||
publicKeyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
|
||||
asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
|
||||
asn1_bitstring("m", publicKey));
|
||||
hasher->allocate_hash(hasher, publicKeyInfo, &hash);
|
||||
*keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash);
|
||||
chunk_free(&hash);
|
||||
|
||||
hasher->destroy(hasher);
|
||||
chunk_free(&publicKeyInfo);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a public key from an ASN1 encoded blob
|
||||
*/
|
||||
static gmp_rsa_public_key_t *load(chunk_t blob)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty();
|
||||
|
||||
mpz_init(this->n);
|
||||
mpz_init(this->e);
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE, FALSE);
|
||||
|
||||
while (objectID < PUB_KEY_ROOF)
|
||||
{
|
||||
if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
free(blob.ptr);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case PUB_KEY_MODULUS:
|
||||
mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
case PUB_KEY_EXPONENT:
|
||||
mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
free(blob.ptr);
|
||||
this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
|
||||
if (!gmp_rsa_public_key_build_id(this->n, this->e,
|
||||
&this->keyid, &this->keyid_info))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
||||
typedef struct private_builder_t private_builder_t;
|
||||
/**
|
||||
* Builder implementation for key loading
|
||||
*/
|
||||
struct private_builder_t {
|
||||
/** implements the builder interface */
|
||||
builder_t public;
|
||||
/** loaded public key */
|
||||
gmp_rsa_public_key_t *key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.build
|
||||
*/
|
||||
static gmp_rsa_public_key_t *build(private_builder_t *this)
|
||||
{
|
||||
gmp_rsa_public_key_t *key = this->key;
|
||||
|
||||
free(this);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.add
|
||||
*/
|
||||
static void add(private_builder_t *this, builder_part_t part, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (this->key)
|
||||
{
|
||||
DBG1("ignoring surplus build part %N", builder_part_names, part);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (part)
|
||||
{
|
||||
case BUILD_BLOB_ASN1_DER:
|
||||
{
|
||||
va_start(args, part);
|
||||
this->key = load(va_arg(args, chunk_t));
|
||||
va_end(args);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1("ignoring unsupported build part %N", builder_part_names, part);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder construction function
|
||||
*/
|
||||
builder_t *gmp_rsa_public_key_builder(key_type_t type)
|
||||
{
|
||||
private_builder_t *this;
|
||||
|
||||
if (type != KEY_RSA)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_builder_t);
|
||||
|
||||
this->key = NULL;
|
||||
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||
this->public.build = (void*(*)(builder_t *this))build;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup gmp_rsa_public_key gmp_rsa_public_key
|
||||
* @{ @ingroup gmp_p
|
||||
*/
|
||||
|
||||
#ifndef GMP_RSA_PUBLIC_KEY_H_
|
||||
#define GMP_RSA_PUBLIC_KEY_H_
|
||||
|
||||
typedef struct gmp_rsa_public_key_t gmp_rsa_public_key_t;
|
||||
|
||||
#include <credentials/keys/public_key.h>
|
||||
|
||||
/**
|
||||
* public_key_t implementation of RSA algorithm using libgmp.
|
||||
*/
|
||||
struct gmp_rsa_public_key_t {
|
||||
|
||||
/**
|
||||
* Implements the public_key_t interface
|
||||
*/
|
||||
public_key_t interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the builder for a public key.
|
||||
*
|
||||
* @param type type of the key, must be KEY_RSA
|
||||
* @return builder instance
|
||||
*/
|
||||
builder_t *gmp_rsa_public_key_builder(key_type_t type);
|
||||
|
||||
#endif /*GMP_RSA_PUBLIC_KEY_H_ @}*/
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-hmac.la
|
||||
|
||||
libstrongswan_hmac_la_SOURCES = hmac_plugin.h hmac_plugin.c hmac.h hmac.c \
|
||||
hmac_prf.h hmac_prf.c hmac_signer.h hmac_signer.c
|
||||
libstrongswan_hmac_la_LDFLAGS = -module
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General hmac License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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 hmac License
|
||||
* for more details.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hmac.h"
|
||||
|
||||
|
||||
typedef struct private_hmac_t private_hmac_t;
|
||||
|
||||
/**
|
||||
* Private data of a hmac_t object.
|
||||
*
|
||||
* The variable names are the same as in the RFC.
|
||||
*/
|
||||
struct private_hmac_t {
|
||||
/**
|
||||
* Public hmac_t interface.
|
||||
*/
|
||||
hmac_t hmac;
|
||||
|
||||
/**
|
||||
* Block size, as in RFC.
|
||||
*/
|
||||
u_int8_t b;
|
||||
|
||||
/**
|
||||
* Hash function.
|
||||
*/
|
||||
hasher_t *h;
|
||||
|
||||
/**
|
||||
* Previously xor'ed key using opad.
|
||||
*/
|
||||
chunk_t opaded_key;
|
||||
|
||||
/**
|
||||
* Previously xor'ed key using ipad.
|
||||
*/
|
||||
chunk_t ipaded_key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of hmac_t.get_mac.
|
||||
*/
|
||||
static void get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out)
|
||||
{
|
||||
/* H(K XOR opad, H(K XOR ipad, text))
|
||||
*
|
||||
* if out is NULL, we append text to the inner hash.
|
||||
* else, we complete the inner and do the outer.
|
||||
*
|
||||
*/
|
||||
|
||||
u_int8_t buffer[this->h->get_hash_size(this->h)];
|
||||
chunk_t inner;
|
||||
|
||||
if (out == NULL)
|
||||
{
|
||||
/* append data to inner */
|
||||
this->h->get_hash(this->h, data, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* append and do outer hash */
|
||||
inner.ptr = buffer;
|
||||
inner.len = this->h->get_hash_size(this->h);
|
||||
|
||||
/* complete inner */
|
||||
this->h->get_hash(this->h, data, buffer);
|
||||
|
||||
/* do outer */
|
||||
this->h->get_hash(this->h, this->opaded_key, NULL);
|
||||
this->h->get_hash(this->h, inner, out);
|
||||
|
||||
/* reinit for next call */
|
||||
this->h->get_hash(this->h, this->ipaded_key, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hmac_t.allocate_mac.
|
||||
*/
|
||||
static void allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out)
|
||||
{
|
||||
/* allocate space and use get_mac */
|
||||
if (out == NULL)
|
||||
{
|
||||
/* append mode */
|
||||
this->hmac.get_mac(&(this->hmac), data, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
out->len = this->h->get_hash_size(this->h);
|
||||
out->ptr = malloc(out->len);
|
||||
this->hmac.get_mac(&(this->hmac), data, out->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hmac_t.get_block_size.
|
||||
*/
|
||||
static size_t get_block_size(private_hmac_t *this)
|
||||
{
|
||||
return this->h->get_hash_size(this->h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hmac_t.set_key.
|
||||
*/
|
||||
static void set_key(private_hmac_t *this, chunk_t key)
|
||||
{
|
||||
int i;
|
||||
u_int8_t buffer[this->b];
|
||||
|
||||
memset(buffer, 0, this->b);
|
||||
|
||||
if (key.len > this->b)
|
||||
{
|
||||
/* if key is too long, it will be hashed */
|
||||
this->h->get_hash(this->h, key, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if not, just copy it in our pre-padded k */
|
||||
memcpy(buffer, key.ptr, key.len);
|
||||
}
|
||||
|
||||
/* apply ipad and opad to key */
|
||||
for (i = 0; i < this->b; i++)
|
||||
{
|
||||
this->ipaded_key.ptr[i] = buffer[i] ^ 0x36;
|
||||
this->opaded_key.ptr[i] = buffer[i] ^ 0x5C;
|
||||
}
|
||||
|
||||
/* begin hashing of inner pad */
|
||||
this->h->reset(this->h);
|
||||
this->h->get_hash(this->h, this->ipaded_key, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hmac_t.destroy.
|
||||
*/
|
||||
static void destroy(private_hmac_t *this)
|
||||
{
|
||||
this->h->destroy(this->h);
|
||||
free(this->opaded_key.ptr);
|
||||
free(this->ipaded_key.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
hmac_t *hmac_create(hash_algorithm_t hash_algorithm)
|
||||
{
|
||||
private_hmac_t *this = malloc_thing(private_hmac_t);
|
||||
|
||||
/* set hmac_t methods */
|
||||
this->hmac.get_mac = (void (*)(hmac_t *,chunk_t,u_int8_t*))get_mac;
|
||||
this->hmac.allocate_mac = (void (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac;
|
||||
this->hmac.get_block_size = (size_t (*)(hmac_t *))get_block_size;
|
||||
this->hmac.set_key = (void (*)(hmac_t *,chunk_t))set_key;
|
||||
this->hmac.destroy = (void (*)(hmac_t *))destroy;
|
||||
|
||||
/* set b, according to hasher */
|
||||
switch (hash_algorithm)
|
||||
{
|
||||
case HASH_SHA1:
|
||||
case HASH_MD5:
|
||||
case HASH_SHA256:
|
||||
this->b = 64;
|
||||
break;
|
||||
case HASH_SHA384:
|
||||
case HASH_SHA512:
|
||||
this->b = 128;
|
||||
break;
|
||||
default:
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* build the hasher */
|
||||
this->h = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
|
||||
if (this->h == NULL)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* build ipad and opad */
|
||||
this->opaded_key.ptr = malloc(this->b);
|
||||
this->opaded_key.len = this->b;
|
||||
|
||||
this->ipaded_key.ptr = malloc(this->b);
|
||||
this->ipaded_key.len = this->b;
|
||||
|
||||
return &(this->hmac);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup hmac hmac
|
||||
* @{ @ingroup hmac_p
|
||||
*/
|
||||
|
||||
#ifndef HMAC_H_
|
||||
#define HMAC_H_
|
||||
|
||||
typedef struct hmac_t hmac_t;
|
||||
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* Message authentication using hash functions.
|
||||
*
|
||||
* This class implements the message authenticaion algorithm
|
||||
* described in RFC2104. It uses a hash function, wich must
|
||||
* be implemented as a hasher_t class.
|
||||
*/
|
||||
struct hmac_t {
|
||||
/**
|
||||
* Generate message authentication code.
|
||||
*
|
||||
* If buffer is NULL, no result is given back. A next call will
|
||||
* append the data to already supplied data. If buffer is not NULL,
|
||||
* the mac of all apended data is calculated, returned and the
|
||||
* state of the hmac_t is reseted.
|
||||
*
|
||||
* @param data chunk of data to authenticate
|
||||
* @param buffer pointer where the generated bytes will be written
|
||||
*/
|
||||
void (*get_mac) (hmac_t *this, chunk_t data, u_int8_t *buffer);
|
||||
|
||||
/**
|
||||
* Generates message authentication code and allocate space for them.
|
||||
*
|
||||
* If chunk is NULL, no result is given back. A next call will
|
||||
* append the data to already supplied. If chunk is not NULL,
|
||||
* the mac of all apended data is calculated, returned and the
|
||||
* state of the hmac_t reset;
|
||||
*
|
||||
* @param data chunk of data to authenticate
|
||||
* @param chunk chunk which will hold generated bytes
|
||||
*/
|
||||
void (*allocate_mac) (hmac_t *this, chunk_t data, chunk_t *chunk);
|
||||
|
||||
/**
|
||||
* Get the block size of this hmac_t object.
|
||||
*
|
||||
* @return block size in bytes
|
||||
*/
|
||||
size_t (*get_block_size) (hmac_t *this);
|
||||
|
||||
/**
|
||||
* Set the key for this hmac_t object.
|
||||
*
|
||||
* Any key length is accepted.
|
||||
*
|
||||
* @param key key to set
|
||||
*/
|
||||
void (*set_key) (hmac_t *this, chunk_t key);
|
||||
|
||||
/**
|
||||
* Destroys a hmac_t object.
|
||||
*/
|
||||
void (*destroy) (hmac_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new hmac_t object.
|
||||
*
|
||||
* @param hash_algorithm hash algorithm to use
|
||||
* @return hmac_t object, NULL if not supported
|
||||
*/
|
||||
hmac_t *hmac_create(hash_algorithm_t hash_algorithm);
|
||||
|
||||
#endif /*HMAC_H_ @}*/
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "hmac_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "hmac_signer.h"
|
||||
#include "hmac_prf.h"
|
||||
|
||||
typedef struct private_hmac_plugin_t private_hmac_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of hmac_plugin
|
||||
*/
|
||||
struct private_hmac_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
hmac_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of hmac_plugin_t.hmactroy
|
||||
*/
|
||||
static void destroy(private_hmac_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_prf(lib->crypto,
|
||||
(prf_constructor_t)hmac_prf_create);
|
||||
lib->crypto->remove_signer(lib->crypto,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_hmac_plugin_t *this = malloc_thing(private_hmac_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_prf(lib->crypto, PRF_HMAC_MD5,
|
||||
(prf_constructor_t)hmac_prf_create);
|
||||
lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA1,
|
||||
(prf_constructor_t)hmac_prf_create);
|
||||
lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_256,
|
||||
(prf_constructor_t)hmac_prf_create);
|
||||
lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_384,
|
||||
(prf_constructor_t)hmac_prf_create);
|
||||
lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_512,
|
||||
(prf_constructor_t)hmac_prf_create);
|
||||
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_MD5_96,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA1_96,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA1_128,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_256_128,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_384_192,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_512_256,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup hmac_p hmac
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup hmac_plugin hmac_plugin
|
||||
* @{ @ingroup hmac_p
|
||||
*/
|
||||
|
||||
#ifndef HMAC_PLUGIN_H_
|
||||
#define HMAC_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct hmac_plugin_t hmac_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing HMAC algorithm to prvoide hash based PRF and signers.
|
||||
*/
|
||||
struct hmac_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a hmac_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* HMAC_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "hmac_prf.h"
|
||||
|
||||
#include "hmac.h"
|
||||
|
||||
|
||||
typedef struct private_hmac_prf_t private_hmac_prf_t;
|
||||
|
||||
/**
|
||||
* Private data of a hma_prf_t object.
|
||||
*/
|
||||
struct private_hmac_prf_t {
|
||||
/**
|
||||
* Public hmac_prf_t interface.
|
||||
*/
|
||||
hmac_prf_t public;
|
||||
|
||||
/**
|
||||
* Hmac to use for generation.
|
||||
*/
|
||||
hmac_t *hmac;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_bytes.
|
||||
*/
|
||||
static void get_bytes(private_hmac_prf_t *this, chunk_t seed, u_int8_t *buffer)
|
||||
{
|
||||
this->hmac->get_mac(this->hmac, seed, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.allocate_bytes.
|
||||
*/
|
||||
static void allocate_bytes(private_hmac_prf_t *this, chunk_t seed, chunk_t *chunk)
|
||||
{
|
||||
this->hmac->allocate_mac(this->hmac, seed, chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_block_size.
|
||||
*/
|
||||
static size_t get_block_size(private_hmac_prf_t *this)
|
||||
{
|
||||
return this->hmac->get_block_size(this->hmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_block_size.
|
||||
*/
|
||||
static size_t get_key_size(private_hmac_prf_t *this)
|
||||
{
|
||||
/* for HMAC prfs, IKEv2 uses block size as key size */
|
||||
return this->hmac->get_block_size(this->hmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.set_key.
|
||||
*/
|
||||
static void set_key(private_hmac_prf_t *this, chunk_t key)
|
||||
{
|
||||
this->hmac->set_key(this->hmac, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.destroy.
|
||||
*/
|
||||
static void destroy(private_hmac_prf_t *this)
|
||||
{
|
||||
this->hmac->destroy(this->hmac);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo)
|
||||
{
|
||||
private_hmac_prf_t *this;
|
||||
hash_algorithm_t hash;
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case PRF_HMAC_SHA1:
|
||||
hash = HASH_SHA1;
|
||||
break;
|
||||
case PRF_HMAC_MD5:
|
||||
hash = HASH_MD5;
|
||||
break;
|
||||
case PRF_HMAC_SHA2_256:
|
||||
hash = HASH_SHA256;
|
||||
break;
|
||||
case PRF_HMAC_SHA2_384:
|
||||
hash = HASH_SHA384;
|
||||
break;
|
||||
case PRF_HMAC_SHA2_512:
|
||||
hash = HASH_SHA512;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_hmac_prf_t);
|
||||
this->hmac = hmac_create(hash);
|
||||
if (this->hmac == NULL)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
|
||||
this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
|
||||
this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
|
||||
this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
|
||||
this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
|
||||
this->public.prf_interface.destroy = (void (*) (prf_t *))destroy;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup hmac_prf hmac_prf
|
||||
* @{ @ingroup hmac_p
|
||||
*/
|
||||
|
||||
#ifndef PRF_HMAC_H_
|
||||
#define PRF_HMAC_H_
|
||||
|
||||
typedef struct hmac_prf_t hmac_prf_t;
|
||||
|
||||
#include <crypto/prfs/prf.h>
|
||||
|
||||
/**
|
||||
* Implementation of prf_t interface using the HMAC algorithm.
|
||||
*
|
||||
* This simply wraps a hmac_t in a prf_t. More a question of
|
||||
* interface matching.
|
||||
*/
|
||||
struct hmac_prf_t {
|
||||
|
||||
/**
|
||||
* Generic prf_t interface for this hmac_prf_t class.
|
||||
*/
|
||||
prf_t prf_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new hmac_prf_t object.
|
||||
*
|
||||
* @param algo algorithm to implement
|
||||
* @return hmac_prf_t object, NULL if hash not supported
|
||||
*/
|
||||
hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo);
|
||||
|
||||
#endif /*PRF_HMAC_SHA1_H_ @}*/
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hmac_signer.h"
|
||||
#include "hmac.h"
|
||||
|
||||
typedef struct private_hmac_signer_t private_hmac_signer_t;
|
||||
|
||||
/**
|
||||
* Private data structure with signing context.
|
||||
*/
|
||||
struct private_hmac_signer_t {
|
||||
/**
|
||||
* Public interface of hmac_signer_t.
|
||||
*/
|
||||
hmac_signer_t public;
|
||||
|
||||
/**
|
||||
* Assigned hmac function.
|
||||
*/
|
||||
hmac_t *hmac;
|
||||
|
||||
/**
|
||||
* Block size (truncation of HMAC Hash)
|
||||
*/
|
||||
size_t block_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.get_signature.
|
||||
*/
|
||||
static void get_signature(private_hmac_signer_t *this,
|
||||
chunk_t data, u_int8_t *buffer)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
{ /* append mode */
|
||||
this->hmac->get_mac(this->hmac, data, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
u_int8_t mac[this->hmac->get_block_size(this->hmac)];
|
||||
|
||||
this->hmac->get_mac(this->hmac, data, mac);
|
||||
memcpy(buffer, mac, this->block_size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.allocate_signature.
|
||||
*/
|
||||
static void allocate_signature (private_hmac_signer_t *this,
|
||||
chunk_t data, chunk_t *chunk)
|
||||
{
|
||||
if (chunk == NULL)
|
||||
{ /* append mode */
|
||||
this->hmac->get_mac(this->hmac, data, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
u_int8_t mac[this->hmac->get_block_size(this->hmac)];
|
||||
|
||||
this->hmac->get_mac(this->hmac, data, mac);
|
||||
|
||||
chunk->ptr = malloc(this->block_size);
|
||||
chunk->len = this->block_size;
|
||||
|
||||
memcpy(chunk->ptr, mac, this->block_size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.verify_signature.
|
||||
*/
|
||||
static bool verify_signature(private_hmac_signer_t *this,
|
||||
chunk_t data, chunk_t signature)
|
||||
{
|
||||
u_int8_t mac[this->hmac->get_block_size(this->hmac)];
|
||||
|
||||
this->hmac->get_mac(this->hmac, data, mac);
|
||||
|
||||
if (signature.len != this->block_size)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return memeq(signature.ptr, mac, this->block_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.get_key_size.
|
||||
*/
|
||||
static size_t get_key_size(private_hmac_signer_t *this)
|
||||
{
|
||||
return this->hmac->get_block_size(this->hmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.get_block_size.
|
||||
*/
|
||||
static size_t get_block_size(private_hmac_signer_t *this)
|
||||
{
|
||||
return this->block_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.set_key.
|
||||
*/
|
||||
static void set_key(private_hmac_signer_t *this, chunk_t key)
|
||||
{
|
||||
this->hmac->set_key(this->hmac, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.destroy.
|
||||
*/
|
||||
static status_t destroy(private_hmac_signer_t *this)
|
||||
{
|
||||
this->hmac->destroy(this->hmac);
|
||||
free(this);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo)
|
||||
{
|
||||
private_hmac_signer_t *this;
|
||||
size_t trunc;
|
||||
hash_algorithm_t hash;
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case AUTH_HMAC_SHA1_96:
|
||||
hash = HASH_SHA1;
|
||||
trunc = 12;
|
||||
break;
|
||||
case AUTH_HMAC_SHA1_128:
|
||||
hash = HASH_SHA1;
|
||||
trunc = 16;
|
||||
break;
|
||||
case AUTH_HMAC_MD5_96:
|
||||
hash = HASH_MD5;
|
||||
trunc = 12;
|
||||
break;
|
||||
case AUTH_HMAC_SHA2_256_128:
|
||||
hash = HASH_SHA256;
|
||||
trunc = 16;
|
||||
break;
|
||||
case AUTH_HMAC_SHA2_384_192:
|
||||
hash = HASH_SHA384;
|
||||
trunc = 24;
|
||||
break;
|
||||
case AUTH_HMAC_SHA2_512_256:
|
||||
hash = HASH_SHA512;
|
||||
trunc = 32;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_hmac_signer_t);
|
||||
this->hmac = hmac_create(hash);
|
||||
if (this->hmac == NULL)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
/* prevent invalid truncation */
|
||||
this->block_size = min(trunc, this->hmac->get_block_size(this->hmac));
|
||||
|
||||
/* interface functions */
|
||||
this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature;
|
||||
this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature;
|
||||
this->public.signer_interface.verify_signature = (bool (*) (signer_t*, chunk_t, chunk_t))verify_signature;
|
||||
this->public.signer_interface.get_key_size = (size_t (*) (signer_t*))get_key_size;
|
||||
this->public.signer_interface.get_block_size = (size_t (*) (signer_t*))get_block_size;
|
||||
this->public.signer_interface.set_key = (void (*) (signer_t*,chunk_t))set_key;
|
||||
this->public.signer_interface.destroy = (void (*) (signer_t*))destroy;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup hmac_signer hmac_signer
|
||||
* @{ @ingroup hmac_p
|
||||
*/
|
||||
|
||||
#ifndef HMAC_SIGNER_H_
|
||||
#define HMAC_SIGNER_H_
|
||||
|
||||
typedef struct hmac_signer_t hmac_signer_t;
|
||||
|
||||
#include <crypto/signers/signer.h>
|
||||
|
||||
/**
|
||||
* Implementation of signer_t interface using HMAC.
|
||||
*
|
||||
* HMAC uses a standard hash function implemented in a hasher_t to build a MAC.
|
||||
*/
|
||||
struct hmac_signer_t {
|
||||
|
||||
/**
|
||||
* generic signer_t interface for this signer
|
||||
*/
|
||||
signer_t signer_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new hmac_signer_t.
|
||||
*
|
||||
* HMAC signatures are often truncated to shorten them to a more usable, but
|
||||
* still secure enough length.
|
||||
* Block size must be equal or smaller then the hash algorithms
|
||||
* hash.
|
||||
*
|
||||
* @param algo algorithm to implement
|
||||
* @return hmac_signer_t, NULL if not supported
|
||||
*/
|
||||
hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo);
|
||||
|
||||
#endif /*HMAC_SIGNER_H_ @}*/
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-ldap.la
|
||||
|
||||
libstrongswan_ldap_la_SOURCES = ldap_plugin.h ldap_plugin.c ldap_fetcher.h ldap_fetcher.c
|
||||
libstrongswan_ldap_la_LDFLAGS = -module
|
||||
libstrongswan_ldap_la_LIBADD = -lldap -llber
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Copyright (C) 2007 Andreas Steffen
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef LDAP_DEPRECATED
|
||||
#define LDAP_DEPRECATED 1
|
||||
#endif /* LDAP_DEPRECATED */
|
||||
#include <ldap.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "ldap_fetcher.h"
|
||||
|
||||
#define DEFAULT_TIMEOUT 10
|
||||
|
||||
typedef struct private_ldap_fetcher_t private_ldap_fetcher_t;
|
||||
|
||||
/**
|
||||
* Private Data of a ldap_fetcher_t object.
|
||||
*/
|
||||
struct private_ldap_fetcher_t {
|
||||
/**
|
||||
* Public data
|
||||
*/
|
||||
ldap_fetcher_t public;
|
||||
|
||||
/**
|
||||
* timeout to use for fetches
|
||||
*/
|
||||
u_int timeout;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the result returned by an ldap query
|
||||
*/
|
||||
static bool parse(LDAP *ldap, LDAPMessage *result, chunk_t *response)
|
||||
{
|
||||
LDAPMessage *entry = ldap_first_entry(ldap, result);
|
||||
bool success = FALSE;
|
||||
|
||||
if (entry)
|
||||
{
|
||||
BerElement *ber = NULL;
|
||||
char *attr;
|
||||
|
||||
attr = ldap_first_attribute(ldap, entry, &ber);
|
||||
if (attr)
|
||||
{
|
||||
struct berval **values = ldap_get_values_len(ldap, entry, attr);
|
||||
|
||||
if (values)
|
||||
{
|
||||
if (values[0])
|
||||
{
|
||||
*response = chunk_alloc(values[0]->bv_len);
|
||||
memcpy(response->ptr, values[0]->bv_val, response->len);
|
||||
success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("LDAP response contains no values");
|
||||
}
|
||||
ldap_value_free_len(values);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("getting LDAP values failed: %s",
|
||||
ldap_err2string(ldap_result2error(ldap, entry, 0)));
|
||||
}
|
||||
ldap_memfree(attr);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("finding LDAP attributes failed: %s",
|
||||
ldap_err2string(ldap_result2error(ldap, entry, 0)));
|
||||
}
|
||||
ber_free(ber, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("finding first LDAP entry failed: %s",
|
||||
ldap_err2string(ldap_result2error(ldap, entry, 0)));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
static status_t fetch(private_ldap_fetcher_t *this, char *url,
|
||||
chunk_t *result, va_list args)
|
||||
{
|
||||
LDAP *ldap;
|
||||
LDAPURLDesc *lurl;
|
||||
LDAPMessage *msg;
|
||||
int res;
|
||||
int ldap_version = LDAP_VERSION3;
|
||||
struct timeval timeout;
|
||||
status_t status = FAILED;
|
||||
|
||||
if (!strneq(url, "ldap", 4))
|
||||
{
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
if (ldap_url_parse(url, &lurl) != LDAP_SUCCESS)
|
||||
{
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
ldap = ldap_init(lurl->lud_host, lurl->lud_port);
|
||||
if (ldap == NULL)
|
||||
{
|
||||
DBG1("LDAP initialization failed: %s", strerror(errno));
|
||||
ldap_free_urldesc(lurl);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
timeout.tv_sec = this->timeout;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
|
||||
ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
|
||||
|
||||
DBG1("sending LDAP request to '%s'...", url);
|
||||
|
||||
res = ldap_simple_bind_s(ldap, NULL, NULL);
|
||||
if (res == LDAP_SUCCESS)
|
||||
{
|
||||
res = ldap_search_st(ldap, lurl->lud_dn, lurl->lud_scope,
|
||||
lurl->lud_filter, lurl->lud_attrs,
|
||||
0, &timeout, &msg);
|
||||
|
||||
if (res == LDAP_SUCCESS)
|
||||
{
|
||||
if (parse(ldap, msg, result))
|
||||
{
|
||||
status = SUCCESS;
|
||||
}
|
||||
ldap_msgfree(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("LDAP search failed: %s", ldap_err2string(res));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("LDAP bind to '%s' failed: %s", url, ldap_err2string(res));
|
||||
}
|
||||
ldap_unbind_s(ldap);
|
||||
ldap_free_urldesc(lurl);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of fetcher_t.set_option.
|
||||
*/
|
||||
static bool set_option(private_ldap_fetcher_t *this, fetcher_option_t option, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, option);
|
||||
switch (option)
|
||||
{
|
||||
case FETCH_TIMEOUT:
|
||||
{
|
||||
this->timeout = va_arg(args, u_int);
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ldap_fetcher_t.destroy
|
||||
*/
|
||||
static void destroy(private_ldap_fetcher_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
ldap_fetcher_t *ldap_fetcher_create()
|
||||
{
|
||||
private_ldap_fetcher_t *this = malloc_thing(private_ldap_fetcher_t);
|
||||
|
||||
this->public.interface.fetch = (status_t(*)(fetcher_t*,char*,chunk_t*))fetch;
|
||||
this->public.interface.set_option = (bool(*)(fetcher_t*, fetcher_option_t option, ...))set_option;
|
||||
this->public.interface.destroy = (void (*)(fetcher_t*))destroy;
|
||||
|
||||
this->timeout = DEFAULT_TIMEOUT;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ldap_fetcher ldap_fetcher
|
||||
* @{ @ingroup ldap_p
|
||||
*/
|
||||
|
||||
#ifndef LDAP_FETCHER_H_
|
||||
#define LDAP_FETCHER_H_
|
||||
|
||||
typedef struct ldap_fetcher_t ldap_fetcher_t;
|
||||
|
||||
/**
|
||||
* Fetcher implementation using OpenLDAP.
|
||||
*/
|
||||
struct ldap_fetcher_t {
|
||||
|
||||
/**
|
||||
* Implements fetcher interface
|
||||
*/
|
||||
fetcher_t interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a ldap_fetcher instance.
|
||||
*/
|
||||
ldap_fetcher_t *ldap_fetcher_create();
|
||||
|
||||
#endif /* LDAP_FETCHER_H_ @}*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "ldap_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "ldap_fetcher.h"
|
||||
|
||||
typedef struct private_ldap_plugin_t private_ldap_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of ldap_plugin
|
||||
*/
|
||||
struct private_ldap_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
ldap_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of ldap_plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_ldap_plugin_t *this)
|
||||
{
|
||||
lib->fetcher->remove_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)ldap_fetcher_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_ldap_plugin_t *this = malloc_thing(private_ldap_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->fetcher->add_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)ldap_fetcher_create, "ldap://");
|
||||
lib->fetcher->add_fetcher(lib->fetcher,
|
||||
(fetcher_constructor_t)ldap_fetcher_create, "ldaps://");
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ldap_p ldap
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup ldap_plugin ldap_plugin
|
||||
* @{ @ingroup ldap_p
|
||||
*/
|
||||
|
||||
#ifndef LDAP_PLUGIN_H_
|
||||
#define LDAP_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct ldap_plugin_t ldap_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing LDAP fetcher using OpenLDAP.
|
||||
*/
|
||||
struct ldap_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a ldap_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* LDAP_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-md5.la
|
||||
|
||||
libstrongswan_md5_la_SOURCES = md5_plugin.h md5_plugin.c md5_hasher.c md5_hasher.h
|
||||
libstrongswan_md5_la_LDFLAGS = -module
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
|
||||
* Ported to fulfill hasher_t interface.
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "md5_hasher.h"
|
||||
|
||||
|
||||
/* Constants for MD5Transform routine. */
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
static u_int8_t PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* ugly macro stuff
|
||||
*/
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation.
|
||||
*/
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct private_md5_hasher_t private_md5_hasher_t;
|
||||
|
||||
/**
|
||||
* Private data structure with hasing context.
|
||||
*/
|
||||
struct private_md5_hasher_t {
|
||||
/**
|
||||
* Public interface for this hasher.
|
||||
*/
|
||||
md5_hasher_t public;
|
||||
|
||||
/*
|
||||
* State of the hasher.
|
||||
*/
|
||||
u_int32_t state[5];
|
||||
u_int32_t count[2];
|
||||
u_int8_t buffer[64];
|
||||
};
|
||||
|
||||
|
||||
#if BYTE_ORDER != LITTLE_ENDIAN
|
||||
|
||||
/* Encodes input (u_int32_t) into output (u_int8_t). Assumes len is
|
||||
* a multiple of 4.
|
||||
*/
|
||||
static void Encode (u_int8_t *output, u_int32_t *input, size_t len)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
{
|
||||
output[j] = (u_int8_t)(input[i] & 0xff);
|
||||
output[j+1] = (u_int8_t)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (u_int8_t)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (u_int8_t)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes input (u_int8_t) into output (u_int32_t). Assumes len is
|
||||
* a multiple of 4.
|
||||
*/
|
||||
static void Decode(u_int32_t *output, u_int8_t *input, size_t len)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
{
|
||||
output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) |
|
||||
(((u_int32_t)input[j+2]) << 16) | (((u_int32_t)input[j+3]) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define Encode memcpy
|
||||
#define Decode memcpy
|
||||
#endif
|
||||
|
||||
/* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static void MD5Transform(u_int32_t state[4], u_int8_t block[64])
|
||||
{
|
||||
u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode(x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
|
||||
/* MD5 block update operation. Continues an MD5 message-digest
|
||||
* operation, processing another message block, and updating the
|
||||
* context.
|
||||
*/
|
||||
static void MD5Update(private_md5_hasher_t *this, u_int8_t *input, size_t inputLen)
|
||||
{
|
||||
u_int32_t i;
|
||||
size_t index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (u_int8_t)((this->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((this->count[0] += (inputLen << 3)) < (inputLen << 3))
|
||||
{
|
||||
this->count[1]++;
|
||||
}
|
||||
this->count[1] += (inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible. */
|
||||
if (inputLen >= partLen)
|
||||
{
|
||||
memcpy(&this->buffer[index], input, partLen);
|
||||
MD5Transform (this->state, this->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
{
|
||||
MD5Transform (this->state, &input[i]);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
|
||||
/* Buffer remaining input */
|
||||
memcpy(&this->buffer[index], &input[i], inputLen-i);
|
||||
}
|
||||
|
||||
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
* the message digest and zeroizing the context.
|
||||
*/
|
||||
static void MD5Final (private_md5_hasher_t *this, u_int8_t digest[16])
|
||||
{
|
||||
u_int8_t bits[8];
|
||||
size_t index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode (bits, this->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64. */
|
||||
index = (size_t)((this->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
MD5Update (this, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD5Update (this, bits, 8);
|
||||
|
||||
if (digest != NULL) /* Bill Simpson's padding */
|
||||
{
|
||||
/* store state in digest */
|
||||
Encode (digest, this->state, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash.
|
||||
*/
|
||||
static void get_hash(private_md5_hasher_t *this, chunk_t chunk, u_int8_t *buffer)
|
||||
{
|
||||
MD5Update(this, chunk.ptr, chunk.len);
|
||||
if (buffer != NULL)
|
||||
{
|
||||
MD5Final(this, buffer);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.allocate_hash.
|
||||
*/
|
||||
static void allocate_hash(private_md5_hasher_t *this, chunk_t chunk, chunk_t *hash)
|
||||
{
|
||||
chunk_t allocated_hash;
|
||||
|
||||
MD5Update(this, chunk.ptr, chunk.len);
|
||||
if (hash != NULL)
|
||||
{
|
||||
allocated_hash.ptr = malloc(HASH_SIZE_MD5);
|
||||
allocated_hash.len = HASH_SIZE_MD5;
|
||||
|
||||
MD5Final(this, allocated_hash.ptr);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
|
||||
*hash = allocated_hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash_size.
|
||||
*/
|
||||
static size_t get_hash_size(private_md5_hasher_t *this)
|
||||
{
|
||||
return HASH_SIZE_MD5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.reset.
|
||||
*/
|
||||
static void reset(private_md5_hasher_t *this)
|
||||
{
|
||||
this->state[0] = 0x67452301;
|
||||
this->state[1] = 0xefcdab89;
|
||||
this->state[2] = 0x98badcfe;
|
||||
this->state[3] = 0x10325476;
|
||||
this->count[0] = 0;
|
||||
this->count[1] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.destroy.
|
||||
*/
|
||||
static void destroy(private_md5_hasher_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
md5_hasher_t *md5_hasher_create(hash_algorithm_t algo)
|
||||
{
|
||||
private_md5_hasher_t *this;
|
||||
|
||||
if (algo != HASH_MD5)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
this = malloc_thing(private_md5_hasher_t);
|
||||
|
||||
this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash;
|
||||
this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
|
||||
this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
|
||||
this->public.hasher_interface.reset = (void (*) (hasher_t*))reset;
|
||||
this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy;
|
||||
|
||||
/* initialize */
|
||||
reset(this);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup md5_hasher md5_hasher
|
||||
* @{ @ingroup md5_p
|
||||
*/
|
||||
|
||||
#ifndef MD5_HASHER_H_
|
||||
#define MD5_HASHER_H_
|
||||
|
||||
typedef struct md5_hasher_t md5_hasher_t;
|
||||
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t interface using the MD5 algorithm.
|
||||
*/
|
||||
struct md5_hasher_t {
|
||||
|
||||
/**
|
||||
* Generic hasher_t interface for this hasher.
|
||||
*/
|
||||
hasher_t hasher_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new md5_hasher_t.
|
||||
*
|
||||
* @param algo hash algorithm, must be HASH_MD5
|
||||
* @return md5_hasher_t object, NULL if not supported
|
||||
*/
|
||||
md5_hasher_t *md5_hasher_create(hash_algorithm_t algo);
|
||||
|
||||
#endif /*MD5_HASHER_H_@}*/
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "md5_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "md5_hasher.h"
|
||||
|
||||
typedef struct private_md5_plugin_t private_md5_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of md5_plugin
|
||||
*/
|
||||
struct private_md5_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
md5_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of md5_plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_md5_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_hasher(lib->crypto,
|
||||
(hasher_constructor_t)md5_hasher_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_md5_plugin_t *this = malloc_thing(private_md5_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_hasher(lib->crypto, HASH_MD5,
|
||||
(hasher_constructor_t)md5_hasher_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup md5_p md5
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup md5_plugin md5_plugin
|
||||
* @{ @ingroup md5_p
|
||||
*/
|
||||
|
||||
#ifndef MD5_PLUGIN_H_
|
||||
#define MD5_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct md5_plugin_t md5_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing the MD5 hash algorithm in software.
|
||||
*/
|
||||
struct md5_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a md5_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* MD5_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-mysql.la
|
||||
|
||||
libstrongswan_mysql_la_SOURCES = mysql_plugin.h mysql_plugin.c \
|
||||
mysql_database.h mysql_database.c
|
||||
libstrongswan_mysql_la_LDFLAGS = -module
|
||||
libstrongswan_mysql_la_LIBADD = -lmysqlclient_r
|
||||
|
||||
@@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
#include "mysql_database.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include <utils/mutex.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
|
||||
typedef struct private_mysql_database_t private_mysql_database_t;
|
||||
|
||||
/**
|
||||
* private data of mysql_database
|
||||
*/
|
||||
struct private_mysql_database_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
mysql_database_t public;
|
||||
|
||||
/**
|
||||
* connection pool, contains conn_t
|
||||
*/
|
||||
linked_list_t *pool;
|
||||
|
||||
/**
|
||||
* mutex to lock pool
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
|
||||
/**
|
||||
* hostname to connect to
|
||||
*/
|
||||
char *host;
|
||||
|
||||
/**
|
||||
* username to use
|
||||
*/
|
||||
char *username;
|
||||
|
||||
/**
|
||||
* password
|
||||
*/
|
||||
char *password;
|
||||
|
||||
/**
|
||||
* database name
|
||||
*/
|
||||
char *database;
|
||||
|
||||
/**
|
||||
* tcp port
|
||||
*/
|
||||
int port;
|
||||
};
|
||||
|
||||
typedef struct conn_t conn_t;
|
||||
|
||||
/**
|
||||
* connection pool entry
|
||||
*/
|
||||
struct conn_t {
|
||||
|
||||
/**
|
||||
* MySQL database connection
|
||||
*/
|
||||
MYSQL *mysql;
|
||||
|
||||
/**
|
||||
* connection in use?
|
||||
*/
|
||||
bool in_use;
|
||||
};
|
||||
|
||||
/**
|
||||
* Release a mysql connection
|
||||
*/
|
||||
static void conn_release(conn_t *conn)
|
||||
{
|
||||
conn->in_use = FALSE;
|
||||
}
|
||||
/**
|
||||
* thread specific initialization flag
|
||||
*/
|
||||
pthread_key_t initialized;
|
||||
|
||||
/**
|
||||
* Initialize a thread for mysql usage
|
||||
*/
|
||||
static void thread_initialize()
|
||||
{
|
||||
if (pthread_getspecific(initialized) == NULL)
|
||||
{
|
||||
pthread_setspecific(initialized, (void*)TRUE);
|
||||
mysql_thread_init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mysql library initialization function
|
||||
*/
|
||||
bool mysql_database_init()
|
||||
{
|
||||
if (mysql_library_init(0, NULL, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (pthread_key_create(&initialized, (void*)mysql_thread_end))
|
||||
{
|
||||
mysql_library_end();
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* mysql library cleanup function
|
||||
*/
|
||||
void mysql_database_deinit()
|
||||
{
|
||||
pthread_key_delete(initialized);
|
||||
mysql_thread_end();
|
||||
/* mysql_library_end(); would be the clean way, however, it hangs... */
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a mysql connection
|
||||
*/
|
||||
static void conn_destroy(conn_t *this)
|
||||
{
|
||||
mysql_close(this->mysql);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire/Reuse a mysql connection
|
||||
*/
|
||||
static conn_t *conn_get(private_mysql_database_t *this)
|
||||
{
|
||||
conn_t *current, *found = NULL;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
thread_initialize();
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
this->mutex->lock(this->mutex);
|
||||
enumerator = this->pool->create_enumerator(this->pool);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
if (!current->in_use)
|
||||
{
|
||||
found = current;
|
||||
found->in_use = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->mutex->unlock(this->mutex);
|
||||
if (found)
|
||||
{ /* check connection if found, release if ping fails */
|
||||
if (mysql_ping(found->mysql) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
this->mutex->lock(this->mutex);
|
||||
this->pool->remove(this->pool, found, NULL);
|
||||
this->mutex->unlock(this->mutex);
|
||||
conn_destroy(found);
|
||||
found = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (found == NULL)
|
||||
{
|
||||
found = malloc_thing(conn_t);
|
||||
found->in_use = TRUE;
|
||||
found->mysql = mysql_init(NULL);
|
||||
if (!mysql_real_connect(found->mysql, this->host, this->username,
|
||||
this->password, this->database, this->port,
|
||||
NULL, 0))
|
||||
{
|
||||
DBG1("connecting to mysql://%s:***@%s:%d/%s failed: %s",
|
||||
this->username, this->host, this->port, this->database,
|
||||
mysql_error(found->mysql));
|
||||
conn_destroy(found);
|
||||
found = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->mutex->lock(this->mutex);
|
||||
this->pool->insert_last(this->pool, found);
|
||||
DBG1("increased MySQL connection pool size to %d",
|
||||
this->pool->get_count(this->pool));
|
||||
this->mutex->unlock(this->mutex);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and run a MySQL stmt using a sql string and args
|
||||
*/
|
||||
static MYSQL_STMT* run(MYSQL *mysql, char *sql, va_list *args)
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
int params;
|
||||
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (stmt == NULL)
|
||||
{
|
||||
DBG1("creating MySQL statement failed: %s", mysql_error(mysql));
|
||||
return NULL;
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
|
||||
{
|
||||
DBG1("preparing MySQL statement failed: %s", mysql_stmt_error(stmt));
|
||||
mysql_stmt_close(stmt);
|
||||
return NULL;
|
||||
}
|
||||
params = mysql_stmt_param_count(stmt);
|
||||
if (params > 0)
|
||||
{
|
||||
int i;
|
||||
MYSQL_BIND *bind;
|
||||
|
||||
bind = alloca(sizeof(MYSQL_BIND) * params);
|
||||
memset(bind, 0, sizeof(MYSQL_BIND) * params);
|
||||
|
||||
for (i = 0; i < params; i++)
|
||||
{
|
||||
switch (va_arg(*args, db_type_t))
|
||||
{
|
||||
case DB_INT:
|
||||
{
|
||||
bind[i].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[i].buffer = (char*)alloca(sizeof(int));
|
||||
*(int*)bind[i].buffer = va_arg(*args, int);
|
||||
bind[i].buffer_length = sizeof(int);
|
||||
break;
|
||||
}
|
||||
case DB_UINT:
|
||||
{
|
||||
bind[i].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[i].buffer = (char*)alloca(sizeof(u_int));
|
||||
*(u_int*)bind[i].buffer = va_arg(*args, u_int);
|
||||
bind[i].buffer_length = sizeof(u_int);
|
||||
bind[i].is_unsigned = TRUE;
|
||||
break;
|
||||
}
|
||||
case DB_TEXT:
|
||||
{
|
||||
bind[i].buffer_type = MYSQL_TYPE_STRING;;
|
||||
bind[i].buffer = va_arg(*args, char*);
|
||||
bind[i].buffer_length = strlen(bind[i].buffer);
|
||||
break;
|
||||
}
|
||||
case DB_BLOB:
|
||||
{
|
||||
chunk_t chunk = va_arg(*args, chunk_t);
|
||||
bind[i].buffer_type = MYSQL_TYPE_BLOB;
|
||||
bind[i].buffer = chunk.ptr;
|
||||
bind[i].buffer_length = chunk.len;
|
||||
break;
|
||||
}
|
||||
case DB_DOUBLE:
|
||||
{
|
||||
bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
|
||||
bind[i].buffer = (char*)alloca(sizeof(double));
|
||||
*(double*)bind[i].buffer = va_arg(*args, double);
|
||||
bind[i].buffer_length = sizeof(double);
|
||||
break;
|
||||
}
|
||||
case DB_NULL:
|
||||
{
|
||||
bind[i].buffer_type = MYSQL_TYPE_NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1("invalid data type supplied");
|
||||
mysql_stmt_close(stmt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (mysql_stmt_bind_param(stmt, bind))
|
||||
{
|
||||
DBG1("binding MySQL param failed: %s", mysql_stmt_error(stmt));
|
||||
mysql_stmt_close(stmt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (mysql_stmt_execute(stmt))
|
||||
{
|
||||
DBG1("executing MySQL statement failed: %s", mysql_stmt_error(stmt));
|
||||
mysql_stmt_close(stmt);
|
||||
return NULL;
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
/** implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/** associated MySQL statement */
|
||||
MYSQL_STMT *stmt;
|
||||
/** result bindings */
|
||||
MYSQL_BIND *bind;
|
||||
/** pooled connection handle */
|
||||
conn_t *conn;
|
||||
/** value for INT, UINT, double */
|
||||
union {
|
||||
void *p_void;;
|
||||
int *p_int;
|
||||
u_int *p_uint;
|
||||
double *p_double;
|
||||
} val;
|
||||
/* length for TEXT and BLOB */
|
||||
unsigned long *length;
|
||||
} mysql_enumerator_t;
|
||||
|
||||
/**
|
||||
* create a mysql enumerator
|
||||
*/
|
||||
static void mysql_enumerator_destroy(mysql_enumerator_t *this)
|
||||
{
|
||||
int columns, i;
|
||||
|
||||
columns = mysql_stmt_field_count(this->stmt);
|
||||
|
||||
for (i = 0; i < columns; i++)
|
||||
{
|
||||
switch (this->bind[i].buffer_type)
|
||||
{
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
{
|
||||
free(this->bind[i].buffer);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
mysql_stmt_close(this->stmt);
|
||||
conn_release(this->conn);
|
||||
free(this->bind);
|
||||
free(this->val.p_void);
|
||||
free(this->length);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database.query().enumerate
|
||||
*/
|
||||
static bool mysql_enumerator_enumerate(mysql_enumerator_t *this, ...)
|
||||
{
|
||||
int i, columns;
|
||||
va_list args;
|
||||
|
||||
columns = mysql_stmt_field_count(this->stmt);
|
||||
|
||||
/* free/reset data set of previous call */
|
||||
for (i = 0; i < columns; i++)
|
||||
{
|
||||
switch (this->bind[i].buffer_type)
|
||||
{
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
{
|
||||
free(this->bind[i].buffer);
|
||||
this->bind[i].buffer = NULL;
|
||||
this->bind[i].buffer_length = 0;
|
||||
this->bind[i].length = &this->length[i];
|
||||
this->length[i] = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mysql_stmt_fetch(this->stmt))
|
||||
{
|
||||
case 0:
|
||||
case MYSQL_DATA_TRUNCATED:
|
||||
break;
|
||||
case MYSQL_NO_DATA:
|
||||
return FALSE;
|
||||
default:
|
||||
DBG1("fetching MySQL row failed: %s", mysql_stmt_error(this->stmt));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
va_start(args, this);
|
||||
for (i = 0; i < columns; i++)
|
||||
{
|
||||
switch (this->bind[i].buffer_type)
|
||||
{
|
||||
case MYSQL_TYPE_LONG:
|
||||
{
|
||||
if (this->bind[i].is_unsigned)
|
||||
{
|
||||
u_int *value = va_arg(args, u_int*);
|
||||
*value = this->val.p_uint[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
int *value = va_arg(args, int*);
|
||||
*value = this->val.p_int[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MYSQL_TYPE_STRING:
|
||||
{
|
||||
char **value = va_arg(args, char**);
|
||||
this->bind[i].buffer = malloc(this->length[i]+1);
|
||||
this->bind[i].buffer_length = this->length[i];
|
||||
*value = this->bind[i].buffer;
|
||||
mysql_stmt_fetch_column(this->stmt, &this->bind[i], i, 0);
|
||||
((char*)this->bind[i].buffer)[this->length[i]] = '\0';
|
||||
break;
|
||||
}
|
||||
case MYSQL_TYPE_BLOB:
|
||||
{
|
||||
chunk_t *value = va_arg(args, chunk_t*);
|
||||
this->bind[i].buffer = malloc(this->length[i]);
|
||||
this->bind[i].buffer_length = this->length[i];
|
||||
value->ptr = this->bind[i].buffer;
|
||||
value->len = this->length[i];
|
||||
mysql_stmt_fetch_column(this->stmt, &this->bind[i], i, 0);
|
||||
break;
|
||||
}
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
{
|
||||
double *value = va_arg(args, double*);
|
||||
*value = this->val.p_double[i];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database_t.query.
|
||||
*/
|
||||
static enumerator_t* query(private_mysql_database_t *this, char *sql, ...)
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
va_list args;
|
||||
mysql_enumerator_t *enumerator = NULL;
|
||||
conn_t *conn;
|
||||
|
||||
conn = conn_get(this);
|
||||
if (!conn)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start(args, sql);
|
||||
stmt = run(conn->mysql, sql, &args);
|
||||
if (stmt)
|
||||
{
|
||||
int columns, i;
|
||||
|
||||
enumerator = malloc_thing(mysql_enumerator_t);
|
||||
enumerator->public.enumerate = (void*)mysql_enumerator_enumerate;
|
||||
enumerator->public.destroy = (void*)mysql_enumerator_destroy;
|
||||
enumerator->stmt = stmt;
|
||||
enumerator->conn = conn;
|
||||
columns = mysql_stmt_field_count(stmt);
|
||||
enumerator->bind = calloc(columns, sizeof(MYSQL_BIND));
|
||||
enumerator->length = calloc(columns, sizeof(unsigned long));
|
||||
enumerator->val.p_void = calloc(columns, sizeof(enumerator->val));
|
||||
for (i = 0; i < columns; i++)
|
||||
{
|
||||
switch (va_arg(args, db_type_t))
|
||||
{
|
||||
case DB_INT:
|
||||
{
|
||||
enumerator->bind[i].buffer_type = MYSQL_TYPE_LONG;
|
||||
enumerator->bind[i].buffer = (char*)&enumerator->val.p_int[i];
|
||||
break;
|
||||
}
|
||||
case DB_UINT:
|
||||
{
|
||||
enumerator->bind[i].buffer_type = MYSQL_TYPE_LONG;
|
||||
enumerator->bind[i].buffer = (char*)&enumerator->val.p_uint[i];
|
||||
enumerator->bind[i].is_unsigned = TRUE;
|
||||
break;
|
||||
}
|
||||
case DB_TEXT:
|
||||
{
|
||||
enumerator->bind[i].buffer_type = MYSQL_TYPE_STRING;
|
||||
enumerator->bind[i].length = &enumerator->length[i];
|
||||
break;
|
||||
}
|
||||
case DB_BLOB:
|
||||
{
|
||||
enumerator->bind[i].buffer_type = MYSQL_TYPE_BLOB;
|
||||
enumerator->bind[i].length = &enumerator->length[i];
|
||||
break;
|
||||
}
|
||||
case DB_DOUBLE:
|
||||
{
|
||||
enumerator->bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
|
||||
enumerator->bind[i].buffer = (char*)&enumerator->val.p_double[i];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1("invalid result data type supplied");
|
||||
mysql_enumerator_destroy(enumerator);
|
||||
va_end(args);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (mysql_stmt_bind_result(stmt, enumerator->bind))
|
||||
{
|
||||
DBG1("binding MySQL result failed: %s", mysql_stmt_error(stmt));
|
||||
mysql_enumerator_destroy(enumerator);
|
||||
enumerator = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
conn_release(conn);
|
||||
}
|
||||
va_end(args);
|
||||
return (enumerator_t*)enumerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database_t.execute.
|
||||
*/
|
||||
static int execute(private_mysql_database_t *this, int *rowid, char *sql, ...)
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
va_list args;
|
||||
conn_t *conn;
|
||||
int affected = -1;
|
||||
|
||||
conn = conn_get(this);
|
||||
if (!conn)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
va_start(args, sql);
|
||||
stmt = run(conn->mysql, sql, &args);
|
||||
if (stmt)
|
||||
{
|
||||
if (rowid)
|
||||
{
|
||||
*rowid = mysql_stmt_insert_id(stmt);
|
||||
}
|
||||
affected = mysql_stmt_affected_rows(stmt);
|
||||
mysql_stmt_close(stmt);
|
||||
}
|
||||
va_end(args);
|
||||
conn_release(conn);
|
||||
return affected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database_t.destroy
|
||||
*/
|
||||
static void destroy(private_mysql_database_t *this)
|
||||
{
|
||||
this->pool->destroy_function(this->pool, (void*)conn_destroy);
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this->host);
|
||||
free(this->username);
|
||||
free(this->password);
|
||||
free(this->database);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static bool parse_uri(private_mysql_database_t *this, char *uri)
|
||||
{
|
||||
char *username, *password, *host, *port = "0", *database, *pos;
|
||||
|
||||
/**
|
||||
* parse mysql://username:pass@host:port/database uri
|
||||
*/
|
||||
username = strdupa(uri + 8);
|
||||
pos = strchr(username, ':');
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
password = pos + 1;
|
||||
pos = strrchr(password, '@');
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
host = pos + 1;
|
||||
pos = strrchr(host, ':');
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
port = pos + 1;
|
||||
pos = strchr(port, '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = strchr(host, '/');
|
||||
}
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
database = pos + 1;
|
||||
|
||||
this->host = strdup(host);
|
||||
this->username = strdup(username);
|
||||
this->password = strdup(password);
|
||||
this->database = strdup(database);
|
||||
this->port = atoi(port);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBG1("parsing MySQL database uri '%s' failed", uri);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
mysql_database_t *mysql_database_create(char *uri)
|
||||
{
|
||||
conn_t *conn;
|
||||
private_mysql_database_t *this;
|
||||
|
||||
if (!strneq(uri, "mysql://", 8))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_mysql_database_t);
|
||||
|
||||
this->public.db.query = (enumerator_t* (*)(database_t *this, char *sql, ...))query;
|
||||
this->public.db.execute = (int (*)(database_t *this, int *rowid, char *sql, ...))execute;
|
||||
this->public.db.destroy = (void(*)(database_t*))destroy;
|
||||
|
||||
if (!parse_uri(this, uri))
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
this->mutex = mutex_create(MUTEX_DEFAULT);
|
||||
this->pool = linked_list_create();
|
||||
|
||||
/* check connectivity */
|
||||
conn = conn_get(this);
|
||||
if (!conn)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
conn_release(conn);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup mysql_database mysql_database
|
||||
* @{ @ingroup mysql_p
|
||||
*/
|
||||
|
||||
#ifndef MYSQL_DATABASE_H_
|
||||
#define MYSQL_DATABASE_H_
|
||||
|
||||
#include <database/database.h>
|
||||
|
||||
typedef struct mysql_database_t mysql_database_t;
|
||||
|
||||
/**
|
||||
* MySQL databse_t implementation.
|
||||
*/
|
||||
struct mysql_database_t {
|
||||
|
||||
/**
|
||||
* Implements database_t
|
||||
*/
|
||||
database_t db;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a mysql_database instance.
|
||||
*
|
||||
* @param uri connection URI, mysql://user:pass@host:port/database
|
||||
*/
|
||||
mysql_database_t *mysql_database_create(char *uri);
|
||||
|
||||
/**
|
||||
* MySQL client library initialization function
|
||||
*
|
||||
* @return FALSE if initialization failed
|
||||
*/
|
||||
bool mysql_database_init();
|
||||
|
||||
/**
|
||||
* Mysql client library cleanup function
|
||||
*/
|
||||
void mysql_database_deinit();
|
||||
|
||||
#endif /* MYSQL_DATABASE_H_ @}*/
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "mysql_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include "mysql_database.h"
|
||||
|
||||
typedef struct private_mysql_plugin_t private_mysql_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of mysql_plugin
|
||||
*/
|
||||
struct private_mysql_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
mysql_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_mysql_plugin_t *this)
|
||||
{
|
||||
lib->db->remove_database(lib->db,
|
||||
(database_constructor_t)mysql_database_create);
|
||||
mysql_database_deinit();
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_mysql_plugin_t *this;
|
||||
|
||||
if (!mysql_database_init())
|
||||
{
|
||||
DBG1("MySQL client library initialization failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_mysql_plugin_t);
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->db->add_database(lib->db,
|
||||
(database_constructor_t)mysql_database_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup mysql_p mysql
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup mysql_plugin mysql_plugin
|
||||
* @{ @ingroup mysql_p
|
||||
*/
|
||||
|
||||
#ifndef MYSQL_PLUGIN_H_
|
||||
#define MYSQL_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct mysql_plugin_t mysql_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing mysql database connectivity.
|
||||
*/
|
||||
struct mysql_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a mysql_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* MYSQL_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup plugin plugin
|
||||
* @{ @ingroup plugins
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_H_
|
||||
#define PLUGIN_H_
|
||||
|
||||
typedef struct plugin_t plugin_t;
|
||||
|
||||
/**
|
||||
* Interface definition of a plugin.
|
||||
*/
|
||||
struct plugin_t {
|
||||
|
||||
/**
|
||||
* Destroy a plugin instance.
|
||||
*/
|
||||
void (*destroy)(plugin_t *this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Plugin constructor function definiton.
|
||||
*
|
||||
* Each plugin has a constructor functions. This function is called on daemon
|
||||
* startup to initialize each plugin.
|
||||
* The plugin function is named plugin_create().
|
||||
*
|
||||
* @return plugin_t instance
|
||||
*/
|
||||
typedef plugin_t *(*plugin_constructor_t)(void);
|
||||
|
||||
#endif /* PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "plugin_loader.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct private_plugin_loader_t private_plugin_loader_t;
|
||||
|
||||
/**
|
||||
* private data of plugin_loader
|
||||
*/
|
||||
struct private_plugin_loader_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
plugin_loader_t public;
|
||||
|
||||
/**
|
||||
* list of loaded plugins
|
||||
*/
|
||||
linked_list_t *plugins;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of plugin_loader_t.load_plugins.
|
||||
*/
|
||||
static int load(private_plugin_loader_t *this, char *path, char *prefix)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
char *file, *ending, *rel;
|
||||
void *handle;
|
||||
int count = 0;
|
||||
|
||||
enumerator = enumerator_create_directory(path);
|
||||
if (!enumerator)
|
||||
{
|
||||
DBG1("opening plugin directory %s failed", path);
|
||||
return 0;
|
||||
}
|
||||
DBG1("loading plugins from %s", path);
|
||||
while (enumerator->enumerate(enumerator, &rel, &file, NULL))
|
||||
{
|
||||
plugin_t *plugin;
|
||||
plugin_constructor_t constructor;
|
||||
|
||||
ending = file + strlen(file) - 3;
|
||||
if (ending <= file || !streq(ending, ".so"))
|
||||
{ /* only process .so libraries */
|
||||
continue;
|
||||
}
|
||||
if (!strneq(prefix, rel, strlen(prefix)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
handle = dlopen(file, RTLD_LAZY);
|
||||
if (handle == NULL)
|
||||
{
|
||||
DBG1("loading plugin %s failed: %s", rel, dlerror());
|
||||
continue;
|
||||
}
|
||||
constructor = dlsym(handle, "plugin_create");
|
||||
if (constructor == NULL)
|
||||
{
|
||||
DBG1("plugin %s has no plugin_create() function, skipped", rel);
|
||||
dlclose(handle);
|
||||
continue;
|
||||
}
|
||||
plugin = constructor();
|
||||
if (plugin == NULL)
|
||||
{
|
||||
DBG1("plugin %s constructor failed, skipping", rel);
|
||||
dlclose(handle);
|
||||
continue;
|
||||
}
|
||||
DBG1("plugin %s loaded successfully", rel);
|
||||
/* insert in front to destroy them in reverse order */
|
||||
this->plugins->insert_last(this->plugins, plugin);
|
||||
/* we do not store or free dlopen() handles, leak_detective requires
|
||||
* the modules to keep loaded until leak report */
|
||||
count++;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of plugin_loader_t.destroy
|
||||
*/
|
||||
static void destroy(private_plugin_loader_t *this)
|
||||
{
|
||||
this->plugins->destroy_offset(this->plugins, offsetof(plugin_t, destroy));
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_loader_t *plugin_loader_create()
|
||||
{
|
||||
private_plugin_loader_t *this = malloc_thing(private_plugin_loader_t);
|
||||
|
||||
this->public.load = (int(*)(plugin_loader_t*, char *path, char *prefix))load;
|
||||
this->public.destroy = (void(*)(plugin_loader_t*))destroy;
|
||||
|
||||
this->plugins = linked_list_create();
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup plugin_loader plugin_loader
|
||||
* @{ @ingroup plugin
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_LOADER_H_
|
||||
#define PLUGIN_LOADER_H_
|
||||
|
||||
typedef struct plugin_loader_t plugin_loader_t;
|
||||
|
||||
/**
|
||||
* The plugin_loader loads plugins from a directory and initializes them
|
||||
*/
|
||||
struct plugin_loader_t {
|
||||
|
||||
/**
|
||||
* Load plugins from a directory.
|
||||
*
|
||||
* @param path path containing loadable plugins
|
||||
* @param prefix prefix of plugin libraries to load
|
||||
* @return number of successfully loaded plugins
|
||||
*/
|
||||
int (*load)(plugin_loader_t *this, char *path, char *prefix);
|
||||
|
||||
/**
|
||||
* Unload loaded plugins, destroy plugin_loader instance.
|
||||
*/
|
||||
void (*destroy)(plugin_loader_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a plugin_loader instance.
|
||||
*
|
||||
* @return plugin loader instance
|
||||
*/
|
||||
plugin_loader_t *plugin_loader_create();
|
||||
|
||||
#endif /* PLUGIN_LOADER_H_ @}*/
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-sha1.la
|
||||
|
||||
libstrongswan_sha1_la_SOURCES = sha1_plugin.h sha1_plugin.c sha1_hasher.c sha1_hasher.h
|
||||
libstrongswan_sha1_la_LDFLAGS = -module
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* Ported from Steve Reid's <[email protected]> implementation
|
||||
* "SHA1 in C" found in strongSwan.
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "sha1_hasher.h"
|
||||
|
||||
/*
|
||||
* ugly macro stuff
|
||||
*/
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) |(rol(block->l[i],8)&0x00FF00FF))
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
#define blk0(i) block->l[i]
|
||||
#else
|
||||
#error "Endianness not defined!"
|
||||
#endif
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
|
||||
typedef struct private_sha1_hasher_t private_sha1_hasher_t;
|
||||
|
||||
/**
|
||||
* Private data structure with hasing context.
|
||||
*/
|
||||
struct private_sha1_hasher_t {
|
||||
/**
|
||||
* Public interface for this hasher.
|
||||
*/
|
||||
sha1_hasher_t public;
|
||||
|
||||
/**
|
||||
* implemented algorithm
|
||||
*/
|
||||
hash_algorithm_t algo;
|
||||
|
||||
/*
|
||||
* State of the hasher.
|
||||
*/
|
||||
u_int32_t state[5];
|
||||
u_int32_t count[2];
|
||||
u_int8_t buffer[64];
|
||||
};
|
||||
|
||||
/*
|
||||
* Hash a single 512-bit block. This is the core of the algorithm. *
|
||||
*/
|
||||
static void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
|
||||
{
|
||||
u_int32_t a, b, c, d, e;
|
||||
typedef union {
|
||||
u_int8_t c[64];
|
||||
u_int32_t l[16];
|
||||
} CHAR64LONG16;
|
||||
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
|
||||
memcpy(block, buffer, 64);
|
||||
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
memset(block, '\0', sizeof(block));
|
||||
}
|
||||
|
||||
/*
|
||||
* Run your data through this.
|
||||
*/
|
||||
static void SHA1Update(private_sha1_hasher_t* this, u_int8_t *data, u_int32_t len)
|
||||
{
|
||||
u_int32_t i;
|
||||
u_int32_t j;
|
||||
|
||||
j = this->count[0];
|
||||
if ((this->count[0] += len << 3) < j)
|
||||
{
|
||||
this->count[1]++;
|
||||
}
|
||||
this->count[1] += (len>>29);
|
||||
j = (j >> 3) & 63;
|
||||
if ((j + len) > 63)
|
||||
{
|
||||
memcpy(&this->buffer[j], data, (i = 64-j));
|
||||
SHA1Transform(this->state, this->buffer);
|
||||
for ( ; i + 63 < len; i += 64)
|
||||
{
|
||||
SHA1Transform(this->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
memcpy(&this->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add padding and return the message digest.
|
||||
*/
|
||||
static void SHA1Final(private_sha1_hasher_t *this, u_int8_t *digest)
|
||||
{
|
||||
u_int32_t i;
|
||||
u_int8_t finalcount[8];
|
||||
u_int8_t c;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
finalcount[i] = (u_int8_t)((this->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
c = 0200;
|
||||
SHA1Update(this, &c, 1);
|
||||
while ((this->count[0] & 504) != 448)
|
||||
{
|
||||
c = 0000;
|
||||
SHA1Update(this, &c, 1);
|
||||
}
|
||||
SHA1Update(this, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
digest[i] = (u_int8_t)((this->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.reset.
|
||||
*/
|
||||
static void reset(private_sha1_hasher_t *this)
|
||||
{
|
||||
this->state[0] = 0x67452301;
|
||||
this->state[1] = 0xEFCDAB89;
|
||||
this->state[2] = 0x98BADCFE;
|
||||
this->state[3] = 0x10325476;
|
||||
this->state[4] = 0xC3D2E1F0;
|
||||
this->count[0] = 0;
|
||||
this->count[1] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* copy hasher state to buf
|
||||
*/
|
||||
static void state_to_buf(private_sha1_hasher_t *this, u_int8_t *buffer)
|
||||
{
|
||||
u_int32_t *hash = (u_int32_t*)buffer;
|
||||
hash[0] = htonl(this->state[0]);
|
||||
hash[1] = htonl(this->state[1]);
|
||||
hash[2] = htonl(this->state[2]);
|
||||
hash[3] = htonl(this->state[3]);
|
||||
hash[4] = htonl(this->state[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash.
|
||||
*/
|
||||
static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer)
|
||||
{
|
||||
SHA1Update(this, chunk.ptr, chunk.len);
|
||||
if (buffer != NULL)
|
||||
{
|
||||
if (this->algo == HASH_SHA1_NOFINAL)
|
||||
{
|
||||
state_to_buf(this, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
SHA1Final(this, buffer);
|
||||
}
|
||||
reset(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.allocate_hash.
|
||||
*/
|
||||
static void allocate_hash(private_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash)
|
||||
{
|
||||
SHA1Update(this, chunk.ptr, chunk.len);
|
||||
if (hash != NULL)
|
||||
{
|
||||
hash->ptr = malloc(HASH_SIZE_SHA1);
|
||||
hash->len = HASH_SIZE_SHA1;
|
||||
|
||||
if (this->algo == HASH_SHA1_NOFINAL)
|
||||
{
|
||||
state_to_buf(this, hash->ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
SHA1Final(this, hash->ptr);
|
||||
}
|
||||
reset(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash_size.
|
||||
*/
|
||||
static size_t get_hash_size(private_sha1_hasher_t *this)
|
||||
{
|
||||
return HASH_SIZE_SHA1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.destroy.
|
||||
*/
|
||||
static void destroy(private_sha1_hasher_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo)
|
||||
{
|
||||
private_sha1_hasher_t *this;
|
||||
if (algo != HASH_SHA1 && algo != HASH_SHA1_NOFINAL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
this = malloc_thing(private_sha1_hasher_t);
|
||||
this->algo = algo;
|
||||
this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash;
|
||||
this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
|
||||
this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
|
||||
this->public.hasher_interface.reset = (void (*) (hasher_t*))reset;
|
||||
this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy;
|
||||
|
||||
/* initialize */
|
||||
reset(this);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sha1_hasher sha1_hasher
|
||||
* @{ @ingroup sha1_p
|
||||
*/
|
||||
|
||||
#ifndef SHA1_HASHER_H_
|
||||
#define SHA1_HASHER_H_
|
||||
|
||||
typedef struct sha1_hasher_t sha1_hasher_t;
|
||||
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t interface using the SHA1 algorithm.
|
||||
*/
|
||||
struct sha1_hasher_t {
|
||||
|
||||
/**
|
||||
* Implements hasher_t interface.
|
||||
*/
|
||||
hasher_t hasher_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new sha1_hasher_t.
|
||||
*
|
||||
* This implementation supports two algorithms, HASH_SHA1 and HASH_SHA1_NOFINAL
|
||||
*
|
||||
* @param algo algorithm
|
||||
* @return sha1_hasher_t object
|
||||
*/
|
||||
sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo);
|
||||
|
||||
#endif /*SHA1_HASHER_H_ @}*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "sha1_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "sha1_hasher.h"
|
||||
|
||||
typedef struct private_sha1_plugin_t private_sha1_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of sha1_plugin
|
||||
*/
|
||||
struct private_sha1_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
sha1_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of sha1_plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_sha1_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_hasher(lib->crypto,
|
||||
(hasher_constructor_t)sha1_hasher_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_sha1_plugin_t *this = malloc_thing(private_sha1_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_hasher(lib->crypto, HASH_SHA1,
|
||||
(hasher_constructor_t)sha1_hasher_create);
|
||||
lib->crypto->add_hasher(lib->crypto, HASH_SHA1_NOFINAL,
|
||||
(hasher_constructor_t)sha1_hasher_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sha1_p sha1
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup sha1_plugin sha1_plugin
|
||||
* @{ @ingroup sha1_p
|
||||
*/
|
||||
|
||||
#ifndef SHA1_PLUGIN_H_
|
||||
#define SHA1_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct sha1_plugin_t sha1_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing the SHA1 algorithm in software.
|
||||
*/
|
||||
struct sha1_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a sha1_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* SHA1_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-sha2.la
|
||||
|
||||
libstrongswan_sha2_la_SOURCES = sha2_plugin.h sha2_plugin.c sha2_hasher.c sha2_hasher.h
|
||||
libstrongswan_sha2_la_LDFLAGS = -module
|
||||
|
||||
@@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 2001 Jari Ruusu.
|
||||
*
|
||||
* Ported from strongSwans implementation written by Jari Ruusu.
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sha2_hasher.h"
|
||||
|
||||
|
||||
typedef struct private_sha512_hasher_t private_sha512_hasher_t;
|
||||
|
||||
/**
|
||||
* Private data structure with hasing context for SHA384 and SHA512
|
||||
*/
|
||||
struct private_sha512_hasher_t {
|
||||
/**
|
||||
* Public interface for this hasher.
|
||||
*/
|
||||
sha2_hasher_t public;
|
||||
|
||||
unsigned char sha_out[128]; /* results are here, bytes 0..47/0..63 */
|
||||
u_int64_t sha_H[8];
|
||||
u_int64_t sha_blocks;
|
||||
u_int64_t sha_blocksMSB;
|
||||
int sha_bufCnt;
|
||||
};
|
||||
|
||||
|
||||
typedef struct private_sha256_hasher_t private_sha256_hasher_t;
|
||||
|
||||
/**
|
||||
* Private data structure with hasing context for SHA256
|
||||
*/
|
||||
struct private_sha256_hasher_t {
|
||||
/**
|
||||
* Public interface for this hasher.
|
||||
*/
|
||||
sha2_hasher_t public;
|
||||
|
||||
unsigned char sha_out[64]; /* results are here, bytes 0...31 */
|
||||
u_int32_t sha_H[8];
|
||||
u_int64_t sha_blocks;
|
||||
int sha_bufCnt;
|
||||
};
|
||||
|
||||
|
||||
static const u_int32_t sha256_hashInit[8] = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
|
||||
0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
static const u_int32_t sha256_K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
static const u_int64_t sha512_hashInit[8] = {
|
||||
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
|
||||
0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
|
||||
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
|
||||
};
|
||||
|
||||
static const u_int64_t sha384_hashInit[8] = {
|
||||
0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL,
|
||||
0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
|
||||
0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL
|
||||
};
|
||||
|
||||
static const u_int64_t sha512_K[80] = {
|
||||
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
|
||||
0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
|
||||
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
|
||||
0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
|
||||
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
|
||||
0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
|
||||
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
|
||||
0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
|
||||
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
|
||||
0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
|
||||
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
|
||||
0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
|
||||
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
|
||||
0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
|
||||
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
|
||||
0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
|
||||
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
|
||||
0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
|
||||
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
|
||||
0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
|
||||
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
|
||||
0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
|
||||
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
|
||||
0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
|
||||
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
|
||||
0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
|
||||
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
|
||||
};
|
||||
|
||||
|
||||
/* set macros for SHA256 */
|
||||
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
|
||||
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define R(x,y) ((y) >> (x))
|
||||
|
||||
#define S(x,y) (((y) >> (x)) | ((y) << (32 - (x))))
|
||||
#define uSig0(x) ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x))))
|
||||
#define uSig1(x) ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x))))
|
||||
#define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x))))
|
||||
#define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x))))
|
||||
|
||||
/**
|
||||
* Single block SHA256 transformation
|
||||
*/
|
||||
static void sha256_transform(private_sha256_hasher_t *ctx,
|
||||
const unsigned char *datap)
|
||||
{
|
||||
register int j;
|
||||
u_int32_t a, b, c, d, e, f, g, h;
|
||||
u_int32_t T1, T2, W[64], Wm2, Wm15;
|
||||
|
||||
/* read the data, big endian byte order */
|
||||
j = 0;
|
||||
do {
|
||||
W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) |
|
||||
(((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3]));
|
||||
datap += 4;
|
||||
} while(++j < 16);
|
||||
|
||||
/* initialize variables a...h */
|
||||
a = ctx->sha_H[0];
|
||||
b = ctx->sha_H[1];
|
||||
c = ctx->sha_H[2];
|
||||
d = ctx->sha_H[3];
|
||||
e = ctx->sha_H[4];
|
||||
f = ctx->sha_H[5];
|
||||
g = ctx->sha_H[6];
|
||||
h = ctx->sha_H[7];
|
||||
|
||||
/* apply compression function */
|
||||
j = 0;
|
||||
do
|
||||
{
|
||||
if(j >= 16)
|
||||
{
|
||||
Wm2 = W[j - 2];
|
||||
Wm15 = W[j - 15];
|
||||
W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
|
||||
}
|
||||
T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j];
|
||||
T2 = uSig0(a) + Maj(a,b,c);
|
||||
h = g; g = f; f = e;
|
||||
e = d + T1;
|
||||
d = c; c = b; b = a;
|
||||
a = T1 + T2;
|
||||
} while(++j < 64);
|
||||
|
||||
/* compute intermediate hash value */
|
||||
ctx->sha_H[0] += a;
|
||||
ctx->sha_H[1] += b;
|
||||
ctx->sha_H[2] += c;
|
||||
ctx->sha_H[3] += d;
|
||||
ctx->sha_H[4] += e;
|
||||
ctx->sha_H[5] += f;
|
||||
ctx->sha_H[6] += g;
|
||||
ctx->sha_H[7] += h;
|
||||
|
||||
ctx->sha_blocks++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update SHA256 hash
|
||||
*/
|
||||
static void sha256_write(private_sha256_hasher_t *ctx,
|
||||
const unsigned char *datap, int length)
|
||||
{
|
||||
while(length > 0)
|
||||
{
|
||||
if(!ctx->sha_bufCnt)
|
||||
{
|
||||
while(length >= sizeof(ctx->sha_out))
|
||||
{
|
||||
sha256_transform(ctx, datap);
|
||||
datap += sizeof(ctx->sha_out);
|
||||
length -= sizeof(ctx->sha_out);
|
||||
}
|
||||
if(!length) return;
|
||||
}
|
||||
ctx->sha_out[ctx->sha_bufCnt] = *datap++;
|
||||
length--;
|
||||
if(++ctx->sha_bufCnt == sizeof(ctx->sha_out))
|
||||
{
|
||||
sha256_transform(ctx, &ctx->sha_out[0]);
|
||||
ctx->sha_bufCnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* finalize SHA256 hash
|
||||
*/
|
||||
static void sha256_final(private_sha256_hasher_t *ctx)
|
||||
{
|
||||
register int j;
|
||||
u_int64_t bitLength;
|
||||
u_int32_t i;
|
||||
unsigned char padByte, *datap;
|
||||
|
||||
bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3);
|
||||
padByte = 0x80;
|
||||
sha256_write(ctx, &padByte, 1);
|
||||
|
||||
/* pad extra space with zeroes */
|
||||
padByte = 0;
|
||||
while(ctx->sha_bufCnt != 56)
|
||||
{
|
||||
sha256_write(ctx, &padByte, 1);
|
||||
}
|
||||
|
||||
/* write bit length, big endian byte order */
|
||||
ctx->sha_out[56] = bitLength >> 56;
|
||||
ctx->sha_out[57] = bitLength >> 48;
|
||||
ctx->sha_out[58] = bitLength >> 40;
|
||||
ctx->sha_out[59] = bitLength >> 32;
|
||||
ctx->sha_out[60] = bitLength >> 24;
|
||||
ctx->sha_out[61] = bitLength >> 16;
|
||||
ctx->sha_out[62] = bitLength >> 8;
|
||||
ctx->sha_out[63] = bitLength;
|
||||
sha256_transform(ctx, &ctx->sha_out[0]);
|
||||
|
||||
/* return results in ctx->sha_out[0...31] */
|
||||
datap = &ctx->sha_out[0];
|
||||
j = 0;
|
||||
do {
|
||||
i = ctx->sha_H[j];
|
||||
datap[0] = i >> 24;
|
||||
datap[1] = i >> 16;
|
||||
datap[2] = i >> 8;
|
||||
datap[3] = i;
|
||||
datap += 4;
|
||||
} while(++j < 8);
|
||||
}
|
||||
|
||||
/* update macros for SHA512 */
|
||||
#undef S
|
||||
#undef uSig0
|
||||
#undef uSig1
|
||||
#undef lSig0
|
||||
#undef lSig1
|
||||
#define S(x,y) (((y) >> (x)) | ((y) << (64 - (x))))
|
||||
#define uSig0(x) ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x))))
|
||||
#define uSig1(x) ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x))))
|
||||
#define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x))))
|
||||
#define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x))))
|
||||
|
||||
/**
|
||||
* Single block SHA384/SHA512 transformation
|
||||
*/
|
||||
static void sha512_transform(private_sha512_hasher_t *ctx,
|
||||
const unsigned char *datap)
|
||||
{
|
||||
register int j;
|
||||
u_int64_t a, b, c, d, e, f, g, h;
|
||||
u_int64_t T1, T2, W[80], Wm2, Wm15;
|
||||
|
||||
/* read the data, big endian byte order */
|
||||
j = 0;
|
||||
do {
|
||||
W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) |
|
||||
(((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) |
|
||||
(((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) |
|
||||
(((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7]));
|
||||
datap += 8;
|
||||
} while(++j < 16);
|
||||
|
||||
/* initialize variables a...h */
|
||||
a = ctx->sha_H[0];
|
||||
b = ctx->sha_H[1];
|
||||
c = ctx->sha_H[2];
|
||||
d = ctx->sha_H[3];
|
||||
e = ctx->sha_H[4];
|
||||
f = ctx->sha_H[5];
|
||||
g = ctx->sha_H[6];
|
||||
h = ctx->sha_H[7];
|
||||
|
||||
/* apply compression function */
|
||||
j = 0;
|
||||
do {
|
||||
if(j >= 16) {
|
||||
Wm2 = W[j - 2];
|
||||
Wm15 = W[j - 15];
|
||||
W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
|
||||
}
|
||||
T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j];
|
||||
T2 = uSig0(a) + Maj(a,b,c);
|
||||
h = g; g = f; f = e;
|
||||
e = d + T1;
|
||||
d = c; c = b; b = a;
|
||||
a = T1 + T2;
|
||||
} while(++j < 80);
|
||||
|
||||
/* compute intermediate hash value */
|
||||
ctx->sha_H[0] += a;
|
||||
ctx->sha_H[1] += b;
|
||||
ctx->sha_H[2] += c;
|
||||
ctx->sha_H[3] += d;
|
||||
ctx->sha_H[4] += e;
|
||||
ctx->sha_H[5] += f;
|
||||
ctx->sha_H[6] += g;
|
||||
ctx->sha_H[7] += h;
|
||||
|
||||
ctx->sha_blocks++;
|
||||
if(!ctx->sha_blocks) ctx->sha_blocksMSB++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a SHA384/SHA512 hash
|
||||
*/
|
||||
static void sha512_write(private_sha512_hasher_t *ctx,
|
||||
const unsigned char *datap, int length)
|
||||
{
|
||||
while(length > 0)
|
||||
{
|
||||
if(!ctx->sha_bufCnt)
|
||||
{
|
||||
while(length >= sizeof(ctx->sha_out))
|
||||
{
|
||||
sha512_transform(ctx, datap);
|
||||
datap += sizeof(ctx->sha_out);
|
||||
length -= sizeof(ctx->sha_out);
|
||||
}
|
||||
if(!length) return;
|
||||
}
|
||||
ctx->sha_out[ctx->sha_bufCnt] = *datap++;
|
||||
length--;
|
||||
if(++ctx->sha_bufCnt == sizeof(ctx->sha_out))
|
||||
{
|
||||
sha512_transform(ctx, &ctx->sha_out[0]);
|
||||
ctx->sha_bufCnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize a SHA384/SHA512 hash
|
||||
*/
|
||||
static void sha512_final(private_sha512_hasher_t *ctx)
|
||||
{
|
||||
register int j;
|
||||
u_int64_t bitLength, bitLengthMSB;
|
||||
u_int64_t i;
|
||||
unsigned char padByte, *datap;
|
||||
|
||||
bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3);
|
||||
bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54);
|
||||
padByte = 0x80;
|
||||
sha512_write(ctx, &padByte, 1);
|
||||
|
||||
/* pad extra space with zeroes */
|
||||
padByte = 0;
|
||||
while(ctx->sha_bufCnt != 112)
|
||||
{
|
||||
sha512_write(ctx, &padByte, 1);
|
||||
}
|
||||
|
||||
/* write bit length, big endian byte order */
|
||||
ctx->sha_out[112] = bitLengthMSB >> 56;
|
||||
ctx->sha_out[113] = bitLengthMSB >> 48;
|
||||
ctx->sha_out[114] = bitLengthMSB >> 40;
|
||||
ctx->sha_out[115] = bitLengthMSB >> 32;
|
||||
ctx->sha_out[116] = bitLengthMSB >> 24;
|
||||
ctx->sha_out[117] = bitLengthMSB >> 16;
|
||||
ctx->sha_out[118] = bitLengthMSB >> 8;
|
||||
ctx->sha_out[119] = bitLengthMSB;
|
||||
ctx->sha_out[120] = bitLength >> 56;
|
||||
ctx->sha_out[121] = bitLength >> 48;
|
||||
ctx->sha_out[122] = bitLength >> 40;
|
||||
ctx->sha_out[123] = bitLength >> 32;
|
||||
ctx->sha_out[124] = bitLength >> 24;
|
||||
ctx->sha_out[125] = bitLength >> 16;
|
||||
ctx->sha_out[126] = bitLength >> 8;
|
||||
ctx->sha_out[127] = bitLength;
|
||||
sha512_transform(ctx, &ctx->sha_out[0]);
|
||||
|
||||
/* return results in ctx->sha_out[0...63] */
|
||||
datap = &ctx->sha_out[0];
|
||||
j = 0;
|
||||
do {
|
||||
i = ctx->sha_H[j];
|
||||
datap[0] = i >> 56;
|
||||
datap[1] = i >> 48;
|
||||
datap[2] = i >> 40;
|
||||
datap[3] = i >> 32;
|
||||
datap[4] = i >> 24;
|
||||
datap[5] = i >> 16;
|
||||
datap[6] = i >> 8;
|
||||
datap[7] = i;
|
||||
datap += 8;
|
||||
} while(++j < 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash for SHA256.
|
||||
*/
|
||||
static void get_hash256(private_sha256_hasher_t *this,
|
||||
chunk_t chunk, u_int8_t *buffer)
|
||||
{
|
||||
sha256_write(this, chunk.ptr, chunk.len);
|
||||
if (buffer != NULL)
|
||||
{
|
||||
sha256_final(this);
|
||||
memcpy(buffer, this->sha_out, HASH_SIZE_SHA256);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash for SHA384.
|
||||
*/
|
||||
static void get_hash384(private_sha512_hasher_t *this,
|
||||
chunk_t chunk, u_int8_t *buffer)
|
||||
{
|
||||
sha512_write(this, chunk.ptr, chunk.len);
|
||||
if (buffer != NULL)
|
||||
{
|
||||
sha512_final(this);
|
||||
memcpy(buffer, this->sha_out, HASH_SIZE_SHA384);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash for SHA512.
|
||||
*/
|
||||
static void get_hash512(private_sha512_hasher_t *this,
|
||||
chunk_t chunk, u_int8_t *buffer)
|
||||
{
|
||||
sha512_write(this, chunk.ptr, chunk.len);
|
||||
if (buffer != NULL)
|
||||
{
|
||||
sha512_final(this);
|
||||
memcpy(buffer, this->sha_out, HASH_SIZE_SHA512);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.allocate_hash for SHA256.
|
||||
*/
|
||||
static void allocate_hash256(private_sha256_hasher_t *this,
|
||||
chunk_t chunk, chunk_t *hash)
|
||||
{
|
||||
chunk_t allocated_hash;
|
||||
|
||||
sha256_write(this, chunk.ptr, chunk.len);
|
||||
if (hash != NULL)
|
||||
{
|
||||
sha256_final(this);
|
||||
allocated_hash = chunk_alloc(HASH_SIZE_SHA256);
|
||||
memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA256);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
*hash = allocated_hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.allocate_hash for SHA384.
|
||||
*/
|
||||
static void allocate_hash384(private_sha512_hasher_t *this,
|
||||
chunk_t chunk, chunk_t *hash)
|
||||
{
|
||||
chunk_t allocated_hash;
|
||||
|
||||
sha512_write(this, chunk.ptr, chunk.len);
|
||||
if (hash != NULL)
|
||||
{
|
||||
sha512_final(this);
|
||||
allocated_hash = chunk_alloc(HASH_SIZE_SHA384);
|
||||
memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA384);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
*hash = allocated_hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.allocate_hash for SHA512.
|
||||
*/
|
||||
static void allocate_hash512(private_sha512_hasher_t *this,
|
||||
chunk_t chunk, chunk_t *hash)
|
||||
{
|
||||
chunk_t allocated_hash;
|
||||
|
||||
sha512_write(this, chunk.ptr, chunk.len);
|
||||
if (hash != NULL)
|
||||
{
|
||||
sha512_final(this);
|
||||
allocated_hash = chunk_alloc(HASH_SIZE_SHA512);
|
||||
memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA512);
|
||||
this->public.hasher_interface.reset(&(this->public.hasher_interface));
|
||||
*hash = allocated_hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash_size for SHA256.
|
||||
*/
|
||||
static size_t get_hash_size256(private_sha256_hasher_t *this)
|
||||
{
|
||||
return HASH_SIZE_SHA256;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash_size for SHA384.
|
||||
*/
|
||||
static size_t get_hash_size384(private_sha512_hasher_t *this)
|
||||
{
|
||||
return HASH_SIZE_SHA384;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_hash_size for SHA512.
|
||||
*/
|
||||
static size_t get_hash_size512(private_sha512_hasher_t *this)
|
||||
{
|
||||
return HASH_SIZE_SHA512;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.reset for SHA256
|
||||
*/
|
||||
static void reset256(private_sha256_hasher_t *ctx)
|
||||
{
|
||||
memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H));
|
||||
ctx->sha_blocks = 0;
|
||||
ctx->sha_bufCnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.reset for SHA384
|
||||
*/
|
||||
static void reset384(private_sha512_hasher_t *ctx)
|
||||
{
|
||||
memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H));
|
||||
ctx->sha_blocks = 0;
|
||||
ctx->sha_blocksMSB = 0;
|
||||
ctx->sha_bufCnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.reset for SHA512
|
||||
*/
|
||||
static void reset512(private_sha512_hasher_t *ctx)
|
||||
{
|
||||
memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H));
|
||||
ctx->sha_blocks = 0;
|
||||
ctx->sha_blocksMSB = 0;
|
||||
ctx->sha_bufCnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.destroy.
|
||||
*/
|
||||
static void destroy(sha2_hasher_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm)
|
||||
{
|
||||
sha2_hasher_t *this;
|
||||
|
||||
switch (algorithm)
|
||||
{
|
||||
case HASH_SHA256:
|
||||
this = (sha2_hasher_t*)malloc_thing(private_sha256_hasher_t);
|
||||
this->hasher_interface.reset = (void(*)(hasher_t*))reset256;
|
||||
this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size256;
|
||||
this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash256;
|
||||
this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash256;
|
||||
break;
|
||||
case HASH_SHA384:
|
||||
/* uses SHA512 data structure */
|
||||
this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t);
|
||||
this->hasher_interface.reset = (void(*)(hasher_t*))reset384;
|
||||
this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size384;
|
||||
this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash384;
|
||||
this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash384;
|
||||
break;
|
||||
case HASH_SHA512:
|
||||
this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t);
|
||||
this->hasher_interface.reset = (void(*)(hasher_t*))reset512;
|
||||
this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size512;
|
||||
this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash512;
|
||||
this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash512;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
this->hasher_interface.destroy = (void(*)(hasher_t*))destroy;
|
||||
|
||||
/* initialize */
|
||||
this->hasher_interface.reset(&this->hasher_interface);
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sha2_hasher sha2_hasher
|
||||
* @{ @ingroup sha2_p
|
||||
*/
|
||||
|
||||
#ifndef SHA2_HASHER_H_
|
||||
#define SHA2_HASHER_H_
|
||||
|
||||
typedef struct sha2_hasher_t sha2_hasher_t;
|
||||
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t interface using the SHA2 algorithms.
|
||||
*
|
||||
* SHA2 is an other name for the SHA-256, SHA-384 and SHA-512 variants of
|
||||
* the SHA hash algorithm.
|
||||
*/
|
||||
struct sha2_hasher_t {
|
||||
|
||||
/**
|
||||
* Generic hasher_t interface for this hasher.
|
||||
*/
|
||||
hasher_t hasher_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new sha2_hasher_t.
|
||||
*
|
||||
* @param algorithm HASH_SHA256, HASH_SHA384 or HASH_SHA512
|
||||
* @return sha2_hasher_t object, NULL if not supported
|
||||
*/
|
||||
sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm);
|
||||
|
||||
#endif /* SHA2_HASHER_H_ @}*/
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "sha2_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "sha2_hasher.h"
|
||||
|
||||
typedef struct private_sha2_plugin_t private_sha2_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of sha2_plugin
|
||||
*/
|
||||
struct private_sha2_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
sha2_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of sha2_plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_sha2_plugin_t *this)
|
||||
{
|
||||
lib->crypto->remove_hasher(lib->crypto,
|
||||
(hasher_constructor_t)sha2_hasher_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_sha2_plugin_t *this = malloc_thing(private_sha2_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->crypto->add_hasher(lib->crypto, HASH_SHA256,
|
||||
(hasher_constructor_t)sha2_hasher_create);
|
||||
lib->crypto->add_hasher(lib->crypto, HASH_SHA384,
|
||||
(hasher_constructor_t)sha2_hasher_create);
|
||||
lib->crypto->add_hasher(lib->crypto, HASH_SHA512,
|
||||
(hasher_constructor_t)sha2_hasher_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sha2_p sha2
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup sha2_plugin sha2_plugin
|
||||
* @{ @ingroup sha2_p
|
||||
*/
|
||||
|
||||
#ifndef SHA2_PLUGIN_H_
|
||||
#define SHA2_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct sha2_plugin_t sha2_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing the SHA256, SHA384 and SHA512 algorithms in software.
|
||||
*/
|
||||
struct sha2_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a sha2_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* SHA2_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-sqlite.la
|
||||
|
||||
libstrongswan_sqlite_la_SOURCES = sqlite_plugin.h sqlite_plugin.c \
|
||||
sqlite_database.h sqlite_database.c
|
||||
libstrongswan_sqlite_la_LDFLAGS = -module
|
||||
libstrongswan_sqlite_la_LIBADD = -lsqlite3
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "sqlite_database.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include <utils/mutex.h>
|
||||
|
||||
typedef struct private_sqlite_database_t private_sqlite_database_t;
|
||||
|
||||
/**
|
||||
* private data of sqlite_database
|
||||
*/
|
||||
struct private_sqlite_database_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
sqlite_database_t public;
|
||||
|
||||
/**
|
||||
* sqlite database connection
|
||||
*/
|
||||
sqlite3 *db;
|
||||
|
||||
/**
|
||||
* mutex used to lock execute()
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create and run a sqlite stmt using a sql string and args
|
||||
*/
|
||||
static sqlite3_stmt* run(private_sqlite_database_t *this, char *sql,
|
||||
va_list *args)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
int params, i, res = SQLITE_OK;
|
||||
|
||||
if (sqlite3_prepare_v2(this->db, sql, -1, &stmt, NULL) == SQLITE_OK)
|
||||
{
|
||||
params = sqlite3_bind_parameter_count(stmt);
|
||||
for (i = 1; i <= params; i++)
|
||||
{
|
||||
switch (va_arg(*args, db_type_t))
|
||||
{
|
||||
case DB_INT:
|
||||
{
|
||||
res = sqlite3_bind_int(stmt, i, va_arg(*args, int));
|
||||
break;
|
||||
}
|
||||
case DB_UINT:
|
||||
{
|
||||
res = sqlite3_bind_int64(stmt, i, va_arg(*args, u_int));
|
||||
break;
|
||||
}
|
||||
case DB_TEXT:
|
||||
{
|
||||
const char *text = va_arg(*args, const char*);
|
||||
res = sqlite3_bind_text(stmt, i, text, -1, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
case DB_BLOB:
|
||||
{
|
||||
chunk_t c = va_arg(*args, chunk_t);
|
||||
res = sqlite3_bind_blob(stmt, i, c.ptr, c.len, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
case DB_DOUBLE:
|
||||
{
|
||||
res = sqlite3_bind_double(stmt, i, va_arg(*args, double));
|
||||
break;
|
||||
}
|
||||
case DB_NULL:
|
||||
{
|
||||
res = sqlite3_bind_null(stmt, i);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
res = SQLITE_MISUSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res != SQLITE_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return NULL;
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
/** implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/** associated sqlite statement */
|
||||
sqlite3_stmt *stmt;
|
||||
/** number of result columns */
|
||||
int count;
|
||||
/** column types */
|
||||
db_type_t *columns;
|
||||
} sqlite_enumerator_t;
|
||||
|
||||
/**
|
||||
* destroy a sqlite enumerator
|
||||
*/
|
||||
static void sqlite_enumerator_destroy(sqlite_enumerator_t *this)
|
||||
{
|
||||
sqlite3_finalize(this->stmt);
|
||||
free(this->columns);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database.query().enumerate
|
||||
*/
|
||||
static bool sqlite_enumerator_enumerate(sqlite_enumerator_t *this, ...)
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
|
||||
if (sqlite3_step(this->stmt) != SQLITE_ROW)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
va_start(args, this);
|
||||
for (i = 0; i < this->count; i++)
|
||||
{
|
||||
switch (this->columns[i])
|
||||
{
|
||||
case DB_INT:
|
||||
{
|
||||
int *value = va_arg(args, int*);
|
||||
*value = sqlite3_column_int(this->stmt, i);
|
||||
break;
|
||||
}
|
||||
case DB_UINT:
|
||||
{
|
||||
u_int *value = va_arg(args, u_int*);
|
||||
*value = (u_int)sqlite3_column_int64(this->stmt, i);
|
||||
break;
|
||||
}
|
||||
case DB_TEXT:
|
||||
{
|
||||
const unsigned char **value = va_arg(args, const unsigned char**);
|
||||
*value = sqlite3_column_text(this->stmt, i);
|
||||
break;
|
||||
}
|
||||
case DB_BLOB:
|
||||
{
|
||||
chunk_t *chunk = va_arg(args, chunk_t*);
|
||||
chunk->len = sqlite3_column_bytes(this->stmt, i);
|
||||
chunk->ptr = (u_char*)sqlite3_column_blob(this->stmt, i);
|
||||
break;
|
||||
}
|
||||
case DB_DOUBLE:
|
||||
{
|
||||
double *value = va_arg(args, double*);
|
||||
*value = sqlite3_column_double(this->stmt, i);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database_t.query.
|
||||
*/
|
||||
static enumerator_t* query(private_sqlite_database_t *this, char *sql, ...)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
va_list args;
|
||||
sqlite_enumerator_t *enumerator = NULL;
|
||||
int i;
|
||||
|
||||
|
||||
va_start(args, sql);
|
||||
stmt = run(this, sql, &args);
|
||||
if (stmt)
|
||||
{
|
||||
enumerator = malloc_thing(sqlite_enumerator_t);
|
||||
enumerator->public.enumerate = (void*)sqlite_enumerator_enumerate;
|
||||
enumerator->public.destroy = (void*)sqlite_enumerator_destroy;
|
||||
enumerator->stmt = stmt;
|
||||
enumerator->count = sqlite3_column_count(stmt);
|
||||
enumerator->columns = malloc(sizeof(db_type_t) * enumerator->count);
|
||||
for (i = 0; i < enumerator->count; i++)
|
||||
{
|
||||
enumerator->columns[i] = va_arg(args, db_type_t);
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
return (enumerator_t*)enumerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database_t.execute.
|
||||
*/
|
||||
static int execute(private_sqlite_database_t *this, int *rowid, char *sql, ...)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
int affected = -1;
|
||||
va_list args;
|
||||
|
||||
/* we need a lock to get our rowid/changes correctly */
|
||||
this->mutex->lock(this->mutex);
|
||||
va_start(args, sql);
|
||||
stmt = run(this, sql, &args);
|
||||
va_end(args);
|
||||
if (stmt)
|
||||
{
|
||||
if (sqlite3_step(stmt) == SQLITE_DONE)
|
||||
{
|
||||
if (rowid)
|
||||
{
|
||||
*rowid = sqlite3_last_insert_rowid(this->db);
|
||||
}
|
||||
affected = sqlite3_changes(this->db);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
return affected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of database_t.destroy
|
||||
*/
|
||||
static void destroy(private_sqlite_database_t *this)
|
||||
{
|
||||
sqlite3_close(this->db);
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
sqlite_database_t *sqlite_database_create(char *uri)
|
||||
{
|
||||
char *file;
|
||||
private_sqlite_database_t *this;
|
||||
|
||||
/**
|
||||
* parse sqlite:///path/to/file.db uri
|
||||
*/
|
||||
if (!strneq(uri, "sqlite://", 9))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
file = uri + 9;
|
||||
|
||||
this = malloc_thing(private_sqlite_database_t);
|
||||
|
||||
this->public.db.query = (enumerator_t* (*)(database_t *this, char *sql, ...))query;
|
||||
this->public.db.execute = (int (*)(database_t *this, int *rowid, char *sql, ...))execute;
|
||||
this->public.db.destroy = (void(*)(database_t*))destroy;
|
||||
|
||||
if (sqlite3_open(file, &this->db) != SQLITE_OK)
|
||||
{
|
||||
DBG1("opening SQLite database '%s' failed", file);
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
this->mutex = mutex_create(MUTEX_DEFAULT);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sqlite_database sqlite_database
|
||||
* @{ @ingroup sqlite_p
|
||||
*/
|
||||
|
||||
#ifndef SQLITE_DATABASE_H_
|
||||
#define SQLITE_DATABASE_H_
|
||||
|
||||
#include <database/database.h>
|
||||
|
||||
typedef struct sqlite_database_t sqlite_database_t;
|
||||
|
||||
/**
|
||||
* sqlite databse_t implementation.
|
||||
*/
|
||||
struct sqlite_database_t {
|
||||
|
||||
/**
|
||||
* Implements database_t
|
||||
*/
|
||||
database_t db;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a sqlite_database instance.
|
||||
*
|
||||
* @param uri connection URI, sqlite:///path/to/file.db
|
||||
*/
|
||||
sqlite_database_t *sqlite_database_create(char *uri);
|
||||
|
||||
#endif /* SQLITE_DATABASE_H_ @}*/
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "sqlite_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "sqlite_database.h"
|
||||
|
||||
typedef struct private_sqlite_plugin_t private_sqlite_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of sqlite_plugin
|
||||
*/
|
||||
struct private_sqlite_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
sqlite_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of plugin_t.destroy
|
||||
*/
|
||||
static void destroy(private_sqlite_plugin_t *this)
|
||||
{
|
||||
lib->db->remove_database(lib->db,
|
||||
(database_constructor_t)sqlite_database_create);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_sqlite_plugin_t *this = malloc_thing(private_sqlite_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->db->add_database(lib->db,
|
||||
(database_constructor_t)sqlite_database_create);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sqlite_p sqlite
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup sqlite_plugin sqlite_plugin
|
||||
* @{ @ingroup sqlite_p
|
||||
*/
|
||||
|
||||
#ifndef SQLITE_PLUGIN_H_
|
||||
#define SQLITE_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct sqlite_plugin_t sqlite_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing sqlite database connectivity
|
||||
*/
|
||||
struct sqlite_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a sqlite_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* SQLITE_PLUGIN_H_ @}*/
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-x509.la
|
||||
|
||||
libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \
|
||||
x509_cert.h x509_cert.c x509_crl.h x509_crl.c \
|
||||
x509_ocsp_request.h x509_ocsp_request.c \
|
||||
x509_ocsp_response.h x509_ocsp_response.c
|
||||
libstrongswan_x509_la_LDFLAGS = -module
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup x509_cert x509_cert
|
||||
* @{ @ingroup x509_p
|
||||
*/
|
||||
|
||||
#ifndef X509_CERT_H_
|
||||
#define X509_CERT_H_
|
||||
|
||||
typedef struct x509_cert_t x509_cert_t;
|
||||
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
/**
|
||||
* Implementation of x509_t/certificate_t using own ASN1 parser.
|
||||
*/
|
||||
struct x509_cert_t {
|
||||
|
||||
/**
|
||||
* Implements the x509_t interface
|
||||
*/
|
||||
x509_t interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the building facility for x509 certificates
|
||||
*
|
||||
* @param type certificate type, CERT_X509 only
|
||||
* @return builder instance to build certificate
|
||||
*/
|
||||
builder_t *x509_cert_builder(certificate_type_t type);
|
||||
|
||||
#endif /* X509_CERT_H_ @}*/
|
||||
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "x509_crl.h"
|
||||
|
||||
typedef struct private_x509_crl_t private_x509_crl_t;
|
||||
typedef struct revoked_t revoked_t;
|
||||
|
||||
#include <debug.h>
|
||||
#include <library.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
/**
|
||||
* entry for a revoked certificate
|
||||
*/
|
||||
struct revoked_t {
|
||||
/**
|
||||
* serial of the revoked certificate
|
||||
*/
|
||||
chunk_t serial;
|
||||
|
||||
/**
|
||||
* date of revocation
|
||||
*/
|
||||
time_t date;
|
||||
|
||||
/**
|
||||
* reason for revocation
|
||||
*/
|
||||
crl_reason_t reason;
|
||||
};
|
||||
|
||||
/**
|
||||
* private data of x509_crl
|
||||
*/
|
||||
struct private_x509_crl_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
x509_crl_t public;
|
||||
|
||||
/**
|
||||
* X.509 crl in DER format
|
||||
*/
|
||||
chunk_t certificateList;
|
||||
|
||||
/**
|
||||
* X.509 crl body over which signature is computed
|
||||
*/
|
||||
chunk_t tbsCertList;
|
||||
|
||||
/**
|
||||
* Version of the X.509 crl
|
||||
*/
|
||||
u_int version;
|
||||
|
||||
/**
|
||||
* ID representing the crl issuer
|
||||
*/
|
||||
identification_t *issuer;
|
||||
|
||||
/**
|
||||
* CRL number
|
||||
*/
|
||||
chunk_t crlNumber;
|
||||
|
||||
/**
|
||||
* Time when the crl was generated
|
||||
*/
|
||||
time_t thisUpdate;
|
||||
|
||||
/**
|
||||
* Time when an update crl will be available
|
||||
*/
|
||||
time_t nextUpdate;
|
||||
|
||||
/**
|
||||
* list of revoked certificates as revoked_t
|
||||
*/
|
||||
linked_list_t *revoked;
|
||||
|
||||
/**
|
||||
* Authority Key Identifier
|
||||
*/
|
||||
identification_t *authKeyIdentifier;
|
||||
|
||||
/**
|
||||
* Authority Key Serial Number
|
||||
*/
|
||||
chunk_t authKeySerialNumber;
|
||||
|
||||
/**
|
||||
* Signature algorithm
|
||||
*/
|
||||
int algorithm;
|
||||
|
||||
/**
|
||||
* Signature
|
||||
*/
|
||||
chunk_t signature;
|
||||
|
||||
/**
|
||||
* reference counter
|
||||
*/
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* from x509_cert
|
||||
*/
|
||||
extern identification_t* x509_parse_authorityKeyIdentifier(
|
||||
chunk_t blob, int level0,
|
||||
chunk_t *authKeySerialNumber);
|
||||
|
||||
/**
|
||||
* ASN.1 definition of an X.509 certificate revocation list
|
||||
*/
|
||||
static const asn1Object_t crlObjects[] = {
|
||||
{ 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "version", ASN1_INTEGER, ASN1_OPT |
|
||||
ASN1_BODY }, /* 2 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
|
||||
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
|
||||
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
|
||||
{ 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
|
||||
{ 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 8 */
|
||||
{ 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
|
||||
{ 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
|
||||
{ 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
|
||||
{ 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 12 */
|
||||
{ 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
|
||||
{ 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
|
||||
{ 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 15 */
|
||||
{ 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
|
||||
{ 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
|
||||
{ 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
|
||||
{ 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
|
||||
{ 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
|
||||
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
|
||||
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
|
||||
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 23 */
|
||||
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
|
||||
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
|
||||
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
|
||||
};
|
||||
|
||||
#define CRL_OBJ_TBS_CERT_LIST 1
|
||||
#define CRL_OBJ_VERSION 2
|
||||
#define CRL_OBJ_SIG_ALG 4
|
||||
#define CRL_OBJ_ISSUER 5
|
||||
#define CRL_OBJ_THIS_UPDATE 6
|
||||
#define CRL_OBJ_NEXT_UPDATE 7
|
||||
#define CRL_OBJ_USER_CERTIFICATE 10
|
||||
#define CRL_OBJ_REVOCATION_DATE 11
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
|
||||
#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
|
||||
#define CRL_OBJ_EXTN_ID 22
|
||||
#define CRL_OBJ_CRITICAL 23
|
||||
#define CRL_OBJ_EXTN_VALUE 24
|
||||
#define CRL_OBJ_ALGORITHM 27
|
||||
#define CRL_OBJ_SIGNATURE 28
|
||||
#define CRL_OBJ_ROOF 29
|
||||
|
||||
/**
|
||||
* Parses an X.509 Certificate Revocation List (CRL)
|
||||
*/
|
||||
static bool parse(private_x509_crl_t *this)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
bool critical;
|
||||
chunk_t extnID;
|
||||
chunk_t userCertificate = chunk_empty;
|
||||
revoked_t *revoked = NULL;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
|
||||
asn1_init(&ctx, this->certificateList, 0, FALSE, FALSE);
|
||||
while (objectID < CRL_OBJ_ROOF)
|
||||
{
|
||||
if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* those objects which will parsed further need the next higher level */
|
||||
level++;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case CRL_OBJ_TBS_CERT_LIST:
|
||||
this->tbsCertList = object;
|
||||
break;
|
||||
case CRL_OBJ_VERSION:
|
||||
this->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
|
||||
DBG2(" v%d", this->version);
|
||||
break;
|
||||
case CRL_OBJ_SIG_ALG:
|
||||
this->algorithm = parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case CRL_OBJ_ISSUER:
|
||||
this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
|
||||
DBG2(" '%D'", this->issuer);
|
||||
break;
|
||||
case CRL_OBJ_THIS_UPDATE:
|
||||
this->thisUpdate = parse_time(object, level);
|
||||
break;
|
||||
case CRL_OBJ_NEXT_UPDATE:
|
||||
this->nextUpdate = parse_time(object, level);
|
||||
break;
|
||||
case CRL_OBJ_USER_CERTIFICATE:
|
||||
userCertificate = object;
|
||||
break;
|
||||
case CRL_OBJ_REVOCATION_DATE:
|
||||
revoked = malloc_thing(revoked_t);
|
||||
revoked->serial = userCertificate;
|
||||
revoked->date = parse_time(object, level);
|
||||
revoked->reason = CRL_UNSPECIFIED;
|
||||
this->revoked->insert_last(this->revoked, (void *)revoked);
|
||||
break;
|
||||
case CRL_OBJ_CRL_ENTRY_EXTN_ID:
|
||||
case CRL_OBJ_EXTN_ID:
|
||||
extnID = object;
|
||||
break;
|
||||
case CRL_OBJ_CRL_ENTRY_CRITICAL:
|
||||
case CRL_OBJ_CRITICAL:
|
||||
critical = object.len && *object.ptr;
|
||||
DBG2(" %s", critical ? "TRUE" : "FALSE");
|
||||
break;
|
||||
case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
|
||||
case CRL_OBJ_EXTN_VALUE:
|
||||
{
|
||||
int extn_oid = known_oid(extnID);
|
||||
|
||||
if (revoked && extn_oid == OID_CRL_REASON_CODE)
|
||||
{
|
||||
if (*object.ptr == ASN1_ENUMERATED &&
|
||||
asn1_length(&object) == 1)
|
||||
{
|
||||
revoked->reason = *object.ptr;
|
||||
}
|
||||
DBG2(" '%N'", crl_reason_names, revoked->reason);
|
||||
}
|
||||
else if (extn_oid == OID_AUTHORITY_KEY_ID)
|
||||
{
|
||||
|
||||
this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
|
||||
level, &this->authKeySerialNumber);
|
||||
}
|
||||
else if (extn_oid == OID_CRL_NUMBER)
|
||||
{
|
||||
if (!parse_asn1_simple_object(&object, ASN1_INTEGER,
|
||||
level, "crlNumber"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
this->crlNumber = object;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CRL_OBJ_ALGORITHM:
|
||||
{
|
||||
int algo = parse_algorithmIdentifier(object, level, NULL);
|
||||
if (this->algorithm != algo)
|
||||
{
|
||||
DBG1(" signature algorithms do not agree");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CRL_OBJ_SIGNATURE:
|
||||
this->signature = object;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* enumerator filter callback for create_enumerator
|
||||
*/
|
||||
static bool filter(void *data, revoked_t *revoked, chunk_t *serial, void *p2,
|
||||
time_t *date, void *p3, crl_reason_t *reason)
|
||||
{
|
||||
if (serial)
|
||||
{
|
||||
*serial = revoked->serial;
|
||||
}
|
||||
if (date)
|
||||
{
|
||||
*date = revoked->date;
|
||||
}
|
||||
if (reason)
|
||||
{
|
||||
*reason = revoked->reason;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of crl_t.is_newer.
|
||||
*/
|
||||
static bool is_newer(private_x509_crl_t *this, crl_t *that)
|
||||
{
|
||||
chunk_t that_crlNumber = that->get_serial(that);
|
||||
bool new;
|
||||
|
||||
/* compare crlNumbers if available - otherwise use thisUpdate */
|
||||
if (this->crlNumber.ptr != NULL && that_crlNumber.ptr != NULL)
|
||||
{
|
||||
new = chunk_compare(this->crlNumber, that_crlNumber) > 0;
|
||||
DBG1(" crl #%#B is %s - existing crl #%#B %s",
|
||||
&this->crlNumber, new ? "newer":"not newer",
|
||||
&that_crlNumber, new ? "replaced":"retained");
|
||||
}
|
||||
else
|
||||
{
|
||||
certificate_t *this_cert = &this->public.crl.certificate;
|
||||
certificate_t *that_cert = &that->certificate;
|
||||
|
||||
time_t this_update, that_update, now = time(NULL);
|
||||
|
||||
this_cert->get_validity(this_cert, &now, &this_update, NULL);
|
||||
that_cert->get_validity(that_cert, &now, &that_update, NULL);
|
||||
new = this_update > that_update;
|
||||
DBG1(" crl from %#T is %s - existing crl from %#T %s",
|
||||
&this_update, FALSE, new ? "newer":"not newer",
|
||||
&that_update, FALSE, new ? "replaced":"retained");
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of crl_t.get_serial.
|
||||
*/
|
||||
static chunk_t get_serial(private_x509_crl_t *this)
|
||||
{
|
||||
return this->crlNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of crl_t.get_authKeyIdentifier.
|
||||
*/
|
||||
static identification_t* get_authKeyIdentifier(private_x509_crl_t *this)
|
||||
{
|
||||
return this->authKeyIdentifier;
|
||||
}
|
||||
/**
|
||||
* Implementation of crl_t.create_enumerator.
|
||||
*/
|
||||
static enumerator_t* create_enumerator(private_x509_crl_t *this)
|
||||
{
|
||||
return enumerator_create_filter(
|
||||
this->revoked->create_enumerator(this->revoked),
|
||||
(void*)filter, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_type
|
||||
*/
|
||||
static certificate_type_t get_type(private_x509_crl_t *this)
|
||||
{
|
||||
return CERT_X509_CRL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_subject
|
||||
*/
|
||||
static identification_t* get_subject(private_x509_crl_t *this)
|
||||
{
|
||||
return this->issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_issuer
|
||||
*/
|
||||
static identification_t* get_issuer(private_x509_crl_t *this)
|
||||
{
|
||||
return this->issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.has_subject.
|
||||
*/
|
||||
static id_match_t has_subject(private_x509_crl_t *this, identification_t *subject)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.has_issuer.
|
||||
*/
|
||||
static id_match_t has_issuer(private_x509_crl_t *this, identification_t *issuer)
|
||||
{
|
||||
id_match_t match;
|
||||
|
||||
if (issuer->get_type(issuer) == ID_PUBKEY_SHA1)
|
||||
{
|
||||
if (this->authKeyIdentifier)
|
||||
{
|
||||
match = issuer->matches(issuer, this->authKeyIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
match = ID_MATCH_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = this->issuer->matches(this->issuer, issuer);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.issued_by
|
||||
*/
|
||||
static bool issued_by(private_x509_crl_t *this, certificate_t *issuer,
|
||||
bool sigcheck)
|
||||
{
|
||||
public_key_t *key;
|
||||
signature_scheme_t scheme;
|
||||
bool valid;
|
||||
x509_t *x509 = (x509_t*)issuer;
|
||||
|
||||
/* check if issuer is an X.509 CA certificate */
|
||||
if (issuer->get_type(issuer) != CERT_X509)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!(x509->get_flags(x509) & X509_CA))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* get the public key of the issuer */
|
||||
key = issuer->get_public_key(issuer);
|
||||
|
||||
/* compare keyIdentifiers if available, otherwise use DNs */
|
||||
if (this->authKeyIdentifier && key)
|
||||
{
|
||||
identification_t *subjectKeyIdentifier = key->get_id(key, ID_PUBKEY_SHA1);
|
||||
|
||||
if (!subjectKeyIdentifier->equals(subjectKeyIdentifier,
|
||||
this->authKeyIdentifier))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sigcheck)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
/* TODO: generic OID to scheme mapper? */
|
||||
switch (this->algorithm)
|
||||
{
|
||||
case OID_MD5_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
|
||||
break;
|
||||
case OID_SHA1_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
|
||||
break;
|
||||
case OID_SHA256_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
|
||||
break;
|
||||
case OID_SHA384_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
|
||||
break;
|
||||
case OID_SHA512_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
if (key == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
valid = key->verify(key, scheme, this->tbsCertList, this->signature);
|
||||
key->destroy(key);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_public_key
|
||||
*/
|
||||
static public_key_t* get_public_key(private_x509_crl_t *this)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.asdf
|
||||
*/
|
||||
static private_x509_crl_t* get_ref(private_x509_crl_t *this)
|
||||
{
|
||||
ref_get(&this->ref);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_validity.
|
||||
*/
|
||||
static bool get_validity(private_x509_crl_t *this, time_t *when,
|
||||
time_t *not_before, time_t *not_after)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
if (when)
|
||||
{
|
||||
t = *when;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = time(NULL);
|
||||
}
|
||||
if (not_after)
|
||||
{
|
||||
*not_after = this->nextUpdate;
|
||||
}
|
||||
if (not_before)
|
||||
{
|
||||
*not_before = this->thisUpdate;
|
||||
}
|
||||
return (t <= this->nextUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_encoding.
|
||||
*/
|
||||
static chunk_t get_encoding(private_x509_crl_t *this)
|
||||
{
|
||||
return chunk_clone(this->certificateList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.equals.
|
||||
*/
|
||||
static bool equals(private_x509_crl_t *this, certificate_t *other)
|
||||
{
|
||||
if ((certificate_t*)this == other)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (other->equals == (void*)equals)
|
||||
{ /* same implementation */
|
||||
return chunk_equals(this->signature,
|
||||
((private_x509_crl_t*)other)->signature);
|
||||
}
|
||||
/* TODO: compare against other implementations */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.destroy
|
||||
*/
|
||||
static void destroy(private_x509_crl_t *this)
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
this->revoked->destroy_function(this->revoked, free);
|
||||
DESTROY_IF(this->issuer);
|
||||
DESTROY_IF(this->authKeyIdentifier);
|
||||
free(this->certificateList.ptr);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load a X509 CRL from a chunk of date (ASN1 DER)
|
||||
*/
|
||||
static x509_crl_t *load(chunk_t chunk)
|
||||
{
|
||||
private_x509_crl_t *this = malloc_thing(private_x509_crl_t);
|
||||
|
||||
this->public.crl.is_newer = (bool (*)(crl_t*,crl_t*))is_newer;
|
||||
this->public.crl.get_serial = (chunk_t (*)(crl_t*))get_serial;
|
||||
this->public.crl.get_authKeyIdentifier = (identification_t* (*)(crl_t*))get_authKeyIdentifier;
|
||||
this->public.crl.create_enumerator = (enumerator_t* (*)(crl_t*))create_enumerator;
|
||||
this->public.crl.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
|
||||
this->public.crl.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject;
|
||||
this->public.crl.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
|
||||
this->public.crl.certificate.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject;
|
||||
this->public.crl.certificate.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer;
|
||||
this->public.crl.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
|
||||
this->public.crl.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
|
||||
this->public.crl.certificate.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
|
||||
this->public.crl.certificate.get_encoding = (chunk_t (*)(certificate_t*))get_encoding;
|
||||
this->public.crl.certificate.equals = (bool (*)(certificate_t*, certificate_t *other))equals;
|
||||
this->public.crl.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
|
||||
this->public.crl.certificate.destroy = (void (*)(certificate_t *this))destroy;
|
||||
|
||||
this->certificateList = chunk;
|
||||
this->tbsCertList = chunk_empty;
|
||||
this->issuer = NULL;
|
||||
this->crlNumber = chunk_empty;
|
||||
this->revoked = linked_list_create();
|
||||
this->authKeyIdentifier = NULL;
|
||||
this->authKeySerialNumber = chunk_empty;
|
||||
this->ref = 1;
|
||||
|
||||
if (!parse(this))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
typedef struct private_builder_t private_builder_t;
|
||||
/**
|
||||
* Builder implementation for certificate loading
|
||||
*/
|
||||
struct private_builder_t {
|
||||
/** implements the builder interface */
|
||||
builder_t public;
|
||||
/** loaded CRL */
|
||||
x509_crl_t *crl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.build
|
||||
*/
|
||||
static x509_crl_t *build(private_builder_t *this)
|
||||
{
|
||||
x509_crl_t *crl = this->crl;
|
||||
|
||||
free(this);
|
||||
return crl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.add
|
||||
*/
|
||||
static void add(private_builder_t *this, builder_part_t part, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (this->crl)
|
||||
{
|
||||
DBG1("ignoring surplus build part %N", builder_part_names, part);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (part)
|
||||
{
|
||||
case BUILD_BLOB_ASN1_DER:
|
||||
{
|
||||
va_start(args, part);
|
||||
this->crl = load(va_arg(args, chunk_t));
|
||||
va_end(args);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1("ignoring unsupported build part %N", builder_part_names, part);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder construction function
|
||||
*/
|
||||
builder_t *x509_crl_builder(certificate_type_t type)
|
||||
{
|
||||
private_builder_t *this;
|
||||
|
||||
if (type != CERT_X509_CRL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_builder_t);
|
||||
|
||||
this->crl = NULL;
|
||||
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||
this->public.build = (void*(*)(builder_t *this))build;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup x509_crl x509_crl
|
||||
* @{ @ingroup x509_p
|
||||
*/
|
||||
|
||||
#ifndef X509_CRL_H_
|
||||
#define X509_CRL_H_
|
||||
|
||||
typedef struct x509_crl_t x509_crl_t;
|
||||
|
||||
#include <credentials/certificates/crl.h>
|
||||
|
||||
/**
|
||||
* Implementation of the X509 certification revocation list.
|
||||
*/
|
||||
struct x509_crl_t {
|
||||
|
||||
/**
|
||||
* Implements the crl_t interface
|
||||
*/
|
||||
crl_t crl;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create the building facility for x509 certificate revocation lists.
|
||||
*
|
||||
* @param type certificate type, CERT_X509_CRL only
|
||||
* @return builder instance to build certificate
|
||||
*/
|
||||
builder_t *x509_crl_builder(certificate_type_t type);
|
||||
|
||||
#endif /* X509_CRL_H_ @}*/
|
||||
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Copyright (C) 2007 Andreas Steffen
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "x509_ocsp_request.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <asn1/oid.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <utils/identification.h>
|
||||
#include <utils/randomizer.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <debug.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
#define NONCE_LEN 16
|
||||
|
||||
typedef struct private_x509_ocsp_request_t private_x509_ocsp_request_t;
|
||||
|
||||
/**
|
||||
* private data of x509_ocsp_request
|
||||
*/
|
||||
struct private_x509_ocsp_request_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
x509_ocsp_request_t public;
|
||||
|
||||
/**
|
||||
* CA the candidates belong to
|
||||
*/
|
||||
x509_t *ca;
|
||||
|
||||
/**
|
||||
* Requestor name, subject of cert used if not set
|
||||
*/
|
||||
identification_t *requestor;
|
||||
|
||||
/**
|
||||
* Requestor certificate, included in request
|
||||
*/
|
||||
certificate_t *cert;
|
||||
|
||||
/**
|
||||
* Requestor private key to sign request
|
||||
*/
|
||||
private_key_t *key;
|
||||
|
||||
/**
|
||||
* list of certificates to check, x509_t
|
||||
*/
|
||||
linked_list_t *candidates;
|
||||
|
||||
/**
|
||||
* nonce used in request
|
||||
*/
|
||||
chunk_t nonce;
|
||||
|
||||
/**
|
||||
* encoded OCSP request
|
||||
*/
|
||||
chunk_t encoding;
|
||||
|
||||
/**
|
||||
* reference count
|
||||
*/
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
static u_char ASN1_nonce_oid_str[] = {
|
||||
0x06, 0x09,
|
||||
0x2B, 0x06,
|
||||
0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
|
||||
};
|
||||
|
||||
static u_char ASN1_response_oid_str[] = {
|
||||
0x06, 0x09,
|
||||
0x2B, 0x06,
|
||||
0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
|
||||
};
|
||||
|
||||
static u_char ASN1_response_content_str[] = {
|
||||
0x04, 0x0D,
|
||||
0x30, 0x0B,
|
||||
0x06, 0x09,
|
||||
0x2B, 0x06,
|
||||
0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
|
||||
};
|
||||
|
||||
static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str);
|
||||
static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str);
|
||||
static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str);
|
||||
|
||||
/**
|
||||
* build requestorName
|
||||
*/
|
||||
static chunk_t build_requestorName(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
if (this->requestor || this->cert)
|
||||
{ /* use requestor name, fallback to his cert subject */
|
||||
if (!this->requestor)
|
||||
{
|
||||
this->requestor = this->cert->get_subject(this->cert);
|
||||
this->requestor = this->requestor->clone(this->requestor);
|
||||
}
|
||||
return asn1_wrap(ASN1_CONTEXT_C_1, "m",
|
||||
asn1_simple_object(ASN1_CONTEXT_C_4,
|
||||
this->requestor->get_encoding(this->requestor)));
|
||||
|
||||
}
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* build Request, not using singleRequestExtensions
|
||||
*/
|
||||
static chunk_t build_Request(private_x509_ocsp_request_t *this,
|
||||
chunk_t issuerNameHash, chunk_t issuerKeyHash,
|
||||
chunk_t serialNumber)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "m",
|
||||
asn1_wrap(ASN1_SEQUENCE, "cmmm",
|
||||
asn1_algorithmIdentifier(OID_SHA1),
|
||||
asn1_simple_object(ASN1_OCTET_STRING, issuerNameHash),
|
||||
asn1_simple_object(ASN1_OCTET_STRING, issuerKeyHash),
|
||||
asn1_simple_object(ASN1_INTEGER, serialNumber)));
|
||||
}
|
||||
|
||||
/**
|
||||
* build requestList
|
||||
*/
|
||||
static chunk_t build_requestList(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
chunk_t issuerNameHash, issuerKeyHash;
|
||||
identification_t *issuer;
|
||||
x509_t *x509;
|
||||
certificate_t *cert;
|
||||
chunk_t list = chunk_empty;
|
||||
public_key_t *public;
|
||||
|
||||
cert = (certificate_t*)this->ca;
|
||||
public = cert->get_public_key(cert);
|
||||
if (public)
|
||||
{
|
||||
hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||
if (hasher)
|
||||
{
|
||||
identification_t *keyid = public->get_id(public, ID_PUBKEY_SHA1);
|
||||
if (keyid)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
|
||||
issuerKeyHash = keyid->get_encoding(keyid);
|
||||
|
||||
issuer = cert->get_subject(cert);
|
||||
hasher->allocate_hash(hasher, issuer->get_encoding(issuer),
|
||||
&issuerNameHash);
|
||||
hasher->destroy(hasher);
|
||||
|
||||
enumerator = this->candidates->create_enumerator(this->candidates);
|
||||
while (enumerator->enumerate(enumerator, &x509))
|
||||
{
|
||||
chunk_t request, serialNumber;
|
||||
|
||||
serialNumber = x509->get_serial(x509);
|
||||
request = build_Request(this, issuerNameHash, issuerKeyHash,
|
||||
serialNumber);
|
||||
list = chunk_cat("mm", list, request);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
chunk_free(&issuerNameHash);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("creating OCSP request failed, SHA1 not supported");
|
||||
}
|
||||
public->destroy(public);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("creating OCSP request failed, CA certificate has no public key");
|
||||
}
|
||||
return asn1_wrap(ASN1_SEQUENCE, "m", list);
|
||||
}
|
||||
|
||||
/**
|
||||
* build nonce extension
|
||||
*/
|
||||
static chunk_t build_nonce(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
randomizer_t *randomizer;
|
||||
|
||||
randomizer = randomizer_create();
|
||||
randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN, &this->nonce);
|
||||
randomizer->destroy(randomizer);
|
||||
|
||||
return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_nonce_oid,
|
||||
asn1_simple_object(ASN1_OCTET_STRING, this->nonce));
|
||||
}
|
||||
|
||||
/**
|
||||
* build acceptableResponses extension
|
||||
*/
|
||||
static chunk_t build_acceptableResponses(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "cc",
|
||||
ASN1_response_oid,
|
||||
ASN1_response_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* build requestExtensions
|
||||
*/
|
||||
static chunk_t build_requestExtensions(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
return asn1_wrap(ASN1_CONTEXT_C_2, "m",
|
||||
asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||
build_nonce(this),
|
||||
build_acceptableResponses(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* build tbsRequest
|
||||
*/
|
||||
static chunk_t build_tbsRequest(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "mmm",
|
||||
build_requestorName(this),
|
||||
build_requestList(this),
|
||||
build_requestExtensions(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the optionalSignature
|
||||
*/
|
||||
static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this,
|
||||
chunk_t tbsRequest)
|
||||
{
|
||||
int oid;
|
||||
signature_scheme_t scheme;
|
||||
chunk_t certs, signature;
|
||||
|
||||
switch (this->key->get_type(this->key))
|
||||
{
|
||||
/* TODO: use a generic mapping function */
|
||||
case KEY_RSA:
|
||||
oid = OID_SHA1_WITH_RSA;
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
|
||||
break;
|
||||
default:
|
||||
DBG1("unable to sign OCSP request, %N signature not supported",
|
||||
key_type_names, this->key->get_type(this->key));
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
if (!this->key->sign(this->key, scheme, tbsRequest, &signature))
|
||||
{
|
||||
DBG1("creating OCSP signature failed, skipped");
|
||||
return chunk_empty;
|
||||
}
|
||||
if (this->cert)
|
||||
{
|
||||
certs = asn1_wrap(ASN1_CONTEXT_C_0, "m",
|
||||
asn1_wrap(ASN1_SEQUENCE, "m",
|
||||
this->cert->get_encoding(this->cert)));
|
||||
}
|
||||
return asn1_wrap(ASN1_CONTEXT_C_0, "m",
|
||||
asn1_wrap(ASN1_SEQUENCE, "cmm",
|
||||
asn1_algorithmIdentifier(oid),
|
||||
asn1_bitstring("m", signature),
|
||||
certs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the OCSPRequest data
|
||||
*
|
||||
*/
|
||||
static chunk_t build_OCSPRequest(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
chunk_t tbsRequest, optionalSignature = chunk_empty;
|
||||
|
||||
tbsRequest = build_tbsRequest(this);
|
||||
if (this->key)
|
||||
{
|
||||
optionalSignature = build_optionalSignature(this, tbsRequest);
|
||||
}
|
||||
return asn1_wrap(ASN1_SEQUENCE, "mm", tbsRequest, optionalSignature);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_type
|
||||
*/
|
||||
static certificate_type_t get_type(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
return CERT_X509_OCSP_REQUEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_subject
|
||||
*/
|
||||
static identification_t* get_subject(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
certificate_t *ca = (certificate_t*)this->ca;
|
||||
|
||||
if (this->requestor)
|
||||
{
|
||||
return this->requestor;
|
||||
}
|
||||
if (this->cert)
|
||||
{
|
||||
return this->cert->get_subject(this->cert);
|
||||
}
|
||||
return ca->get_subject(ca);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_issuer
|
||||
*/
|
||||
static identification_t* get_issuer(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
certificate_t *ca = (certificate_t*)this->ca;
|
||||
|
||||
return ca->get_subject(ca);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.has_subject.
|
||||
*/
|
||||
static id_match_t has_subject(private_x509_ocsp_request_t *this,
|
||||
identification_t *subject)
|
||||
{
|
||||
certificate_t *current;
|
||||
enumerator_t *enumerator;
|
||||
id_match_t match, best = ID_MATCH_NONE;
|
||||
|
||||
enumerator = this->candidates->create_enumerator(this->candidates);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
match = current->has_subject(current, subject);
|
||||
if (match > best)
|
||||
{
|
||||
best = match;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.has_subject.
|
||||
*/
|
||||
static id_match_t has_issuer(private_x509_ocsp_request_t *this,
|
||||
identification_t *issuer)
|
||||
{
|
||||
certificate_t *ca = (certificate_t*)this->ca;
|
||||
|
||||
return ca->has_subject(ca, issuer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.issued_by
|
||||
*/
|
||||
static bool issued_by(private_x509_ocsp_request_t *this, certificate_t *issuer,
|
||||
bool sigcheck)
|
||||
{
|
||||
DBG1("OCSP request validation not implemented!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_public_key
|
||||
*/
|
||||
static public_key_t* get_public_key(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of x509_cert_t.get_validity.
|
||||
*/
|
||||
static bool get_validity(private_x509_ocsp_request_t *this, time_t *when,
|
||||
time_t *not_before, time_t *not_after)
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
if (this->cert)
|
||||
{
|
||||
cert = this->cert;
|
||||
}
|
||||
else
|
||||
{
|
||||
cert = (certificate_t*)this->ca;
|
||||
}
|
||||
return cert->get_validity(cert, when, not_before, not_after);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_encoding.
|
||||
*/
|
||||
static chunk_t get_encoding(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
return chunk_clone(this->encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.equals.
|
||||
*/
|
||||
static bool equals(private_x509_ocsp_request_t *this, certificate_t *other)
|
||||
{
|
||||
if (this == (private_x509_ocsp_request_t*)other)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (other->get_type(other) != CERT_X509_OCSP_REQUEST)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
/* check if we have the same X509 implementation */
|
||||
if (other->equals == (void*)equals)
|
||||
{
|
||||
return chunk_equals(this->encoding,
|
||||
((private_x509_ocsp_request_t*)other)->encoding);
|
||||
}
|
||||
/* TODO: compare against other implementation */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.asdf
|
||||
*/
|
||||
static private_x509_ocsp_request_t* get_ref(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
ref_get(&this->ref);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of x509_ocsp_request_t.destroy
|
||||
*/
|
||||
static void destroy(private_x509_ocsp_request_t *this)
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
DESTROY_IF((certificate_t*)this->ca);
|
||||
DESTROY_IF(this->requestor);
|
||||
DESTROY_IF(this->cert);
|
||||
DESTROY_IF(this->key);
|
||||
this->candidates->destroy_offset(this->candidates, offsetof(certificate_t, destroy));
|
||||
chunk_free(&this->nonce);
|
||||
chunk_free(&this->encoding);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create an empty but initialized OCSP request
|
||||
*/
|
||||
static private_x509_ocsp_request_t *create_empty()
|
||||
{
|
||||
private_x509_ocsp_request_t *this = malloc_thing(private_x509_ocsp_request_t);
|
||||
|
||||
this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
|
||||
this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject;
|
||||
this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
|
||||
this->public.interface.interface.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject;
|
||||
this->public.interface.interface.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer;
|
||||
this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
|
||||
this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
|
||||
this->public.interface.interface.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
|
||||
this->public.interface.interface.get_encoding = (chunk_t(*)(certificate_t*))get_encoding;
|
||||
this->public.interface.interface.equals = (bool(*)(certificate_t*, certificate_t *other))equals;
|
||||
this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
|
||||
this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy;
|
||||
|
||||
this->ca = NULL;
|
||||
this->requestor = NULL;
|
||||
this->cert = NULL;
|
||||
this->key = NULL;
|
||||
this->nonce = chunk_empty;
|
||||
this->encoding = chunk_empty;
|
||||
this->candidates = linked_list_create();
|
||||
this->ref = 1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
typedef struct private_builder_t private_builder_t;
|
||||
/**
|
||||
* Builder implementation for certificate loading
|
||||
*/
|
||||
struct private_builder_t {
|
||||
/** implements the builder interface */
|
||||
builder_t public;
|
||||
/** OCSP request to build */
|
||||
private_x509_ocsp_request_t *req;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.build
|
||||
*/
|
||||
static x509_ocsp_request_t *build(private_builder_t *this)
|
||||
{
|
||||
private_x509_ocsp_request_t *req;
|
||||
|
||||
req = this->req;
|
||||
free(this);
|
||||
if (req->ca)
|
||||
{
|
||||
req->encoding = build_OCSPRequest(req);
|
||||
return &req->public;
|
||||
}
|
||||
destroy(req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.add
|
||||
*/
|
||||
static void add(private_builder_t *this, builder_part_t part, ...)
|
||||
{
|
||||
va_list args;
|
||||
certificate_t *cert;
|
||||
|
||||
va_start(args, part);
|
||||
switch (part)
|
||||
{
|
||||
case BUILD_CA_CERT:
|
||||
cert = va_arg(args, certificate_t*);
|
||||
if (cert->get_type(cert) == CERT_X509)
|
||||
{
|
||||
this->req->ca = (x509_t*)cert;
|
||||
}
|
||||
else
|
||||
{
|
||||
cert->destroy(cert);
|
||||
}
|
||||
break;
|
||||
case BUILD_CERT:
|
||||
cert = va_arg(args, certificate_t*);
|
||||
if (cert->get_type(cert) == CERT_X509)
|
||||
{
|
||||
this->req->candidates->insert_last(this->req->candidates, cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
cert->destroy(cert);
|
||||
}
|
||||
break;
|
||||
case BUILD_SIGNING_CERT:
|
||||
this->req->cert = va_arg(args, certificate_t*);
|
||||
break;
|
||||
case BUILD_SIGNING_KEY:
|
||||
this->req->key = va_arg(args, private_key_t*);
|
||||
break;
|
||||
case BUILD_SUBJECT:
|
||||
this->req->requestor = va_arg(args, identification_t*);
|
||||
break;
|
||||
default:
|
||||
DBG1("ignoring unsupported build part %N", builder_part_names, part);
|
||||
break;
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder construction function
|
||||
*/
|
||||
builder_t *x509_ocsp_request_builder(certificate_type_t type)
|
||||
{
|
||||
private_builder_t *this;
|
||||
|
||||
if (type != CERT_X509_OCSP_REQUEST)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_builder_t);
|
||||
|
||||
this->req = create_empty();
|
||||
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||
this->public.build = (void*(*)(builder_t *this))build;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup x509_ocsp_request x509_ocsp_request
|
||||
* @{ @ingroup x509_p
|
||||
*/
|
||||
|
||||
#ifndef X509_OCSP_REQUEST_H_
|
||||
#define X509_OCSP_REQUEST_H_
|
||||
|
||||
#include <credentials/certificates/ocsp_request.h>
|
||||
|
||||
typedef struct x509_ocsp_request_t x509_ocsp_request_t;
|
||||
|
||||
/**
|
||||
* Implementation of ocsp_request_t using own ASN1 parser.
|
||||
*/
|
||||
struct x509_ocsp_request_t {
|
||||
|
||||
/**
|
||||
* Implements the ocsp_request_t interface
|
||||
*/
|
||||
ocsp_request_t interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the building facility for OCSP requests.
|
||||
*
|
||||
* The resulting builder accepts:
|
||||
* BUILD_CA_CERT: CA of the checked certificates, exactly one
|
||||
* BUILD_CERT: certificates to check with the request, at least one
|
||||
* BUILD_SUBJECT: subject requesting check, optional
|
||||
* BUILD_SIGNING_CERT: certificate to create requestor signature, optional
|
||||
* BUILD_SIGNING_KEY: private key to create requestor signature, optional
|
||||
*
|
||||
* @param type certificate type, CERT_X509_OCSP_REQUEST only
|
||||
* @return builder instance to build OCSP requests
|
||||
*/
|
||||
builder_t *x509_ocsp_request_builder(certificate_type_t type);
|
||||
|
||||
#endif /* X509_OCSP_REQUEST_H_ @}*/
|
||||
@@ -0,0 +1,928 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Copyright (C) 2007 Andreas Steffen
|
||||
* Hochschule für Technik Rapperswil
|
||||
* Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "x509_ocsp_response.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <asn1/oid.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <utils/identification.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
#include <credentials/certificates/crl.h>
|
||||
|
||||
typedef struct private_x509_ocsp_response_t private_x509_ocsp_response_t;
|
||||
|
||||
/**
|
||||
* Private data of a ocsp_t object.
|
||||
*/
|
||||
struct private_x509_ocsp_response_t {
|
||||
/**
|
||||
* Public interface for this ocsp object.
|
||||
*/
|
||||
x509_ocsp_response_t public;
|
||||
|
||||
/**
|
||||
* complete encoded OCSP response
|
||||
*/
|
||||
chunk_t data;
|
||||
|
||||
/**
|
||||
* data for signature verficiation
|
||||
*/
|
||||
chunk_t tbsResponseData;
|
||||
|
||||
/**
|
||||
* signature algorithm (OID)
|
||||
*/
|
||||
int signatureAlgorithm;
|
||||
|
||||
/**
|
||||
* signature value
|
||||
*/
|
||||
chunk_t signature;
|
||||
|
||||
/**
|
||||
* name or keyid of the responder
|
||||
*/
|
||||
identification_t *responderId;
|
||||
|
||||
/**
|
||||
* time of response production
|
||||
*/
|
||||
time_t producedAt;
|
||||
|
||||
/**
|
||||
* list of included certificates
|
||||
*/
|
||||
linked_list_t *certs;
|
||||
|
||||
/**
|
||||
* Linked list of OCSP responses, single_response_t
|
||||
*/
|
||||
linked_list_t *responses;
|
||||
|
||||
/**
|
||||
* Nonce required for ocsp request and response
|
||||
*/
|
||||
chunk_t nonce;
|
||||
|
||||
/**
|
||||
* reference counter
|
||||
*/
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* single response contained in OCSP response
|
||||
*/
|
||||
typedef struct {
|
||||
/** hash algorithm OID to for the two hashes */
|
||||
int hashAlgorithm;
|
||||
/** hash of issuer DN */
|
||||
chunk_t issuerNameHash;
|
||||
/** issuerKeyID */
|
||||
chunk_t issuerKeyHash;
|
||||
/** serial number of certificate */
|
||||
chunk_t serialNumber;
|
||||
/** OCSP certificate status */
|
||||
cert_validation_t status;
|
||||
/** time of revocation, if revoked */
|
||||
time_t revocationTime;
|
||||
/** revocation reason, if revoked */
|
||||
crl_reason_t revocationReason;
|
||||
/** creation of associated CRL */
|
||||
time_t thisUpdate;
|
||||
/** creation of next CRL */
|
||||
time_t nextUpdate;
|
||||
} single_response_t;
|
||||
|
||||
/* our OCSP response version implementation */
|
||||
#define OCSP_BASIC_RESPONSE_VERSION 1
|
||||
|
||||
/* some OCSP specific prefabricated ASN.1 constants */
|
||||
static u_char ASN1_nonce_oid_str[] = {
|
||||
0x06, 0x09,
|
||||
0x2B, 0x06,
|
||||
0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
|
||||
};
|
||||
|
||||
static u_char ASN1_response_oid_str[] = {
|
||||
0x06, 0x09,
|
||||
0x2B, 0x06,
|
||||
0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
|
||||
};
|
||||
|
||||
static u_char ASN1_response_content_str[] = {
|
||||
0x04, 0x0D,
|
||||
0x30, 0x0B,
|
||||
0x06, 0x09,
|
||||
0x2B, 0x06,
|
||||
0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
|
||||
};
|
||||
|
||||
static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str);
|
||||
static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str);
|
||||
static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str);
|
||||
|
||||
/* asn.1 definitions for parsing */
|
||||
|
||||
static const asn1Object_t ocspResponseObjects[] = {
|
||||
{ 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
|
||||
{ 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
|
||||
{ 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
|
||||
{ 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
|
||||
{ 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
|
||||
};
|
||||
|
||||
#define OCSP_RESPONSE_STATUS 1
|
||||
#define OCSP_RESPONSE_TYPE 4
|
||||
#define OCSP_RESPONSE 5
|
||||
#define OCSP_RESPONSE_ROOF 7
|
||||
|
||||
static const asn1Object_t basicResponseObjects[] = {
|
||||
{ 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
|
||||
ASN1_DEF }, /* 2 */
|
||||
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
|
||||
{ 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
|
||||
{ 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
|
||||
{ 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
|
||||
{ 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
|
||||
{ 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
|
||||
{ 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
|
||||
{ 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
|
||||
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
|
||||
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
|
||||
{ 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
|
||||
ASN1_DEF }, /* 16 */
|
||||
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
|
||||
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
|
||||
{ 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
|
||||
{ 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
|
||||
{ 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
|
||||
{ 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */
|
||||
};
|
||||
|
||||
#define BASIC_RESPONSE_TBS_DATA 1
|
||||
#define BASIC_RESPONSE_VERSION 3
|
||||
#define BASIC_RESPONSE_ID_BY_NAME 5
|
||||
#define BASIC_RESPONSE_ID_BY_KEY 8
|
||||
#define BASIC_RESPONSE_PRODUCED_AT 10
|
||||
#define BASIC_RESPONSE_RESPONSES 11
|
||||
#define BASIC_RESPONSE_EXT_ID 15
|
||||
#define BASIC_RESPONSE_CRITICAL 16
|
||||
#define BASIC_RESPONSE_EXT_VALUE 17
|
||||
#define BASIC_RESPONSE_ALGORITHM 20
|
||||
#define BASIC_RESPONSE_SIGNATURE 21
|
||||
#define BASIC_RESPONSE_CERTIFICATE 24
|
||||
#define BASIC_RESPONSE_ROOF 27
|
||||
|
||||
static const asn1Object_t responsesObjects[] = {
|
||||
{ 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
|
||||
{ 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
|
||||
{ 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
|
||||
};
|
||||
|
||||
#define RESPONSES_SINGLE_RESPONSE 1
|
||||
#define RESPONSES_ROOF 3
|
||||
|
||||
static const asn1Object_t singleResponseObjects[] = {
|
||||
{ 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
|
||||
{ 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
|
||||
{ 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
|
||||
{ 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
|
||||
{ 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
|
||||
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
|
||||
{ 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
|
||||
{ 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
|
||||
{ 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
|
||||
{ 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
|
||||
{ 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
|
||||
{ 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
|
||||
{ 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
|
||||
{ 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
|
||||
{ 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
|
||||
{ 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
|
||||
{ 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
|
||||
{ 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
|
||||
{ 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
|
||||
{ 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
|
||||
ASN1_DEF }, /* 24 */
|
||||
{ 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */
|
||||
};
|
||||
|
||||
#define SINGLE_RESPONSE_ALGORITHM 2
|
||||
#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
|
||||
#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
|
||||
#define SINGLE_RESPONSE_SERIAL_NUMBER 5
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
|
||||
#define SINGLE_RESPONSE_THIS_UPDATE 16
|
||||
#define SINGLE_RESPONSE_NEXT_UPDATE 18
|
||||
#define SINGLE_RESPONSE_EXT_ID 23
|
||||
#define SINGLE_RESPONSE_CRITICAL 24
|
||||
#define SINGLE_RESPONSE_EXT_VALUE 25
|
||||
#define SINGLE_RESPONSE_ROOF 28
|
||||
|
||||
/**
|
||||
* Implementaiton of ocsp_response_t.get_status
|
||||
*/
|
||||
static cert_validation_t get_status(private_x509_ocsp_response_t *this,
|
||||
x509_t *subject, x509_t *issuer,
|
||||
time_t *revocation_time,
|
||||
crl_reason_t *revocation_reason,
|
||||
time_t *this_update, time_t *next_update)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
single_response_t *response;
|
||||
cert_validation_t status = VALIDATION_FAILED;
|
||||
certificate_t *issuercert = &issuer->interface;
|
||||
|
||||
enumerator = this->responses->create_enumerator(this->responses);
|
||||
while (enumerator->enumerate(enumerator, &response))
|
||||
{
|
||||
hasher_t *hasher;
|
||||
identification_t *id;
|
||||
chunk_t hash;
|
||||
|
||||
/* check serial first, is cheaper */
|
||||
if (!chunk_equals(subject->get_serial(subject), response->serialNumber))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* check issuerKeyHash if available */
|
||||
if (response->issuerKeyHash.ptr)
|
||||
{
|
||||
public_key_t *public;
|
||||
|
||||
public = issuercert->get_public_key(issuercert);
|
||||
if (!public)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
switch (response->hashAlgorithm)
|
||||
{ /* TODO: generic mapper function */
|
||||
case OID_SHA1:
|
||||
id = public->get_id(public, ID_PUBKEY_SHA1);
|
||||
break;
|
||||
default:
|
||||
public->destroy(public);
|
||||
continue;
|
||||
}
|
||||
if (!chunk_equals(response->issuerKeyHash, id->get_encoding(id)))
|
||||
{
|
||||
public->destroy(public);
|
||||
continue;
|
||||
}
|
||||
public->destroy(public);
|
||||
}
|
||||
/* check issuerNameHash, if available */
|
||||
else if (response->issuerNameHash.ptr)
|
||||
{
|
||||
hasher = lib->crypto->create_hasher(lib->crypto,
|
||||
hasher_algorithm_from_oid(response->hashAlgorithm));
|
||||
if (!hasher)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
id = issuercert->get_subject(issuercert);
|
||||
hasher->allocate_hash(hasher, id->get_encoding(id), &hash);
|
||||
hasher->destroy(hasher);
|
||||
if (!chunk_equals(hash, response->issuerNameHash))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* got a match */
|
||||
status = response->status;
|
||||
*revocation_time = response->revocationTime;
|
||||
*revocation_reason = response->revocationReason;
|
||||
*this_update = response->thisUpdate;
|
||||
*next_update = response->nextUpdate;
|
||||
|
||||
break;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ocsp_response_t.create_cert_enumerator.
|
||||
*/
|
||||
static enumerator_t* create_cert_enumerator(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
return this->certs->create_enumerator(this->certs);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a single OCSP response
|
||||
*/
|
||||
static bool parse_singleResponse(private_x509_ocsp_response_t *this,
|
||||
chunk_t blob, int level0)
|
||||
{
|
||||
u_int level;
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
single_response_t *response;
|
||||
|
||||
response = malloc_thing(single_response_t);
|
||||
response->hashAlgorithm = OID_UNKNOWN;
|
||||
response->issuerNameHash = chunk_empty;
|
||||
response->issuerKeyHash = chunk_empty;
|
||||
response->serialNumber = chunk_empty;
|
||||
response->status = VALIDATION_FAILED;
|
||||
response->revocationTime = 0;
|
||||
response->revocationReason = CRL_UNSPECIFIED;
|
||||
response->thisUpdate = 0;
|
||||
response->nextUpdate = 0;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, FALSE);
|
||||
while (objectID < SINGLE_RESPONSE_ROOF)
|
||||
{
|
||||
if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
free(response);
|
||||
return FALSE;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case SINGLE_RESPONSE_ALGORITHM:
|
||||
response->hashAlgorithm = parse_algorithmIdentifier(object, level+1, NULL);
|
||||
break;
|
||||
case SINGLE_RESPONSE_ISSUER_NAME_HASH:
|
||||
response->issuerNameHash = object;
|
||||
break;
|
||||
case SINGLE_RESPONSE_ISSUER_KEY_HASH:
|
||||
response->issuerKeyHash = object;
|
||||
break;
|
||||
case SINGLE_RESPONSE_SERIAL_NUMBER:
|
||||
response->serialNumber = object;
|
||||
break;
|
||||
case SINGLE_RESPONSE_CERT_STATUS_GOOD:
|
||||
response->status = VALIDATION_GOOD;
|
||||
break;
|
||||
case SINGLE_RESPONSE_CERT_STATUS_REVOKED:
|
||||
response->status = VALIDATION_REVOKED;
|
||||
break;
|
||||
case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
|
||||
response->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
|
||||
if (object.len == 1)
|
||||
{
|
||||
response->revocationReason = *object.ptr;
|
||||
}
|
||||
break;
|
||||
case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
|
||||
response->status = VALIDATION_FAILED;
|
||||
break;
|
||||
case SINGLE_RESPONSE_THIS_UPDATE:
|
||||
response->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case SINGLE_RESPONSE_NEXT_UPDATE:
|
||||
response->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
this->responses->insert_last(this->responses, response);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse all contained responses
|
||||
*/
|
||||
static bool parse_responses(private_x509_ocsp_response_t *this,
|
||||
chunk_t blob, int level0)
|
||||
{
|
||||
u_int level;
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, FALSE);
|
||||
while (objectID < RESPONSES_ROOF)
|
||||
{
|
||||
if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case RESPONSES_SINGLE_RESPONSE:
|
||||
if (!parse_singleResponse(this, object, level+1))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a basicOCSPResponse
|
||||
*/
|
||||
static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this,
|
||||
chunk_t blob, int level0)
|
||||
{
|
||||
u_int level, version;
|
||||
asn1_ctx_t ctx;
|
||||
bool critical;
|
||||
chunk_t object, responses = chunk_empty;
|
||||
int objectID = 0;
|
||||
int extn_oid = OID_UNKNOWN;
|
||||
certificate_t *cert;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, FALSE);
|
||||
while (objectID < BASIC_RESPONSE_ROOF)
|
||||
{
|
||||
if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case BASIC_RESPONSE_TBS_DATA:
|
||||
this->tbsResponseData = object;
|
||||
break;
|
||||
case BASIC_RESPONSE_VERSION:
|
||||
version = (object.len)? (1 + (u_int)*object.ptr) : 1;
|
||||
if (version != OCSP_BASIC_RESPONSE_VERSION)
|
||||
{
|
||||
DBG1("OCSP ResponseData version %d not supported", version);
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case BASIC_RESPONSE_ID_BY_NAME:
|
||||
this->responderId = identification_create_from_encoding(
|
||||
ID_DER_ASN1_DN, object);
|
||||
DBG3(" %D", this->responderId);
|
||||
break;
|
||||
case BASIC_RESPONSE_ID_BY_KEY:
|
||||
this->responderId = identification_create_from_encoding(
|
||||
ID_PUBKEY_INFO_SHA1, object);
|
||||
DBG3(" %D", this->responderId);
|
||||
break;
|
||||
case BASIC_RESPONSE_PRODUCED_AT:
|
||||
this->producedAt = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case BASIC_RESPONSE_RESPONSES:
|
||||
responses = object;
|
||||
break;
|
||||
case BASIC_RESPONSE_EXT_ID:
|
||||
extn_oid = known_oid(object);
|
||||
break;
|
||||
case BASIC_RESPONSE_CRITICAL:
|
||||
critical = object.len && *object.ptr;
|
||||
DBG3(" %s", critical ? "TRUE" : "FALSE");
|
||||
break;
|
||||
case BASIC_RESPONSE_EXT_VALUE:
|
||||
if (extn_oid == OID_NONCE)
|
||||
{
|
||||
this->nonce = object;
|
||||
}
|
||||
break;
|
||||
case BASIC_RESPONSE_ALGORITHM:
|
||||
this->signatureAlgorithm = parse_algorithmIdentifier(
|
||||
object, level+1, NULL);
|
||||
break;
|
||||
case BASIC_RESPONSE_SIGNATURE:
|
||||
this->signature = object;
|
||||
break;
|
||||
case BASIC_RESPONSE_CERTIFICATE:
|
||||
{
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,CERT_X509,
|
||||
BUILD_BLOB_ASN1_DER, chunk_clone(object),
|
||||
BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
this->certs->insert_last(this->certs, cert);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
if (!this->responderId)
|
||||
{
|
||||
this->responderId = identification_create_from_encoding(ID_ANY, chunk_empty);
|
||||
}
|
||||
return parse_responses(this, responses, level + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse OCSPResponse object
|
||||
*/
|
||||
static bool parse_OCSPResponse(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
int responseType = OID_UNKNOWN;
|
||||
ocsp_status_t status;
|
||||
|
||||
asn1_init(&ctx, this->data, 0, FALSE, FALSE);
|
||||
while (objectID < OCSP_RESPONSE_ROOF)
|
||||
{
|
||||
if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case OCSP_RESPONSE_STATUS:
|
||||
status = (ocsp_status_t)*object.ptr;
|
||||
switch (status)
|
||||
{
|
||||
case OCSP_SUCCESSFUL:
|
||||
break;
|
||||
default:
|
||||
DBG1("OCSP response status: %N",
|
||||
ocsp_status_names, status);
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case OCSP_RESPONSE_TYPE:
|
||||
responseType = known_oid(object);
|
||||
break;
|
||||
case OCSP_RESPONSE:
|
||||
switch (responseType)
|
||||
{
|
||||
case OID_BASIC:
|
||||
return parse_basicOCSPResponse(this, object, level+1);
|
||||
default:
|
||||
DBG1("OCSP response type %#B not supported", &object);
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_type
|
||||
*/
|
||||
static certificate_type_t get_type(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
return CERT_X509_OCSP_RESPONSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_issuer
|
||||
*/
|
||||
static identification_t* get_issuer(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
return this->responderId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.has_subject.
|
||||
*/
|
||||
static id_match_t has_issuer(private_x509_ocsp_response_t *this,
|
||||
identification_t *issuer)
|
||||
{
|
||||
return this->responderId->matches(this->responderId, issuer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.issued_by
|
||||
*/
|
||||
static bool issued_by(private_x509_ocsp_response_t *this, certificate_t *issuer,
|
||||
bool sigcheck)
|
||||
{
|
||||
public_key_t *key;
|
||||
signature_scheme_t scheme;
|
||||
bool valid;
|
||||
x509_t *x509 = (x509_t*)issuer;
|
||||
|
||||
if (issuer->get_type(issuer) != CERT_X509)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (this->responderId->get_type(this->responderId) == ID_DER_ASN1_DN)
|
||||
{
|
||||
if (!this->responderId->equals(this->responderId,
|
||||
issuer->get_subject(issuer)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool equal;
|
||||
public_key_t *public = issuer->get_public_key(issuer);
|
||||
|
||||
if (public == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
equal = this->responderId->equals(this->responderId,
|
||||
public->get_id(public, ID_PUBKEY_SHA1));
|
||||
public->destroy(public);
|
||||
if (!equal)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (!(x509->get_flags(x509) & X509_OCSP_SIGNER))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!sigcheck)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
/* TODO: generic OID to scheme mapper? */
|
||||
switch (this->signatureAlgorithm)
|
||||
{
|
||||
case OID_MD5_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
|
||||
break;
|
||||
case OID_SHA1_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
|
||||
break;
|
||||
case OID_SHA256_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
|
||||
break;
|
||||
case OID_SHA384_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
|
||||
break;
|
||||
case OID_SHA512_WITH_RSA:
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
key = issuer->get_public_key(issuer);
|
||||
if (key == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
valid = key->verify(key, scheme, this->tbsResponseData, this->signature);
|
||||
key->destroy(key);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_public_key
|
||||
*/
|
||||
static public_key_t* get_public_key(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of x509_cert_t.get_validity.
|
||||
*/
|
||||
static bool get_validity(private_x509_ocsp_response_t *this, time_t *when,
|
||||
time_t *not_before, time_t *not_after)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
if (when == NULL)
|
||||
{
|
||||
t = time(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = *when;
|
||||
}
|
||||
if (not_before)
|
||||
{
|
||||
*not_before = this->producedAt;
|
||||
}
|
||||
if (not_after)
|
||||
{
|
||||
*not_after = ~0;
|
||||
}
|
||||
/* valid from produceAt up to infinity */
|
||||
if (t >= this->producedAt)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_encoding.
|
||||
*/
|
||||
static chunk_t get_encoding(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
return chunk_clone(this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.equals.
|
||||
*/
|
||||
static bool equals(private_x509_ocsp_response_t *this, certificate_t *other)
|
||||
{
|
||||
if (this == (private_x509_ocsp_response_t*)other)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (other->get_type(other) != CERT_X509_OCSP_RESPONSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
/* check if we have the same X509 implementation */
|
||||
if (other->equals == (void*)equals)
|
||||
{
|
||||
return chunk_equals(this->data,
|
||||
((private_x509_ocsp_response_t*)other)->data);
|
||||
}
|
||||
/* TODO: compare against other implementation */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of certificate_t.get_ref
|
||||
*/
|
||||
static private_x509_ocsp_response_t* get_ref(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
ref_get(&this->ref);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ocsp_t.destroy.
|
||||
*/
|
||||
static void destroy(private_x509_ocsp_response_t *this)
|
||||
{
|
||||
if (ref_put(&this->ref))
|
||||
{
|
||||
this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy));
|
||||
this->responses->destroy_function(this->responses, free);
|
||||
DESTROY_IF(this->responderId);
|
||||
free(this->data.ptr);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load an OCSP response
|
||||
*/
|
||||
static x509_ocsp_response_t *load(chunk_t data)
|
||||
{
|
||||
private_x509_ocsp_response_t *this;
|
||||
|
||||
this = malloc_thing(private_x509_ocsp_response_t);
|
||||
|
||||
this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
|
||||
this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_issuer;
|
||||
this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
|
||||
this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_issuer;
|
||||
this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer;
|
||||
this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
|
||||
this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
|
||||
this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
|
||||
this->public.interface.certificate.get_encoding = (chunk_t(*)(certificate_t*))get_encoding;
|
||||
this->public.interface.certificate.equals = (bool(*)(certificate_t*, certificate_t *other))equals;
|
||||
this->public.interface.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
|
||||
this->public.interface.certificate.destroy = (void (*)(certificate_t *this))destroy;
|
||||
this->public.interface.get_status = (cert_validation_t(*)(ocsp_response_t*, x509_t *subject, x509_t *issuer, time_t *revocation_time,crl_reason_t *revocation_reason,time_t *this_update, time_t *next_update))get_status;
|
||||
this->public.interface.create_cert_enumerator = (enumerator_t*(*)(ocsp_response_t*))create_cert_enumerator;
|
||||
|
||||
this->ref = 1;
|
||||
this->data = data;
|
||||
this->tbsResponseData = chunk_empty;
|
||||
this->responderId = NULL;
|
||||
this->producedAt = UNDEFINED_TIME;
|
||||
this->responses = linked_list_create();
|
||||
this->nonce = chunk_empty;
|
||||
this->signatureAlgorithm = OID_UNKNOWN;
|
||||
this->signature = chunk_empty;
|
||||
this->certs = linked_list_create();
|
||||
|
||||
if (!parse_OCSPResponse(this))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
||||
typedef struct private_builder_t private_builder_t;
|
||||
/**
|
||||
* Builder implementation for certificate loading
|
||||
*/
|
||||
struct private_builder_t {
|
||||
/** implements the builder interface */
|
||||
builder_t public;
|
||||
/** loaded response */
|
||||
x509_ocsp_response_t *res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.build
|
||||
*/
|
||||
static x509_ocsp_response_t *build(private_builder_t *this)
|
||||
{
|
||||
x509_ocsp_response_t *res = this->res;
|
||||
|
||||
free(this);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of builder_t.add
|
||||
*/
|
||||
static void add(private_builder_t *this, builder_part_t part, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (this->res)
|
||||
{
|
||||
DBG1("ignoring surplus build part %N", builder_part_names, part);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (part)
|
||||
{
|
||||
case BUILD_BLOB_ASN1_DER:
|
||||
{
|
||||
va_start(args, part);
|
||||
this->res = load(va_arg(args, chunk_t));
|
||||
va_end(args);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1("ignoring unsupported build part %N", builder_part_names, part);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder construction function
|
||||
*/
|
||||
builder_t *x509_ocsp_response_builder(certificate_type_t type)
|
||||
{
|
||||
private_builder_t *this;
|
||||
|
||||
if (type != CERT_X509_OCSP_RESPONSE)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(private_builder_t);
|
||||
|
||||
this->res = NULL;
|
||||
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||
this->public.build = (void*(*)(builder_t *this))build;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup x509_ocsp_response x509_ocsp_response
|
||||
* @{ @ingroup x509_p
|
||||
*/
|
||||
|
||||
#ifndef X509_OCSP_RESPONSE_H_
|
||||
#define X509_OCSP_RESPONSE_H_
|
||||
|
||||
#include <credentials/certificates/ocsp_response.h>
|
||||
|
||||
typedef struct x509_ocsp_response_t x509_ocsp_response_t;
|
||||
|
||||
/**
|
||||
* Implementation of ocsp_response_t using own ASN1 parser.
|
||||
*/
|
||||
struct x509_ocsp_response_t {
|
||||
|
||||
/**
|
||||
* Implements the ocsp_response_t interface
|
||||
*/
|
||||
ocsp_response_t interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the building facility for OCSP responses.
|
||||
*
|
||||
* @param type certificate type, CERT_X509_OCSP_RESPONSE only
|
||||
* @return builder instance to build OCSP responses
|
||||
*/
|
||||
builder_t *x509_ocsp_response_builder(certificate_type_t type);
|
||||
|
||||
#endif /* X509_OCSP_RESPONSE_H_ @}*/
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "x509_plugin.h"
|
||||
|
||||
#include <library.h>
|
||||
#include "x509_cert.h"
|
||||
#include "x509_crl.h"
|
||||
#include "x509_ocsp_request.h"
|
||||
#include "x509_ocsp_response.h"
|
||||
|
||||
typedef struct private_x509_plugin_t private_x509_plugin_t;
|
||||
|
||||
/**
|
||||
* private data of x509_plugin
|
||||
*/
|
||||
struct private_x509_plugin_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
x509_plugin_t public;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of x509_plugin_t.x509troy
|
||||
*/
|
||||
static void destroy(private_x509_plugin_t *this)
|
||||
{
|
||||
lib->creds->remove_builder(lib->creds,
|
||||
(builder_constructor_t)x509_cert_builder);
|
||||
lib->creds->remove_builder(lib->creds,
|
||||
(builder_constructor_t)x509_crl_builder);
|
||||
lib->creds->remove_builder(lib->creds,
|
||||
(builder_constructor_t)x509_ocsp_request_builder);
|
||||
lib->creds->remove_builder(lib->creds,
|
||||
(builder_constructor_t)x509_ocsp_response_builder);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
private_x509_plugin_t *this = malloc_thing(private_x509_plugin_t);
|
||||
|
||||
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||
(builder_constructor_t)x509_cert_builder);
|
||||
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
|
||||
(builder_constructor_t)x509_crl_builder);
|
||||
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
|
||||
(builder_constructor_t)x509_ocsp_request_builder);
|
||||
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
|
||||
(builder_constructor_t)x509_ocsp_response_builder);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup x509_p x509
|
||||
* @ingroup plugins
|
||||
*
|
||||
* @defgroup x509_plugin x509_plugin
|
||||
* @{ @ingroup x509_p
|
||||
*/
|
||||
|
||||
#ifndef X509_PLUGIN_H_
|
||||
#define X509_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct x509_plugin_t x509_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin implementing x509, CRL and OCSP certificates.
|
||||
*/
|
||||
struct x509_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a x509_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* X509_PLUGIN_H_ @}*/
|
||||
Reference in New Issue
Block a user