merged the modularization branch (credentials) back to trunk

This commit is contained in:
Martin Willi
2008-03-13 14:14:44 +00:00
parent 2df655134c
commit 552cc11b1f
495 changed files with 30378 additions and 23843 deletions
+10
View File
@@ -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_ @}*/
+10
View File
@@ -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_ @}*/
+14
View File
@@ -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
+214
View File
@@ -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);
}
+93
View File
@@ -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_ @}*/
+137
View File
@@ -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);
}
+51
View File
@@ -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_ @}*/
+10
View File
@@ -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
+392
View File
@@ -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, &current))
{
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_ @}*/
+49
View File
@@ -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_ @}*/
+129
View File
@@ -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;
}
+53
View File
@@ -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_ @}*/
+717
View File
@@ -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;
}
+48
View File
@@ -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, &current))
{
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_ @}*/