aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/conftest/README1
-rw-r--r--src/conftest/conftest.c22
-rw-r--r--src/conftest/hooks/reset_seq.c77
-rw-r--r--src/frontends/android/res/values-ru/arrays.xml21
-rw-r--r--src/frontends/android/res/values-ru/strings.xml105
-rw-r--r--src/frontends/android/res/values-ua/arrays.xml21
-rw-r--r--src/frontends/android/res/values-ua/strings.xml106
-rw-r--r--src/libcharon/encoding/payloads/cert_payload.c18
-rw-r--r--src/libcharon/encoding/payloads/cert_payload.h14
-rw-r--r--src/libcharon/encoding/payloads/certreq_payload.h2
-rw-r--r--src/libcharon/encoding/payloads/eap_payload.c8
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c2
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c155
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_cert_pre.c253
-rw-r--r--src/libimcv/imv/imv_msg.c18
-rw-r--r--src/libimcv/imv/imv_msg.h6
-rwxr-xr-xsrc/libimcv/plugins/imv_os/pacman.sh22
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation.c4
-rw-r--r--src/libstrongswan/Makefile.am7
-rw-r--r--src/libstrongswan/bio/bio_writer.h7
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_pkcs7.c6
-rw-r--r--src/libstrongswan/plugins/rdrand/Makefile.am16
-rw-r--r--src/libstrongswan/plugins/rdrand/rdrand_plugin.c137
-rw-r--r--src/libstrongswan/plugins/rdrand/rdrand_plugin.h42
-rw-r--r--src/libstrongswan/plugins/rdrand/rdrand_rng.c442
-rw-r--r--src/libstrongswan/plugins/rdrand/rdrand_rng.h47
26 files changed, 1369 insertions, 190 deletions
diff --git a/src/conftest/README b/src/conftest/README
index a1b1b3e3a..133ae603c 100644
--- a/src/conftest/README
+++ b/src/conftest/README
@@ -239,6 +239,7 @@ Currently, the following hooks are defined with the following options:
rebuild_auth: rebuild AUTH payload, i.e. if ID payload changed
reset_seq: Reset sequence numbers of an ESP SA
delay: Seconds to delay reset after SA established
+ oseq: Sequence number to set, default is 0
set_critical: Set critical bit on existing payloads:
request: yes to set in request, no in response
id: IKEv2 message identifier of message to mangle payloads
diff --git a/src/conftest/conftest.c b/src/conftest/conftest.c
index bb4c5ed97..c2251effa 100644
--- a/src/conftest/conftest.c
+++ b/src/conftest/conftest.c
@@ -378,6 +378,22 @@ static void load_log_levels(file_logger_t *logger, char *section)
}
/**
+ * Load logger options for a logger from section
+ */
+static void load_logger_options(file_logger_t *logger, char *section)
+{
+ bool ike_name;
+ char *time_format;
+
+ time_format = conftest->test->get_str(conftest->test,
+ "log.%s.time_format", NULL, section);
+ ike_name = conftest->test->get_bool(conftest->test,
+ "log.%s.ike_name", FALSE, section);
+
+ logger->set_options(logger, time_format, ike_name);
+}
+
+/**
* Load logger configuration
*/
static void load_loggers(file_logger_t *logger)
@@ -386,6 +402,10 @@ static void load_loggers(file_logger_t *logger)
char *section;
load_log_levels(logger, "stdout");
+ load_logger_options(logger, "stdout");
+ /* Re-add the logger to propagate configuration changes to the
+ * logging system */
+ charon->bus->add_logger(charon->bus, &logger->logger);
enumerator = conftest->test->create_section_enumerator(conftest->test, "log");
while (enumerator->enumerate(enumerator, &section))
@@ -393,7 +413,7 @@ static void load_loggers(file_logger_t *logger)
if (!streq(section, "stdout"))
{
logger = file_logger_create(section);
- logger->set_options(logger, NULL, FALSE);
+ load_logger_options(logger, section);
logger->open(logger, FALSE, FALSE);
load_log_levels(logger, section);
charon->bus->add_logger(charon->bus, &logger->logger);
diff --git a/src/conftest/hooks/reset_seq.c b/src/conftest/hooks/reset_seq.c
index 6fb7a2e4b..100977324 100644
--- a/src/conftest/hooks/reset_seq.c
+++ b/src/conftest/hooks/reset_seq.c
@@ -12,6 +12,27 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
+/*
+ * Copyright (C) 2012 achelos GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
#include "hook.h"
@@ -40,21 +61,46 @@ struct private_reset_seq_t {
* Delay for reset
*/
int delay;
+
+ /**
+ * Sequence number to set for outgoing packages
+ */
+ int oseq;
+};
+
+typedef struct reset_cb_data_t reset_cb_data_t;
+
+/**
+ * Data needed for the callback job
+ */
+struct reset_cb_data_t {
+
+ /**
+ * The SA to modify
+ */
+ struct xfrm_usersa_id usersa;
+
+ /**
+ * Sequence number to set for outgoing packages
+ */
+ int oseq;
};
/**
* Callback job
*/
-static job_requeue_t reset_cb(struct xfrm_usersa_id *data)
+static job_requeue_t reset_cb(struct reset_cb_data_t *data)
{
netlink_buf_t request;
struct nlmsghdr *hdr;
struct xfrm_aevent_id *id;
struct rtattr *rthdr;
+ struct xfrm_replay_state *rpstate;
struct sockaddr_nl addr;
int s, len;
- DBG1(DBG_CFG, "resetting sequence number of SPI 0x%x", htonl(data->spi));
+ DBG1(DBG_CFG, "setting sequence number of SPI 0x%x to %d",
+ htonl(data->usersa.spi), data->oseq);
memset(&request, 0, sizeof(request));
@@ -66,13 +112,22 @@ static job_requeue_t reset_cb(struct xfrm_usersa_id *data)
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
id = (struct xfrm_aevent_id*)NLMSG_DATA(hdr);
- id->sa_id = *data;
+ id->sa_id = data->usersa;
rthdr = XFRM_RTA(hdr, struct xfrm_aevent_id);
rthdr->rta_type = XFRMA_REPLAY_VAL;
rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
hdr->nlmsg_len += rthdr->rta_len;
+ /* xfrm_replay_state is the structure the kernel uses for
+ * replay detection, and the oseq element contains the
+ * sequence number for outgoing packets. Currently, this
+ * function sets the other elements seq (records the number of
+ * incoming packets) and bitmask to zero, but they could be
+ * adjusted in the same way as oseq if required. */
+ rpstate = (struct xfrm_replay_state*)RTA_DATA(rthdr);
+ rpstate->oseq = data->oseq;
+
s = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
if (s == -1)
{
@@ -97,17 +152,21 @@ static job_requeue_t reset_cb(struct xfrm_usersa_id *data)
static void schedule_reset_job(private_reset_seq_t *this, host_t *dst,
u_int32_t spi)
{
- struct xfrm_usersa_id *data;
+ struct reset_cb_data_t *data;
chunk_t chunk;
INIT(data,
- .spi = spi,
- .family = dst->get_family(dst),
- .proto = IPPROTO_ESP,
+ .usersa = {
+ .spi = spi,
+ .family = dst->get_family(dst),
+ .proto = IPPROTO_ESP,
+ },
+ .oseq = this->oseq,
);
chunk = dst->get_address(dst);
- memcpy(&data->daddr, chunk.ptr, min(chunk.len, sizeof(xfrm_address_t)));
+ memcpy(&data->usersa.daddr, chunk.ptr,
+ min(chunk.len, sizeof(xfrm_address_t)));
lib->scheduler->schedule_job(lib->scheduler,
(job_t*)callback_job_create(
@@ -149,6 +208,8 @@ hook_t *reset_seq_hook_create(char *name)
},
.delay = conftest->test->get_int(conftest->test,
"hooks.%s.delay", 10, name),
+ .oseq = conftest->test->get_int(conftest->test,
+ "hooks.%s.oseq", 0, name),
);
return &this->hook;
diff --git a/src/frontends/android/res/values-ru/arrays.xml b/src/frontends/android/res/values-ru/arrays.xml
new file mode 100644
index 000000000..48a7219cc
--- /dev/null
+++ b/src/frontends/android/res/values-ru/arrays.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012 Dmitry Korzhevin
+
+ 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.
+-->
+<resources>
+ <!-- the order here must match the enum entries in VpnType.java -->
+ <string-array name="vpn_types">
+ <item>IKEv2 EAP (Логин/Пароль)</item>
+ <item>Сертификат IKEv2</item>
+ </string-array>
+</resources>
diff --git a/src/frontends/android/res/values-ru/strings.xml b/src/frontends/android/res/values-ru/strings.xml
new file mode 100644
index 000000000..afa21361b
--- /dev/null
+++ b/src/frontends/android/res/values-ru/strings.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012 Dmitry Korzhevin
+
+ 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.
+-->
+<resources>
+
+ <!-- Application -->
+ <string name="app_name">Клиент strongSwan VPN</string>
+ <string name="main_activity_name">strongSwan</string>
+ <string name="reload_trusted_certs">Обновить сертификат CA</string>
+ <string name="show_log">Журнал</string>
+ <string name="search">Поиск</string>
+ <string name="vpn_not_supported_title">VPN не поддерживается</string>
+ <string name="vpn_not_supported">Ваше устройство не поддерживат VPN приложение.\nПожалуйста свяжитесь с производителем.</string>
+ <string name="vpn_not_supported_during_lockdown">VPN соединения не поддерживаются в режиме lockdown.</string>
+ <string name="loading">Загрузка&#8230;</string>
+ <string name="profile_not_found">Профиль не найден</string>
+ <string name="strongswan_shortcut">Ссылка на strongSwan</string>
+
+ <!-- Log view -->
+ <string name="log_title">Журнал</string>
+ <string name="send_log">Отправить журнал</string>
+ <string name="empty_log">Журнал пуст</string>
+ <string name="log_mail_subject">strongSwan %1$s журнал</string>
+
+ <!-- VPN profile list -->
+ <string name="no_profiles">VPN профили не обнаружены.</string>
+ <string name="add_profile">Добавить VPN профиль</string>
+ <string name="edit_profile">Редактировать</string>
+ <string name="delete_profile">Удалить</string>
+ <string name="select_profiles">Выбрать профили</string>
+ <string name="profiles_deleted">Выбранные профили удалены</string>
+ <string name="no_profile_selected">Профили не выбраны</string>
+ <string name="one_profile_selected">Выбран профиль</string>
+ <string name="x_profiles_selected">%1$d прифиля(ей) выбрано"</string>
+
+ <!-- VPN profile details -->
+ <string name="profile_edit_save">Сохранить</string>
+ <string name="profile_edit_cancel">Отмена</string>
+ <string name="profile_name_label">Название профиля:</string>
+ <string name="profile_name_hint">(адрес шлюза)</string>
+ <string name="profile_gateway_label">Шлюз:</string>
+ <string name="profile_vpn_type_label">Тип:</string>
+ <string name="profile_username_label">Логин:</string>
+ <string name="profile_password_label">Пароль:</string>
+ <string name="profile_password_hint">(спросить если нужно)</string>
+ <string name="profile_user_certificate_label">Сертификат пользователя:</string>
+ <string name="profile_user_select_certificate_label">Выбрать сертификат пользователя</string>
+ <string name="profile_user_select_certificate">Выбрать сертификат пользователя</string>
+ <string name="profile_ca_label">Сертификат CA:</string>
+ <string name="profile_ca_auto_label">Выбрать автоматически</string>
+ <string name="profile_ca_select_certificate_label">Выбрать сертификат CA</string>
+ <string name="profile_ca_select_certificate">Выбрать CA сертификат</string>
+ <!-- Warnings/Notifications in the details view -->
+ <string name="alert_text_no_input_gateway">Пожалуйста введите адрес шлюза</string>
+ <string name="alert_text_no_input_username">Пожалуйста введите имя пользователя</string>
+ <string name="alert_text_nocertfound_title">Не выбран сертификат CA</string>
+ <string name="alert_text_nocertfound">Пожалуйста выберите один <i>Выбрать автоматически</i></string>
+
+ <!-- Trusted certificate selection -->
+ <string name="trusted_certs_title">Сертификаты CA</string>
+ <string name="no_certificates">Нет доступных сертификатов</string>
+ <string name="system_tab">Система</string>
+ <string name="user_tab">Пользователь</string>
+
+ <!-- VPN state fragment -->
+ <string name="state_label">Статус:</string>
+ <string name="profile_label">Профиль:</string>
+ <string name="disconnect">Отключить</string>
+ <string name="state_connecting">Соединение&#8230;</string>
+ <string name="state_connected">Соединен</string>
+ <string name="state_disconnecting">Отключение&#8230;</string>
+ <string name="state_disabled">Нет активных VPN</string>
+ <string name="state_error">Ошибка</string>
+
+ <!-- Dialogs -->
+ <string name="login_title">Введите пароль для соединения</string>
+ <string name="login_confirm">Соединить</string>
+ <string name="error_introduction">Ошибка подключения к VPN:</string>
+ <string name="error_lookup_failed">Не найден адрес шлюза.</string>
+ <string name="error_unreachable">Шлюз недоступен.</string>
+ <string name="error_peer_auth_failed">Ошибка авторизаци при подключении к шлюзу.</string>
+ <string name="error_auth_failed">Ошибка авторизации пользователя.</string>
+ <string name="error_generic">Неизвестная ошибка.</string>
+ <string name="connecting_title">Подключение: %1$s</string>
+ <string name="connecting_message">Подключение к VPN с \""%1$s\".</string>
+ <string name="vpn_connected">Соединение с VPN установлено</string>
+ <string name="vpn_profile_connected">Подключение к этому профилю VPN уже существует!</string>
+ <string name="reconnect">Переподключить</string>
+ <string name="connect_profile_question">Подключить %1$s?</string>
+ <string name="replaces_active_connection">Это заменит ваше текущее VPN соединение!</string>
+ <string name="connect">Соединить</string>
+
+</resources>
+
diff --git a/src/frontends/android/res/values-ua/arrays.xml b/src/frontends/android/res/values-ua/arrays.xml
new file mode 100644
index 000000000..bd4366405
--- /dev/null
+++ b/src/frontends/android/res/values-ua/arrays.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012 Dmitry Korzhevin
+
+ 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.
+-->
+<resources>
+ <!-- the order here must match the enum entries in VpnType.java -->
+ <string-array name="vpn_types">
+ <item>IKEv2 EAP (Логін/Пароль)</item>
+ <item>Сертифікати IKEv2</item>
+ </string-array>
+</resources>
diff --git a/src/frontends/android/res/values-ua/strings.xml b/src/frontends/android/res/values-ua/strings.xml
new file mode 100644
index 000000000..cb3ebee06
--- /dev/null
+++ b/src/frontends/android/res/values-ua/strings.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012 Dmitry Korzhevin
+ Copyright (C) 2013 Pavel Kopchyk
+
+ 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.
+-->
+<resources>
+
+ <!-- Application -->
+ <string name="app_name">strongSwan VPN клієнт</string>
+ <string name="main_activity_name">strongSwan</string>
+ <string name="reload_trusted_certs">Перезавантажити CA сертифікати</string>
+ <string name="show_log">Перегляд журналу</string>
+ <string name="search">Пошук</string>
+ <string name="vpn_not_supported_title">VPN не підтримуеться</string>
+ <string name="vpn_not_supported">Ваш пристрій не підтримує VPN.\nЗв'яжіться з виробником.</string>
+ <string name="vpn_not_supported_during_lockdown">VPN з'єднання не пітримується у режимі lockdown.</string>
+ <string name="loading">Завантаження&#8230;</string>
+ <string name="profile_not_found">Профіль не знайдено</string>
+ <string name="strongswan_shortcut">strongSwan посилання</string>
+
+ <!-- Log view -->
+ <string name="log_title">Журнал</string>
+ <string name="send_log">Відправити файл журналу</string>
+ <string name="empty_log">Журнал порожній</string>
+ <string name="log_mail_subject">strongSwan %1$s файл журналу</string>
+
+ <!-- VPN profile list -->
+ <string name="no_profiles">Немає VPN профілів</string>
+ <string name="add_profile">Додати VPN профіль</string>
+ <string name="edit_profile">Редагувати</string>
+ <string name="delete_profile">Видалити</string>
+ <string name="select_profiles">Обрати профіль</string>
+ <string name="profiles_deleted">Обрані профілі видалено</string>
+ <string name="no_profile_selected">Профіль не обрано</string>
+ <string name="one_profile_selected">Один профіль обрано</string>
+ <string name="x_profiles_selected">%1$d профілів обрано"</string>
+
+ <!-- VPN profile details -->
+ <string name="profile_edit_save">Зберегти</string>
+ <string name="profile_edit_cancel">Відміна</string>
+ <string name="profile_name_label">Назва профілю:</string>
+ <string name="profile_name_hint">(використовувати адресу шлюза)</string>
+ <string name="profile_gateway_label">Шлюз:</string>
+ <string name="profile_vpn_type_label">Тип:</string>
+ <string name="profile_username_label">Логін:</string>
+ <string name="profile_password_label">Пароль:</string>
+ <string name="profile_password_hint">(запитати якщо потрібно)</string>
+ <string name="profile_user_certificate_label">Сертифікат користувача:</string>
+ <string name="profile_user_select_certificate_label">Виберіть сертифікат користувача</string>
+ <string name="profile_user_select_certificate">Вибрати спеціальний сертифікат користувача</string>
+ <string name="profile_ca_label">Сертифікат CA:</string>
+ <string name="profile_ca_auto_label">Вибрати автоматично</string>
+ <string name="profile_ca_select_certificate_label">Вибрати сертифікат CA</string>
+ <string name="profile_ca_select_certificate">Вибрати спеціальний сертифікат CA</string>
+ <!-- Warnings/Notifications in the details view -->
+ <string name="alert_text_no_input_gateway">Введіть адресу шлюза тут</string>
+ <string name="alert_text_no_input_username">Введіть ім'я користувача тут</string>
+ <string name="alert_text_nocertfound_title">Не вибрано сертифікат CA</string>
+ <string name="alert_text_nocertfound">Будь ласка виберіть один <i>Вибрати автоматично</i></string>
+
+ <!-- Trusted certificate selection -->
+ <string name="trusted_certs_title">Сертифікати CA</string>
+ <string name="no_certificates">Немає сертифікатів</string>
+ <string name="system_tab">Система</string>
+ <string name="user_tab">Користувач</string>
+
+ <!-- VPN state fragment -->
+ <string name="state_label">Статус:</string>
+ <string name="profile_label">Профіль:</string>
+ <string name="disconnect">Роз'єднати</string>
+ <string name="state_connecting">Підключення&#8230;</string>
+ <string name="state_connected">Підключений</string>
+ <string name="state_disconnecting">Роз'єднання&#8230;</string>
+ <string name="state_disabled">Немає активних VPN</string>
+ <string name="state_error">Помилка</string>
+
+ <!-- Dialogs -->
+ <string name="login_title">Введіть пароль для з'єднання</string>
+ <string name="login_confirm">Підключити</string>
+ <string name="error_introduction">Помилка підлючення VPN:</string>
+ <string name="error_lookup_failed">Помилка пошуку адреси шлюза.</string>
+ <string name="error_unreachable">Немає зв'язку зі шлюзом.</string>
+ <string name="error_peer_auth_failed">Помилка перевірки данних аутентифікації шлюза.</string>
+ <string name="error_auth_failed">Помилка аутентифікації користувача.</string>
+ <string name="error_generic">Невідома помилка під час підключення.</string>
+ <string name="connecting_title">Підключення: %1$s</string>
+ <string name="connecting_message">Підключення VPN з \""%1$s\".</string>
+ <string name="vpn_connected">VPN підключено</string>
+ <string name="vpn_profile_connected">Цей VPN профіль зараз підключений!</string>
+ <string name="reconnect">Перепідключитися</string>
+ <string name="connect_profile_question">Підключити %1$s?</string>
+ <string name="replaces_active_connection">Ця дія замінить ваше поточне VPN з'єднання!</string>
+ <string name="connect">Підключити</string>
+
+</resources>
+
diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c
index 3a230b91e..a32f5705d 100644
--- a/src/libcharon/encoding/payloads/cert_payload.c
+++ b/src/libcharon/encoding/payloads/cert_payload.c
@@ -234,6 +234,23 @@ METHOD(cert_payload_t, get_cert, certificate_t*,
BUILD_BLOB_ASN1_DER, this->data, BUILD_END);
}
+METHOD(cert_payload_t, get_container, container_t*,
+ private_cert_payload_t *this)
+{
+ int type;
+
+ switch (this->encoding)
+ {
+ case ENC_PKCS7_WRAPPED_X509:
+ type = CONTAINER_PKCS7;
+ break;
+ default:
+ return NULL;
+ }
+ return lib->creds->create(lib->creds, CRED_CONTAINER, type,
+ BUILD_BLOB_ASN1_DER, this->data, BUILD_END);
+}
+
METHOD(cert_payload_t, get_hash, chunk_t,
private_cert_payload_t *this)
{
@@ -289,6 +306,7 @@ cert_payload_t *cert_payload_create(payload_type_t type)
.destroy = _destroy,
},
.get_cert = _get_cert,
+ .get_container = _get_container,
.get_cert_encoding = _get_cert_encoding,
.get_hash = _get_hash,
.get_url = _get_url,
diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h
index 19ed2ccd2..834f35d60 100644
--- a/src/libcharon/encoding/payloads/cert_payload.h
+++ b/src/libcharon/encoding/payloads/cert_payload.h
@@ -28,10 +28,11 @@ typedef enum cert_encoding_t cert_encoding_t;
#include <library.h>
#include <credentials/certificates/certificate.h>
+#include <credentials/containers/container.h>
#include <encoding/payloads/payload.h>
/**
- * Certifcate encodings, as in RFC4306
+ * Certificate encodings, as in RFC4306
*/
enum cert_encoding_t {
ENC_PKCS7_WRAPPED_X509 = 1,
@@ -65,13 +66,20 @@ struct cert_payload_t {
payload_t payload_interface;
/**
- * Get the playoads encoded certifcate.
+ * Get the payloads encoded certificate.
*
- * @return certifcate copy
+ * @return certificate copy
*/
certificate_t *(*get_cert)(cert_payload_t *this);
/**
+ * Get the payloads certificate container.
+ *
+ * @return container copy
+ */
+ container_t *(*get_container)(cert_payload_t *this);
+
+ /**
* Get the encoding of the certificate.
*
* @return encoding
diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h
index cce71c0ad..2915decf3 100644
--- a/src/libcharon/encoding/payloads/certreq_payload.h
+++ b/src/libcharon/encoding/payloads/certreq_payload.h
@@ -56,7 +56,7 @@ struct certreq_payload_t {
/**
* Add a certificates keyid to the payload (IKEv2 only).
*
- * @param keyid keyid of the trusted certifcate
+ * @param keyid keyid of the trusted certificate
* @return
*/
void (*add_keyid)(certreq_payload_t *this, chunk_t keyid);
diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c
index dd2e25795..f2f35aa69 100644
--- a/src/libcharon/encoding/payloads/eap_payload.c
+++ b/src/libcharon/encoding/payloads/eap_payload.c
@@ -410,14 +410,15 @@ eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type,
eap_type_t reg_type;
u_int32_t reg_vendor;
bio_writer_t *writer;
- chunk_t length, data;
+ chunk_t data;
bool added_any = FALSE, found_vendor = FALSE;
eap_payload_t *payload;
writer = bio_writer_create(12);
writer->write_uint8(writer, EAP_RESPONSE);
writer->write_uint8(writer, identifier);
- length = writer->skip(writer, 2);
+ /* write zero length, we update it once we know the length */
+ writer->write_uint16(writer, 0);
write_type(writer, EAP_NAK, 0, expanded);
@@ -453,10 +454,9 @@ eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type,
/* set length */
data = writer->get_buf(writer);
- htoun16(length.ptr, data.len);
+ htoun16(data.ptr + offsetof(eap_packet_t, length), data.len);
payload = eap_payload_create_data(data);
writer->destroy(writer);
return payload;
}
-
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index 0ab94f2a7..112c32d41 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -443,7 +443,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
cfg = auth_cfg_create();
- /* add identity and peer certifcate */
+ /* add identity and peer certificate */
identity = identification_create_from_string(id);
if (cert)
{
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c
index d48484f09..43a0aaa36 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c
@@ -13,6 +13,28 @@
* for more details.
*/
+/*
+ * Copyright (C) 2013 Volker Rümelin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
#include "isakmp_cert_pre.h"
#include <daemon.h>
@@ -21,6 +43,7 @@
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/certreq_payload.h>
#include <credentials/certificates/x509.h>
+#include <credentials/containers/pkcs7.h>
typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t;
@@ -132,7 +155,106 @@ static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message
}
/**
- * Import receuved certificates
+ * Process an X509 certificate payload
+ */
+static void process_x509(cert_payload_t *payload, auth_cfg_t *auth, bool *first)
+{
+ certificate_t *cert;
+
+ cert = payload->get_cert(payload);
+ if (cert)
+ {
+ if (*first)
+ { /* the first is an end entity certificate */
+ DBG1(DBG_IKE, "received end entity cert \"%Y\"",
+ cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
+ *first = FALSE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received issuer cert \"%Y\"",
+ cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_IM_CERT, cert);
+ }
+ }
+}
+
+/**
+ * Process a CRL certificate payload
+ */
+static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
+{
+ certificate_t *cert;
+
+ cert = payload->get_cert(payload);
+ if (cert)
+ {
+ DBG1(DBG_IKE, "received CRL \"%Y\"", cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
+ }
+}
+
+/**
+ * Process a PKCS7 certificate payload
+ */
+static void process_pkcs7(cert_payload_t *payload, auth_cfg_t *auth)
+{
+ enumerator_t *enumerator;
+ container_t *container;
+ certificate_t *cert;
+ pkcs7_t *pkcs7;
+
+ container = payload->get_container(payload);
+ if (!container)
+ {
+ return;
+ }
+ switch (container->get_type(container))
+ {
+ case CONTAINER_PKCS7_DATA:
+ case CONTAINER_PKCS7_SIGNED_DATA:
+ case CONTAINER_PKCS7_ENVELOPED_DATA:
+ break;
+ default:
+ container->destroy(container);
+ return;
+ }
+
+ pkcs7 = (pkcs7_t *)container;
+ enumerator = pkcs7->create_cert_enumerator(pkcs7);
+ while (enumerator->enumerate(enumerator, &cert))
+ {
+ if (cert->get_type(cert) == CERT_X509)
+ {
+ x509_t *x509 = (x509_t*)cert;
+
+ if (x509->get_flags(x509) & X509_CA)
+ {
+ DBG1(DBG_IKE, "received issuer cert \"%Y\"",
+ cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_IM_CERT, cert->get_ref(cert));
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received end entity cert \"%Y\"",
+ cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert->get_ref(cert));
+ }
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received unsupported cert type %N",
+ certificate_type_names, cert->get_type(cert));
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ container->destroy(container);
+}
+
+/**
+ * Import received certificates
*/
static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
{
@@ -150,7 +272,6 @@ static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
{
cert_payload_t *cert_payload;
cert_encoding_t encoding;
- certificate_t *cert;
cert_payload = (cert_payload_t*)payload;
encoding = cert_payload->get_cert_encoding(cert_payload);
@@ -158,36 +279,14 @@ static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
switch (encoding)
{
case ENC_X509_SIGNATURE:
- {
- cert = cert_payload->get_cert(cert_payload);
- if (cert)
- {
- if (first)
- { /* the first is an end entity certificate */
- DBG1(DBG_IKE, "received end entity cert \"%Y\"",
- cert->get_subject(cert));
- auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
- first = FALSE;
- }
- else
- {
- DBG1(DBG_IKE, "received issuer cert \"%Y\"",
- cert->get_subject(cert));
- auth->add(auth, AUTH_HELPER_IM_CERT, cert);
- }
- }
+ process_x509(cert_payload, auth, &first);
break;
- }
case ENC_CRL:
- cert = cert_payload->get_cert(cert_payload);
- if (cert)
- {
- DBG1(DBG_IKE, "received CRL \"%Y\"",
- cert->get_subject(cert));
- auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
- }
+ process_crl(cert_payload, auth);
break;
case ENC_PKCS7_WRAPPED_X509:
+ process_pkcs7(cert_payload, auth);
+ break;
case ENC_PGP:
case ENC_DNS_SIGNED_KEY:
case ENC_KERBEROS_TOKEN:
diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
index 60e878777..2cbe8f8c5 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
@@ -57,6 +57,72 @@ struct private_ike_cert_pre_t {
};
/**
+ * Process a single certificate request payload
+ */
+static void process_certreq(private_ike_cert_pre_t *this,
+ certreq_payload_t *certreq, auth_cfg_t *auth)
+{
+ enumerator_t *enumerator;
+ u_int unknown = 0;
+ chunk_t keyid;
+
+ this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
+
+ if (certreq->get_cert_type(certreq) != CERT_X509)
+ {
+ DBG1(DBG_IKE, "cert payload %N not supported - ignored",
+ certificate_type_names, certreq->get_cert_type(certreq));
+ return;
+ }
+
+ enumerator = certreq->create_keyid_enumerator(certreq);
+ while (enumerator->enumerate(enumerator, &keyid))
+ {
+ identification_t *id;
+ certificate_t *cert;
+
+ id = identification_create_from_encoding(ID_KEY_ID, keyid);
+ cert = lib->credmgr->get_cert(lib->credmgr,
+ CERT_X509, KEY_ANY, id, TRUE);
+ if (cert)
+ {
+ DBG1(DBG_IKE, "received cert request for \"%Y\"",
+ cert->get_subject(cert));
+ auth->add(auth, AUTH_RULE_CA_CERT, cert);
+ }
+ else
+ {
+ DBG2(DBG_IKE, "received cert request for unknown ca with keyid %Y",
+ id);
+ unknown++;
+ }
+ id->destroy(id);
+ }
+ enumerator->destroy(enumerator);
+ if (unknown)
+ {
+ DBG1(DBG_IKE, "received %u cert requests for an unknown ca",
+ unknown);
+ }
+}
+
+/**
+ * Process a single notify payload
+ */
+static void process_notify(private_ike_cert_pre_t *this,
+ notify_payload_t *notify)
+{
+ switch (notify->get_notify_type(notify))
+ {
+ case HTTP_CERT_LOOKUP_SUPPORTED:
+ this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
* read certificate requests
*/
static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
@@ -73,62 +139,11 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
switch (payload->get_type(payload))
{
case CERTIFICATE_REQUEST:
- {
- certreq_payload_t *certreq = (certreq_payload_t*)payload;
- enumerator_t *enumerator;
- u_int unknown = 0;
- chunk_t keyid;
-
- this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
-
- if (certreq->get_cert_type(certreq) != CERT_X509)
- {
- DBG1(DBG_IKE, "cert payload %N not supported - ignored",
- certificate_type_names, certreq->get_cert_type(certreq));
- break;
- }
- enumerator = certreq->create_keyid_enumerator(certreq);
- while (enumerator->enumerate(enumerator, &keyid))
- {
- identification_t *id;
- certificate_t *cert;
-
- id = identification_create_from_encoding(ID_KEY_ID, keyid);
- cert = lib->credmgr->get_cert(lib->credmgr,
- CERT_X509, KEY_ANY, id, TRUE);
- if (cert)
- {
- DBG1(DBG_IKE, "received cert request for \"%Y\"",
- cert->get_subject(cert));
- auth->add(auth, AUTH_RULE_CA_CERT, cert);
- }
- else
- {
- DBG2(DBG_IKE, "received cert request for unknown ca "
- "with keyid %Y", id);
- unknown++;
- }
- id->destroy(id);
- }
- enumerator->destroy(enumerator);
- if (unknown)
- {
- DBG1(DBG_IKE, "received %u cert requests for an unknown ca",
- unknown);
- }
+ process_certreq(this, (certreq_payload_t*)payload, auth);
break;
- }
case NOTIFY:
- {
- notify_payload_t *notify = (notify_payload_t*)payload;
-
- /* we only handle one type of notify here */
- if (notify->get_notify_type(notify) == HTTP_CERT_LOOKUP_SUPPORTED)
- {
- this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
- }
+ process_notify(this, (notify_payload_t*)payload);
break;
- }
default:
/* ignore other payloads here, these are handled elsewhere */
break;
@@ -177,7 +192,75 @@ static certificate_t *try_get_cert(cert_payload_t *cert_payload)
}
/**
- * import certificates
+ * Process a X509 certificate payload
+ */
+static void process_x509(cert_payload_t *payload, auth_cfg_t *auth,
+ cert_encoding_t encoding, bool *first)
+{
+ certificate_t *cert;
+ char *url;
+
+ cert = try_get_cert(payload);
+ if (cert)
+ {
+ if (*first)
+ { /* the first is an end entity certificate */
+ DBG1(DBG_IKE, "received end entity cert \"%Y\"",
+ cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
+ *first = FALSE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received issuer cert \"%Y\"",
+ cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_IM_CERT, cert);
+ }
+ }
+ else if (encoding == ENC_X509_HASH_AND_URL)
+ {
+ /* we fetch the certificate not yet, but only if
+ * it is really needed during authentication */
+ url = payload->get_url(payload);
+ if (!url)
+ {
+ DBG1(DBG_IKE, "received invalid hash-and-url "
+ "encoded cert, ignore");
+ return;
+ }
+ url = strdup(url);
+ if (first)
+ { /* first URL is for an end entity certificate */
+ DBG1(DBG_IKE, "received hash-and-url for end entity cert \"%s\"",
+ url);
+ auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url);
+ first = FALSE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received hash-and-url for issuer cert \"%s\"", url);
+ auth->add(auth, AUTH_HELPER_IM_HASH_URL, url);
+ }
+ }
+}
+
+/**
+ * Process a CRL certificate payload
+ */
+static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
+{
+ certificate_t *cert;
+
+ cert = payload->get_cert(payload);
+ if (cert)
+ {
+ DBG1(DBG_IKE, "received CRL \"%Y\"", cert->get_subject(cert));
+ auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
+ }
+}
+
+/**
+ * Process certificate payloads
*/
static void process_certs(private_ike_cert_pre_t *this, message_t *message)
{
@@ -195,8 +278,6 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
{
cert_payload_t *cert_payload;
cert_encoding_t encoding;
- certificate_t *cert;
- char *url;
cert_payload = (cert_payload_t*)payload;
encoding = cert_payload->get_cert_encoding(cert_payload);
@@ -204,70 +285,18 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
switch (encoding)
{
case ENC_X509_HASH_AND_URL:
- {
if (!this->do_http_lookup)
{
- DBG1(DBG_IKE, "received hash-and-url encoded cert, but"
- " we don't accept them, ignore");
+ DBG1(DBG_IKE, "received hash-and-url encoded cert, but "
+ "we don't accept them, ignore");
break;
}
/* FALL */
- }
case ENC_X509_SIGNATURE:
- {
- cert = try_get_cert(cert_payload);
- if (cert)
- {
- if (first)
- { /* the first is an end entity certificate */
- DBG1(DBG_IKE, "received end entity cert \"%Y\"",
- cert->get_subject(cert));
- auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
- first = FALSE;
- }
- else
- {
- DBG1(DBG_IKE, "received issuer cert \"%Y\"",
- cert->get_subject(cert));
- auth->add(auth, AUTH_HELPER_IM_CERT, cert);
- }
- }
- else if (encoding == ENC_X509_HASH_AND_URL)
- {
- /* we fetch the certificate not yet, but only if
- * it is really needed during authentication */
- url = cert_payload->get_url(cert_payload);
- if (!url)
- {
- DBG1(DBG_IKE, "received invalid hash-and-url "
- "encoded cert, ignore");
- break;
- }
- url = strdup(url);
- if (first)
- { /* first URL is for an end entity certificate */
- DBG1(DBG_IKE, "received hash-and-url for end"
- " entity cert \"%s\"", url);
- auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url);
- first = FALSE;
- }
- else
- {
- DBG1(DBG_IKE, "received hash-and-url for issuer"
- " cert \"%s\"", url);
- auth->add(auth, AUTH_HELPER_IM_HASH_URL, url);
- }
- }
+ process_x509(cert_payload, auth, encoding, &first);
break;
- }
case ENC_CRL:
- cert = cert_payload->get_cert(cert_payload);
- if (cert)
- {
- DBG1(DBG_IKE, "received CRL \"%Y\"",
- cert->get_subject(cert));
- auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
- }
+ process_crl(cert_payload, auth);
break;
case ENC_PKCS7_WRAPPED_X509:
case ENC_PGP:
diff --git a/src/libimcv/imv/imv_msg.c b/src/libimcv/imv/imv_msg.c
index 81209ce57..4ed19dd13 100644
--- a/src/libimcv/imv/imv_msg.c
+++ b/src/libimcv/imv/imv_msg.c
@@ -195,6 +195,12 @@ METHOD(imv_msg_t, send_assessment, TNC_Result,
char *lang_code = NULL, *uri = NULL;
enumerator_t *e;
+ /* Remove any attributes that have already been constructed */
+ while (this->attr_list->remove_last(this->attr_list, (void**)&attr) == SUCCESS)
+ {
+ attr->destroy(attr);
+ }
+
/* Send an IETF Assessment Result attribute if enabled */
if (lib->settings->get_bool(lib->settings, "libimcv.assessment_result",
TRUE))
@@ -306,17 +312,6 @@ METHOD(imv_msg_t, receive, TNC_Result,
return TNC_RESULT_SUCCESS;
}
-METHOD(imv_msg_t, delete_attributes, void,
- private_imv_msg_t *this)
-{
- pa_tnc_attr_t *attr;
-
- while (this->attr_list->remove_last(this->attr_list, (void**)&attr) == SUCCESS)
- {
- attr->destroy(attr);
- }
-}
-
METHOD(imv_msg_t, create_attribute_enumerator, enumerator_t*,
private_imv_msg_t *this)
{
@@ -361,7 +356,6 @@ imv_msg_t *imv_msg_create(imv_agent_t *agent, imv_state_t *state,
.send_assessment = _send_assessment,
.receive = _receive,
.add_attribute = _add_attribute,
- .delete_attributes = _delete_attributes,
.create_attribute_enumerator = _create_attribute_enumerator,
.get_encoding = _get_encoding,
.destroy = _destroy,
diff --git a/src/libimcv/imv/imv_msg.h b/src/libimcv/imv/imv_msg.h
index 92347934f..b639712e8 100644
--- a/src/libimcv/imv/imv_msg.h
+++ b/src/libimcv/imv/imv_msg.h
@@ -85,12 +85,6 @@ struct imv_msg_t {
void (*add_attribute)(imv_msg_t *this, pa_tnc_attr_t *attr);
/**
- * Delete all PA-TNC attributes in the send queue
- *
- */
- void (*delete_attributes)(imv_msg_t *this);
-
- /**
* Enumerator over PA-TNC attributes contained in the PA-TNC message
*
* @return PA-TNC attribute enumerator
diff --git a/src/libimcv/plugins/imv_os/pacman.sh b/src/libimcv/plugins/imv_os/pacman.sh
index a17a0839a..e9134ea5d 100755
--- a/src/libimcv/plugins/imv_os/pacman.sh
+++ b/src/libimcv/plugins/imv_os/pacman.sh
@@ -5,6 +5,10 @@ DEBIAN=http://packages.debian.org
UBUNTU=http://packages.ubuntu.com
UBUNTU_VERSIONS="quantal precise oneiric lucid"
PACKAGES=allpackages?format=txt.gz
+PACMAN=/usr/libexec/ipsec/pacman
+DIR=/etc/pts
+
+cd $DIR
for v in $UBUNTU_VERSIONS
do
@@ -15,22 +19,22 @@ done
wget $DEBIAN/stable/$PACKAGES -O $DATE-squeeze.txt.gz
gunzip *.gz
-ipsec pacman --product "Ubuntu 12.10" --file $DATE-quantal.txt
+$PACMAN --product "Ubuntu 12.10" --file $DATE-quantal.txt
echo
-ipsec pacman --product "Ubuntu 12.10" --file $DATE-quantal-updates.txt --update
+$PACMAN --product "Ubuntu 12.10" --file $DATE-quantal-updates.txt --update
echo
-ipsec pacman --product "Ubuntu 12.04" --file $DATE-precise.txt
+$PACMAN --product "Ubuntu 12.04" --file $DATE-precise.txt
echo
-ipsec pacman --product "Ubuntu 12.04" --file $DATE-precise-updates.txt --update
+$PACMAN --product "Ubuntu 12.04" --file $DATE-precise-updates.txt --update
echo
-ipsec pacman --product "Ubuntu 11.10" --file $DATE-oneiric.txt
+$PACMAN --product "Ubuntu 11.10" --file $DATE-oneiric.txt
echo
-ipsec pacman --product "Ubuntu 11.10" --file $DATE-oneiric-updates.txt --update
+$PACMAN --product "Ubuntu 11.10" --file $DATE-oneiric-updates.txt --update
echo
-ipsec pacman --product "Ubuntu 10.04" --file $DATE-lucid.txt
+$PACMAN --product "Ubuntu 10.04" --file $DATE-lucid.txt
echo
-ipsec pacman --product "Ubuntu 10.04" --file $DATE-lucid-updates.txt --update
+$PACMAN --product "Ubuntu 10.04" --file $DATE-lucid-updates.txt --update
echo
-ipsec pacman --product "Debian squeeze" --file $DATE-squeeze.txt
+$PACMAN --product "Debian squeeze" --file $DATE-squeeze.txt
cp config.db config.db-$DATE
diff --git a/src/libpts/plugins/imv_attestation/imv_attestation.c b/src/libpts/plugins/imv_attestation/imv_attestation.c
index 237300f31..3c5488eba 100644
--- a/src/libpts/plugins/imv_attestation/imv_attestation.c
+++ b/src/libpts/plugins/imv_attestation/imv_attestation.c
@@ -285,9 +285,8 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
if (fatal_error || result != TNC_RESULT_SUCCESS)
{
- out_msg->delete_attributes(out_msg);
state->set_recommendation(state,
- TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
@@ -315,7 +314,6 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
- out_msg->delete_attributes(out_msg);
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
if (result != TNC_RESULT_SUCCESS)
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index 243ff5504..9c4665eeb 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -204,6 +204,13 @@ if MONOLITHIC
endif
endif
+if USE_RDRAND
+ SUBDIRS += plugins/rdrand
+if MONOLITHIC
+ libstrongswan_la_LIBADD += plugins/rdrand/libstrongswan-rdrand.la
+endif
+endif
+
if USE_RANDOM
SUBDIRS += plugins/random
if MONOLITHIC
diff --git a/src/libstrongswan/bio/bio_writer.h b/src/libstrongswan/bio/bio_writer.h
index 57a5c3d38..2ac4f3556 100644
--- a/src/libstrongswan/bio/bio_writer.h
+++ b/src/libstrongswan/bio/bio_writer.h
@@ -126,8 +126,11 @@ struct bio_writer_t {
void (*wrap32)(bio_writer_t *this);
/**
- * Skips len bytes in the buffer before the next data is written, returns
- * a chunk covering the skipped bytes.
+ * Skips len bytes in the buffer, return chunk of skipped data.
+ *
+ * The returned chunk is not valid after calling any other writer function
+ * (except get_buf()), because a buffer reallocation might move the
+ * internal buffer to a different memory location!
*
* @param len number of bytes to skip
* @return chunk pointing to skipped bytes in the internal buffer
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
index 6cd243c61..663397e59 100644
--- a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
@@ -13,6 +13,10 @@
* for more details.
*/
+#include <openssl/opensslconf.h>
+
+#ifndef OPENSSL_NO_CMS
+
#include "openssl_pkcs7.h"
#include "openssl_util.h"
@@ -782,3 +786,5 @@ pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args)
}
return NULL;
}
+
+#endif /* OPENSSL_NO_CMS */
diff --git a/src/libstrongswan/plugins/rdrand/Makefile.am b/src/libstrongswan/plugins/rdrand/Makefile.am
new file mode 100644
index 000000000..4be7b7215
--- /dev/null
+++ b/src/libstrongswan/plugins/rdrand/Makefile.am
@@ -0,0 +1,16 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-rdrand.la
+else
+plugin_LTLIBRARIES = libstrongswan-rdrand.la
+endif
+
+libstrongswan_rdrand_la_SOURCES = \
+ rdrand_plugin.h rdrand_plugin.c \
+ rdrand_rng.h rdrand_rng.c
+
+libstrongswan_rdrand_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/rdrand/rdrand_plugin.c b/src/libstrongswan/plugins/rdrand/rdrand_plugin.c
new file mode 100644
index 000000000..4bdfc258e
--- /dev/null
+++ b/src/libstrongswan/plugins/rdrand/rdrand_plugin.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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.
+ */
+
+#include "rdrand_plugin.h"
+#include "rdrand_rng.h"
+
+#include <stdio.h>
+
+#include <library.h>
+#include <utils/debug.h>
+
+typedef struct private_rdrand_plugin_t private_rdrand_plugin_t;
+typedef enum cpuid_feature_t cpuid_feature_t;
+
+/**
+ * private data of rdrand_plugin
+ */
+struct private_rdrand_plugin_t {
+
+ /**
+ * public functions
+ */
+ rdrand_plugin_t public;
+};
+
+/**
+ * CPU feature flags, returned via cpuid(1)
+ */
+enum cpuid_feature_t {
+ CPUID_RDRAND = (1<<30),
+};
+
+/**
+ * Get cpuid for info, return eax, ebx, ecx and edx.
+ * -fPIC requires to save ebx on IA-32.
+ */
+static void cpuid(u_int op, u_int *a, u_int *b, u_int *c, u_int *d)
+{
+#ifdef __x86_64__
+ asm("cpuid" : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d) : "a" (op));
+#else /* __i386__ */
+ asm("pushl %%ebx;"
+ "cpuid;"
+ "movl %%ebx, %1;"
+ "popl %%ebx;"
+ : "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d) : "a" (op));
+#endif /* __x86_64__ / __i386__*/
+}
+
+/**
+ * Check if we have RDRAND instruction
+ */
+static bool have_rdrand()
+{
+ char vendor[3 * sizeof(u_int32_t) + 1];
+ u_int a, b, c, d;
+
+ cpuid(0, &a, &b, &c, &d);
+ /* VendorID string is in b-d-c (yes, in this order) */
+ snprintf(vendor, sizeof(vendor), "%.4s%.4s%.4s", &b, &d, &c);
+
+ /* check if we have an Intel CPU */
+ if (streq(vendor, "GenuineIntel"))
+ {
+ cpuid(1, &a, &b, &c, &d);
+ if (c & CPUID_RDRAND)
+ {
+ DBG1(DBG_LIB, "detected RDRAND support on %s CPU", vendor);
+ return TRUE;
+ }
+ }
+ DBG1(DBG_LIB, "no RDRAND support on %s CPU, disabled", vendor);
+ return FALSE;
+}
+
+METHOD(plugin_t, get_name, char*,
+ private_rdrand_plugin_t *this)
+{
+ return "rdrand";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_rdrand_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_REGISTER(RNG, rdrand_rng_create),
+ PLUGIN_PROVIDE(RNG, RNG_WEAK),
+ PLUGIN_PROVIDE(RNG, RNG_STRONG),
+ PLUGIN_PROVIDE(RNG, RNG_TRUE),
+ PLUGIN_DEPENDS(CRYPTER, ENCR_AES_CBC, 16),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_rdrand_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *rdrand_plugin_create()
+{
+ private_rdrand_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .reload = (void*)return_false,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ if (have_rdrand())
+ {
+ this->public.plugin.get_features = _get_features;
+ }
+
+ return &this->public.plugin;
+}
diff --git a/src/libstrongswan/plugins/rdrand/rdrand_plugin.h b/src/libstrongswan/plugins/rdrand/rdrand_plugin.h
new file mode 100644
index 000000000..6f0e55313
--- /dev/null
+++ b/src/libstrongswan/plugins/rdrand/rdrand_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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 rdrand_p rdrand
+ * @ingroup plugins
+ *
+ * @defgroup rdrand_plugin rdrand_plugin
+ * @{ @ingroup rdrand_p
+ */
+
+#ifndef RDRAND_PLUGIN_H_
+#define RDRAND_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct rdrand_plugin_t rdrand_plugin_t;
+
+/**
+ * Plugin providing random generators based on Intels RDRAND instruction.
+ */
+struct rdrand_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** RDRAND_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/plugins/rdrand/rdrand_rng.c b/src/libstrongswan/plugins/rdrand/rdrand_rng.c
new file mode 100644
index 000000000..d032cbe31
--- /dev/null
+++ b/src/libstrongswan/plugins/rdrand/rdrand_rng.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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.
+ */
+
+#include "rdrand_rng.h"
+
+#include <unistd.h>
+
+typedef struct private_rdrand_rng_t private_rdrand_rng_t;
+
+/**
+ * Private data of an rdrand_rng_t object.
+ */
+struct private_rdrand_rng_t {
+
+ /**
+ * Public rdrand_rng_t interface.
+ */
+ rdrand_rng_t public;
+
+ /**
+ * Quality we produce RNG data
+ */
+ rng_quality_t quality;
+};
+
+/**
+ * Retries for failed RDRAND instructions
+ */
+#define MAX_TRIES 16
+
+/**
+ * After how many bytes should we reseed for RNG_STRONG
+ * (must be a power of two >= 8)
+ */
+#define FORCE_RESEED 16
+
+/**
+ * How many times we mix reseeded RDRAND output when using RNG_TRUE
+ */
+#define MIX_ROUNDS 32
+
+/**
+ * Get a two byte word using RDRAND
+ */
+static bool rdrand16(u_int16_t *out)
+{
+ u_char res;
+ int i;
+
+ for (i = 0; i < MAX_TRIES; i++)
+ {
+ asm(".byte 0x66;.byte 0x0f;.byte 0xc7;.byte 0xf0; " /* rdrand */
+ "setc %1;"
+ : "=a"(*out), "=qm"(res));
+
+ if (res)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Get a four byte word using RDRAND
+ */
+static bool rdrand32(u_int32_t *out)
+{
+ u_char res;
+ int i;
+
+ for (i = 0; i < MAX_TRIES; i++)
+ {
+ asm(".byte 0x0f;.byte 0xc7;.byte 0xf0;" /* rdrand */
+ "setc %1;"
+ : "=a"(*out), "=qm"(res));
+
+ if (res)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+#ifdef __x86_64__
+/**
+ * Get a eight byte word using RDRAND
+ */
+static bool rdrand64(u_int64_t *out)
+{
+ u_char res;
+ int i;
+
+ for (i = 0; i < MAX_TRIES; i++)
+ {
+ asm(".byte 0x48;.byte 0x0f;.byte 0xc7;.byte 0xf0;" /* rdrand */
+ "setc %1;"
+ : "=a"(*out), "=qm"(res));
+
+ if (res)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+#endif /* __x86_64__ */
+
+/**
+ * Get a one byte word using RDRAND
+ */
+static bool rdrand8(u_int8_t *out)
+{
+ u_int16_t u16;
+
+ if (!rdrand16(&u16))
+ {
+ return FALSE;
+ }
+ *out = u16;
+ return TRUE;
+}
+
+/**
+ * Get a 16 byte word using RDRAND
+ */
+static bool rdrand128(void *out)
+{
+#ifdef __x86_64__
+ if (!rdrand64(out) ||
+ !rdrand64(out + sizeof(u_int64_t)))
+ {
+ return FALSE;
+ }
+#else /* __i386__ */
+ if (!rdrand32(out) ||
+ !rdrand32(out + 1 * sizeof(u_int32_t)) ||
+ !rdrand32(out + 2 * sizeof(u_int32_t)) ||
+ !rdrand32(out + 3 * sizeof(u_int32_t)))
+ {
+ return FALSE;
+ }
+#endif /* __x86_64__ / __i386__ */
+ return TRUE;
+}
+
+/**
+ * Enforce a DRNG reseed by reading 511 128-bit samples
+ */
+static bool reseed()
+{
+ int i;
+
+#ifdef __x86_64__
+ u_int64_t tmp;
+
+ for (i = 0; i < 511 * 16 / sizeof(u_int64_t); i++)
+ {
+ if (!rdrand64(&tmp))
+ {
+ return FALSE;
+ }
+ }
+#else /* __i386__ */
+ u_int32_t tmp;
+
+ for (i = 0; i < 511 * 16 / sizeof(u_int32_t); i++)
+ {
+ if (!rdrand32(&tmp))
+ {
+ return FALSE;
+ }
+ }
+#endif /* __x86_64__ / __i386__ */
+ return TRUE;
+}
+
+/**
+ * Fill a preallocated chunk of data with random bytes
+ */
+static bool rdrand_chunk(private_rdrand_rng_t *this, chunk_t chunk)
+{
+ if (this->quality == RNG_STRONG)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
+
+ /* align to 2 byte */
+ if (chunk.len >= sizeof(u_int8_t))
+ {
+ if ((uintptr_t)chunk.ptr % 2)
+ {
+ if (!rdrand8((u_int8_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int8_t));
+ }
+ }
+
+ /* align to 4 byte */
+ if (chunk.len >= sizeof(u_int16_t))
+ {
+ if ((uintptr_t)chunk.ptr % 4)
+ {
+ if (!rdrand16((u_int16_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int16_t));
+ }
+ }
+
+#ifdef __x86_64__
+
+ /* align to 8 byte */
+ if (chunk.len >= sizeof(u_int32_t))
+ {
+ if ((uintptr_t)chunk.ptr % 8)
+ {
+ if (!rdrand32((u_int32_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int32_t));
+ }
+ }
+
+ /* fill with 8 byte words */
+ while (chunk.len >= sizeof(u_int64_t))
+ {
+ if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
+ if (!rdrand64((u_int64_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int64_t));
+ }
+
+ /* append 4 byte word */
+ if (chunk.len >= sizeof(u_int32_t))
+ {
+ if (!rdrand32((u_int32_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int32_t));
+ }
+
+#else /* __i386__ */
+
+ /* fill with 4 byte words */
+ while (chunk.len >= sizeof(u_int32_t))
+ {
+ if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
+ if (!rdrand32((u_int32_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int32_t));
+ }
+
+#endif /* __x86_64__ / __i386__ */
+
+ if (this->quality == RNG_STRONG)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
+
+ /* append 2 byte word */
+ if (chunk.len >= sizeof(u_int16_t))
+ {
+ if (!rdrand16((u_int16_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int16_t));
+ }
+
+ /* append 1 byte word */
+ if (chunk.len >= sizeof(u_int8_t))
+ {
+ if (!rdrand8((u_int8_t*)chunk.ptr))
+ {
+ return FALSE;
+ }
+ chunk = chunk_skip(chunk, sizeof(u_int8_t));
+ }
+
+ return TRUE;
+}
+
+/**
+ * Stronger variant mixing reseeded results of rdrand output
+ *
+ * This is based on the Intel DRNG "Software Implementation Guide", using
+ * AES-CBC to mix several reseeded RDRAND outputs.
+ */
+static bool rdrand_mixed(private_rdrand_rng_t *this, chunk_t chunk)
+{
+ u_char block[16], forward[16], key[16], iv[16];
+ crypter_t *crypter;
+ int i, len;
+
+ memset(iv, 0, sizeof(iv));
+ crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16);
+ if (!crypter)
+ {
+ return FALSE;
+ }
+ for (i = 0; i < sizeof(key); i++)
+ {
+ key[i] = i;
+ }
+ if (!crypter->set_key(crypter, chunk_from_thing(key)))
+ {
+ crypter->destroy(crypter);
+ return FALSE;
+ }
+ while (chunk.len > 0)
+ {
+ memset(forward, 0, sizeof(forward));
+ for (i = 0; i < MIX_ROUNDS; i++)
+ {
+ /* sleep to reseed PRNG */
+ usleep(10);
+ if (!rdrand128(block))
+ {
+ crypter->destroy(crypter);
+ return FALSE;
+ }
+ memxor(forward, block, sizeof(block));
+ if (!crypter->encrypt(crypter, chunk_from_thing(forward),
+ chunk_from_thing(iv), NULL))
+ {
+ crypter->destroy(crypter);
+ return FALSE;
+ }
+ }
+ len = min(chunk.len, sizeof(forward));
+ memcpy(chunk.ptr, forward, len);
+ chunk = chunk_skip(chunk, len);
+ }
+ crypter->destroy(crypter);
+
+ return TRUE;
+}
+
+METHOD(rng_t, get_bytes, bool,
+ private_rdrand_rng_t *this, size_t bytes, u_int8_t *buffer)
+{
+ switch (this->quality)
+ {
+ case RNG_WEAK:
+ case RNG_STRONG:
+ return rdrand_chunk(this, chunk_create(buffer, bytes));
+ case RNG_TRUE:
+ return rdrand_mixed(this, chunk_create(buffer, bytes));
+ default:
+ return FALSE;
+ }
+}
+
+METHOD(rng_t, allocate_bytes, bool,
+ private_rdrand_rng_t *this, size_t bytes, chunk_t *chunk)
+{
+ *chunk = chunk_alloc(bytes);
+ if (get_bytes(this, bytes, chunk->ptr))
+ {
+ return TRUE;
+ }
+ free(chunk->ptr);
+ return FALSE;
+}
+
+METHOD(rng_t, destroy, void,
+ private_rdrand_rng_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+rdrand_rng_t *rdrand_rng_create(rng_quality_t quality)
+{
+ private_rdrand_rng_t *this;
+
+ switch (quality)
+ {
+ case RNG_WEAK:
+ case RNG_STRONG:
+ case RNG_TRUE:
+ break;
+ default:
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .rng = {
+ .get_bytes = _get_bytes,
+ .allocate_bytes = _allocate_bytes,
+ .destroy = _destroy,
+ },
+ },
+ .quality = quality,
+ );
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/plugins/rdrand/rdrand_rng.h b/src/libstrongswan/plugins/rdrand/rdrand_rng.h
new file mode 100644
index 000000000..d15a48224
--- /dev/null
+++ b/src/libstrongswan/plugins/rdrand/rdrand_rng.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
+ *
+ * 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 rdrand_rng rdrand_rng
+ * @{ @ingroup rdrand
+ */
+
+#ifndef RDRAND_RNG_H_
+#define RDRAND_RNG_H_
+
+#include <crypto/rngs/rng.h>
+
+typedef struct rdrand_rng_t rdrand_rng_t;
+
+/**
+ * RNG implemented with Intels RDRAND instructions, introduced in Ivy Bridge.
+ */
+struct rdrand_rng_t {
+
+ /**
+ * Implements rng_t interface.
+ */
+ rng_t rng;
+};
+
+/**
+ * Create a rdrand_rng instance.
+ *
+ * @param quality RNG quality
+ * @return RNG instance
+ */
+rdrand_rng_t *rdrand_rng_create(rng_quality_t quality);
+
+#endif /** RDRAND_RNG_H_ @}*/