Merge branch 'android-byod'

Adds support for EAP-TNC with a custom Android-specific IMC that
collects data such as installed packages, file hashes or system
settings.

Some parts of the implementation are based on the bachelor semester
project 'strongSwan Android 4 Client with Endpoint Assessment' by
Christoph Bühler and Patrick Lötscher.
This commit is contained in:
Tobias Brunner
2013-07-08 18:50:09 +02:00
86 changed files with 4227 additions and 117 deletions
+5 -1
View File
@@ -37,4 +37,8 @@ apidoc/
coverage/
*.gcno
*.gcda
*.gcov
*.gcov
.cproject
.project
.metadata/
.settings/
+11
View File
@@ -13,6 +13,17 @@ add_plugin = $(if $(call plugin_enabled,$(1)), \
) \
) \
)
add_plugin_subdirs = $(if $(call plugin_enabled,$(1)), \
$(patsubst $(LOCAL_PATH)/%,%, \
$(wildcard \
$(subst %,$(subst -,_,$(strip $(1))), \
$(addprefix $(LOCAL_PATH)/plugins/%/,$(addsuffix /*.c, \
$(strip $(2)) \
)) \
) \
) \
) \
)
# strongSwan version, replaced by top Makefile
strongswan_VERSION := "@PACKAGE_VERSION@"
+2 -1
View File
@@ -100,7 +100,8 @@ strongswan_BUILD := \
libhydra \
libstrongswan \
libtncif \
libtnccs
libtnccs \
libimcv
ifneq ($(strongswan_BUILD_STARTER),)
strongswan_BUILD += \
@@ -54,6 +54,10 @@
android:name=".ui.LogActivity"
android:label="@string/log_title" >
</activity>
<activity
android:name=".ui.RemediationInstructionsActivity"
android:label="@string/remediation_instructions_title" >
</activity>
<activity
android:name=".ui.VpnProfileSelectActivity"
android:label="@string/strongswan_shortcut" >
+32 -9
View File
@@ -1,11 +1,20 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# use "bring your own device" (BYOD) features (also see USE_BYOD in
# MainActivity.java)
strongswan_USE_BYOD := true
strongswan_CHARON_PLUGINS := android-log openssl fips-prf random nonce pubkey \
pkcs1 pkcs8 pem xcbc hmac socket-default kernel-netlink \
eap-identity eap-mschapv2 eap-md5 eap-gtc
strongswan_PLUGINS := $(strongswan_CHARON_PLUGINS)
ifneq ($(strongswan_USE_BYOD),)
strongswan_BYOD_PLUGINS := eap-ttls eap-tnc tnc-imc tnc-tnccs tnccs-20
endif
strongswan_PLUGINS := $(strongswan_CHARON_PLUGINS) \
$(strongswan_BYOD_PLUGINS)
include $(LOCAL_PATH)/strongswan/Android.common.mk
@@ -52,12 +61,26 @@ strongswan_CFLAGS := \
-DDEV_RANDOM=\"/dev/random\" \
-DDEV_URANDOM=\"/dev/urandom\"
ifneq ($(strongswan_USE_BYOD),)
strongswan_CFLAGS += -DUSE_BYOD
endif
strongswan_BUILD := \
vstr \
openssl \
libandroidbridge \
strongswan/src/libipsec \
strongswan/src/libcharon \
strongswan/src/libhydra \
strongswan/src/libstrongswan
ifneq ($(strongswan_USE_BYOD),)
strongswan_BUILD += \
strongswan/src/libtnccs \
strongswan/src/libtncif \
strongswan/src/libimcv \
strongswan/src/libpts
endif
include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
vstr \
openssl \
libandroidbridge \
strongswan/src/libipsec \
strongswan/src/libcharon \
strongswan/src/libhydra \
strongswan/src/libstrongswan \
))
$(strongswan_BUILD)))
@@ -14,6 +14,12 @@ kernel/android_net.c \
kernel/network_manager.c \
vpnservice_builder.c
ifneq ($(strongswan_USE_BYOD),)
LOCAL_SRC_FILES += \
byod/imc_android_state.c \
byod/imc_android.c
endif
# build libandroidbridge -------------------------------------------------------
LOCAL_C_INCLUDES += \
@@ -23,9 +29,22 @@ LOCAL_C_INCLUDES += \
$(strongswan_PATH)/src/libcharon \
$(strongswan_PATH)/src/libstrongswan
ifneq ($(strongswan_USE_BYOD),)
LOCAL_C_INCLUDES += \
$(strongswan_PATH)/src/libimcv \
$(strongswan_PATH)/src/libtncif \
$(strongswan_PATH)/src/libtnccs \
$(strongswan_PATH)/src/libpts \
$(strongswan_PATH)/src/libtls
endif
LOCAL_CFLAGS := $(strongswan_CFLAGS) \
-DPLUGINS='"$(strongswan_CHARON_PLUGINS)"'
ifneq ($(strongswan_USE_BYOD),)
LOCAL_CFLAGS += -DPLUGINS_BYOD='"$(strongswan_BYOD_PLUGINS)"'
endif
LOCAL_MODULE := libandroidbridge
LOCAL_MODULE_TAGS := optional
@@ -38,6 +57,8 @@ LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := libstrongswan libhydra libipsec libcharon
ifneq ($(strongswan_USE_BYOD),)
LOCAL_SHARED_LIBRARIES += libimcv libtncif libtnccs libpts
endif
include $(BUILD_SHARED_LIBRARY)
@@ -464,13 +464,18 @@ METHOD(listener_t, ike_reestablish, bool,
}
static void add_auth_cfg_eap(private_android_service_t *this,
peer_cfg_t *peer_cfg)
peer_cfg_t *peer_cfg, bool byod)
{
identification_t *user;
auth_cfg_t *auth;
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
if (byod)
{ /* use EAP-TTLS if BYOD is enabled */
auth->add(auth, AUTH_RULE_EAP_TYPE, EAP_TTLS);
}
user = identification_create_from_string(this->username);
auth->add(auth, AUTH_RULE_IDENTITY, user);
@@ -549,9 +554,10 @@ static job_requeue_t initiate(private_android_service_t *this)
}
}
if (streq("ikev2-eap", this->type) ||
streq("ikev2-cert-eap", this->type))
streq("ikev2-cert-eap", this->type) ||
streq("ikev2-byod-eap", this->type))
{
add_auth_cfg_eap(this, peer_cfg);
add_auth_cfg_eap(this, peer_cfg, strpfx(this->type, "ikev2-byod"));
}
/* remote auth config */
@@ -0,0 +1,725 @@
/*
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Copyright (C) 2011-2012 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.
*/
#include "imc_android_state.h"
#include "../android_jni.h"
#include "../charonservice.h"
#include <tnc/tnc.h>
#include <libpts.h>
#include <imcv.h>
#include <imc/imc_agent.h>
#include <imc/imc_msg.h>
#include <pa_tnc/pa_tnc_msg.h>
#include <ietf/ietf_attr.h>
#include <ietf/ietf_attr_attr_request.h>
#include <ietf/ietf_attr_installed_packages.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <ietf/ietf_attr_product_info.h>
#include <ietf/ietf_attr_remediation_instr.h>
#include <ietf/ietf_attr_string_version.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_get_settings.h>
#include <tcg/tcg_pts_attr_file_meas.h>
#include <tcg/tcg_pts_attr_meas_algo.h>
#include <tcg/tcg_pts_attr_proto_caps.h>
#include <tcg/tcg_pts_attr_req_file_meas.h>
#include <os_info/os_info.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <stdio.h>
/* IMC definitions */
static const char imc_name[] = "Android";
static pen_type_t msg_types[] = {
{ PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM },
{ PEN_IETF, PA_SUBTYPE_IETF_VPN },
{ PEN_TCG, PA_SUBTYPE_TCG_PTS },
};
static imc_agent_t *imc_android;
/**
* AndroidImc object accessed via JNI
*/
static jobject android_imc;
/**
* AndroidImc class object
*/
static jclass android_imc_cls;
/**
* see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_initialize(TNC_IMCID imc_id,
TNC_Version min_version,
TNC_Version max_version,
TNC_Version *actual_version)
{
if (imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
return TNC_RESULT_ALREADY_INITIALIZED;
}
imc_android = imc_agent_create(imc_name, msg_types, countof(msg_types),
imc_id, actual_version);
if (!imc_android)
{
return TNC_RESULT_FATAL;
}
libpts_init();
if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
{
DBG1(DBG_IMC, "no common IF-IMC version");
return TNC_RESULT_NO_COMMON_VERSION;
}
return TNC_RESULT_SUCCESS;
}
/**
* Update the state in the GUI.
*/
static void update_imc_state(TNC_ConnectionState state)
{
android_imc_state_t imc_state = ANDROID_IMC_STATE_UNKNOWN;
switch (state)
{ /* map connection states to the values used by the GUI */
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
imc_state = ANDROID_IMC_STATE_ALLOW;
break;
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
imc_state = ANDROID_IMC_STATE_ISOLATE;
break;
case TNC_CONNECTION_STATE_ACCESS_NONE:
imc_state = ANDROID_IMC_STATE_BLOCK;
break;
}
charonservice->update_imc_state(charonservice, imc_state);
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_notifyconnectionchange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imc_state_t *state;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imc_android_state_create(connection_id);
return imc_android->create_state(imc_android, state);
case TNC_CONNECTION_STATE_HANDSHAKE:
if (imc_android->change_state(imc_android, connection_id, new_state,
&state) != TNC_RESULT_SUCCESS)
{
return TNC_RESULT_FATAL;
}
state->set_result(state, imc_id,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_android->delete_state(imc_android, connection_id);
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
update_imc_state(new_state);
/* fall-through */
default:
return imc_android->change_state(imc_android, connection_id,
new_state, NULL);
}
}
/**
* Convert the native C strings in the enumerator to a Java String array.
* The given enumerator gets destroyed.
*/
static jobjectArray string_array_create(JNIEnv *env, enumerator_t *enumerator)
{
linked_list_t *list;
jobjectArray jarray;
jstring jstring;
char *native;
jclass cls;
int i = 0;
cls = (*env)->FindClass(env, "java/lang/String");
list = linked_list_create_from_enumerator(enumerator);
jarray = (*env)->NewObjectArray(env, list->get_count(list), cls, NULL);
if (!jarray)
{
goto failed;
}
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, (void**)&native))
{
jstring = (*env)->NewStringUTF(env, native);
if (!jstring)
{
enumerator->destroy(enumerator);
goto failed;
}
(*env)->SetObjectArrayElement(env, jarray, i++, jstring);
}
enumerator->destroy(enumerator);
list->destroy(list);
return jarray;
failed:
androidjni_exception_occurred(env);
list->destroy(list);
return NULL;
}
/**
* Get a measurement for the given attribute type from the Android IMC.
* NULL is returned if no measurement is available or an error occurred.
*
* The optional args is an enumerator over char* (gets destroyed).
*/
static pa_tnc_attr_t *get_measurement(pen_type_t attr_type, enumerator_t *args)
{
JNIEnv *env;
pa_tnc_attr_t *attr;
jmethodID method_id;
jbyteArray jmeasurement;
jobjectArray jargs = NULL;
chunk_t data;
androidjni_attach_thread(&env);
if (args)
{
jargs = string_array_create(env, args);
if (!jargs)
{
goto failed;
}
method_id = (*env)->GetMethodID(env, android_imc_cls, "getMeasurement",
"(II[Ljava/lang/String;)[B");
}
else
{
method_id = (*env)->GetMethodID(env, android_imc_cls, "getMeasurement",
"(II)[B");
}
if (!method_id)
{
goto failed;
}
jmeasurement = (*env)->CallObjectMethod(env, android_imc, method_id,
attr_type.vendor_id, attr_type.type,
jargs);
if (!jmeasurement || androidjni_exception_occurred(env))
{
goto failed;
}
data = chunk_create((*env)->GetByteArrayElements(env, jmeasurement, NULL),
(*env)->GetArrayLength(env, jmeasurement));
if (!data.ptr)
{
goto failed;
}
attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
attr_type.vendor_id, attr_type.type,
data);
(*env)->ReleaseByteArrayElements(env, jmeasurement, data.ptr, JNI_ABORT);
androidjni_detach_thread();
return attr;
failed:
androidjni_exception_occurred(env);
androidjni_detach_thread();
return NULL;
}
/**
* Add the measurement for the requested attribute type with optional
* arguments (enumerator over char*, gets destroyed).
*/
static void add_measurement(pen_type_t attr_type, imc_msg_t *msg,
enumerator_t *args)
{
pa_tnc_attr_t *attr;
enum_name_t *pa_attr_names;
attr = get_measurement(attr_type, args);
if (attr)
{
msg->add_attribute(msg, attr);
return;
}
pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
attr_type.vendor_id);
if (pa_attr_names)
{
DBG1(DBG_IMC, "no measurement available for PA-TNC attribute type "
"'%N/%N' 0x%06x/0x%08x", pen_names, attr_type.vendor_id,
pa_attr_names, attr_type.type, attr_type.vendor_id, attr_type.type);
}
else
{
DBG1(DBG_IMC, "no measurement available for PA-TNC attribute type '%N' "
"0x%06x/0x%08x", pen_names, attr_type.vendor_id,
attr_type.vendor_id, attr_type.type);
}
}
/**
* Handle an IETF attribute
*/
static void handle_ietf_attribute(pen_type_t attr_type, pa_tnc_attr_t *attr,
imc_msg_t *out_msg)
{
if (attr_type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
{
ietf_attr_attr_request_t *attr_cast;
pen_type_t *entry;
enumerator_t *enumerator;
attr_cast = (ietf_attr_attr_request_t*)attr;
enumerator = attr_cast->create_enumerator(attr_cast);
while (enumerator->enumerate(enumerator, &entry))
{
add_measurement(*entry, out_msg, NULL);
}
enumerator->destroy(enumerator);
}
else if (attr_type.type == IETF_ATTR_REMEDIATION_INSTRUCTIONS)
{
ietf_attr_remediation_instr_t *attr_cast;
pen_type_t param;
chunk_t str;
char *instr;
attr_cast = (ietf_attr_remediation_instr_t*)attr;
param = attr_cast->get_parameters_type(attr_cast);
if (pen_type_is(param, PEN_IETF, IETF_REMEDIATION_PARAMETERS_STRING))
{
str = attr_cast->get_string(attr_cast, NULL);
instr = strndup(str.ptr, str.len);
charonservice->add_remediation_instr(charonservice, instr);
free (instr);
}
}
}
/**
* Handle an ITA attribute
*/
static void handle_ita_attribute(pen_type_t attr_type, pa_tnc_attr_t *attr,
imc_msg_t *out_msg)
{
if (attr_type.type == ITA_ATTR_GET_SETTINGS)
{
ita_attr_get_settings_t *attr_cast;
attr_cast = (ita_attr_get_settings_t*)attr;
add_measurement((pen_type_t){ PEN_ITA, ITA_ATTR_SETTINGS },
out_msg, attr_cast->create_enumerator(attr_cast));
}
}
/**
* Handle a TCG attribute
*/
static void handle_tcg_attribute(imc_android_state_t *state,
pen_type_t attr_type, pa_tnc_attr_t *attr,
imc_msg_t *out_msg)
{
pts_t *pts;
pts = state->get_pts(state);
switch (attr_type.type)
{
case TCG_PTS_REQ_PROTO_CAPS:
{
tcg_pts_attr_proto_caps_t *attr_cast;
pts_proto_caps_flag_t caps;
attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
caps = attr_cast->get_flags(attr_cast) & pts->get_proto_caps(pts);
pts->set_proto_caps(pts, caps);
attr = tcg_pts_attr_proto_caps_create(caps, FALSE);
out_msg->add_attribute(out_msg, attr);
break;
}
case TCG_PTS_MEAS_ALGO:
{
tcg_pts_attr_meas_algo_t *attr_cast;
pts_meas_algorithms_t supported, algo;
if (!pts_meas_algo_probe(&supported))
{
attr = pts_hash_alg_error_create(PTS_MEAS_ALGO_NONE);
out_msg->add_attribute(out_msg, attr);
break;
}
attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
algo = pts_meas_algo_select(supported,
attr_cast->get_algorithms(attr_cast));
if (algo == PTS_MEAS_ALGO_NONE)
{
attr = pts_hash_alg_error_create(supported);
out_msg->add_attribute(out_msg, attr);
break;
}
pts->set_meas_algorithm(pts, algo);
attr = tcg_pts_attr_meas_algo_create(algo, TRUE);
out_msg->add_attribute(out_msg, attr);
break;
}
case TCG_PTS_REQ_FILE_MEAS:
{
tcg_pts_attr_req_file_meas_t *attr_cast;
pts_file_meas_t *measurements;
pts_error_code_t pts_error;
u_int32_t delim;
u_int16_t req_id;
bool is_dir;
char *path;
attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
path = attr_cast->get_pathname(attr_cast);
if (!pts->is_path_valid(pts, path, &pts_error))
{ /* silently ignore internal errors */
break;
}
else if (pts_error)
{
attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
pts_error), attr->get_value(attr));
out_msg->add_attribute(out_msg, attr);
break;
}
delim = attr_cast->get_delimiter(attr_cast);
if (delim != SOLIDUS_UTF && delim != REVERSE_SOLIDUS_UTF)
{
attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
TCG_PTS_INVALID_DELIMITER), attr->get_value(attr));
out_msg->add_attribute(out_msg, attr);
break;
}
req_id = attr_cast->get_request_id(attr_cast);
is_dir = attr_cast->get_directory_flag(attr_cast);
DBG1(DBG_IMC, "measurement request %d for %s '%s'", req_id,
is_dir ? "directory" : "file", path);
measurements = pts_file_meas_create_from_path(req_id, path, is_dir,
TRUE, pts->get_meas_algorithm(pts));
if (!measurements)
{
attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
TCG_PTS_FILE_NOT_FOUND), attr->get_value(attr));
out_msg->add_attribute(out_msg, attr);
break;
}
attr = tcg_pts_attr_file_meas_create(measurements);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
break;
}
default:
DBG1(DBG_IMC, "received unsupported TCG attribute '%N'",
tcg_attr_names, attr_type.type);
break;
}
}
/**
* see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_beginhandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
imc_state_t *state;
imc_msg_t *out_msg;
TNC_Result result = TNC_RESULT_SUCCESS;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_android->get_state(imc_android, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
if (lib->settings->get_bool(lib->settings,
"android.imc.send_os_info", TRUE))
{
out_msg = imc_msg_create(imc_android, state, connection_id, imc_id,
TNC_IMVID_ANY, msg_types[0]);
add_measurement((pen_type_t){ PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION },
out_msg, NULL);
add_measurement((pen_type_t){ PEN_IETF, IETF_ATTR_STRING_VERSION },
out_msg, NULL);
add_measurement((pen_type_t){ PEN_ITA, ITA_ATTR_DEVICE_ID },
out_msg, NULL);
/* send PA-TNC message with the excl flag not set */
result = out_msg->send(out_msg, FALSE);
out_msg->destroy(out_msg);
}
return result;
}
static TNC_Result receive_message(imc_android_state_t *state, imc_msg_t *in_msg)
{
imc_msg_t *out_msg;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
pen_type_t attr_type;
TNC_Result result;
bool fatal_error = FALSE;
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
out_msg = imc_msg_create_as_reply(in_msg);
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
attr_type = attr->get_type(attr);
switch (attr_type.vendor_id)
{
case PEN_IETF:
handle_ietf_attribute(attr_type, attr, out_msg);
continue;
case PEN_ITA:
handle_ita_attribute(attr_type, attr, out_msg);
continue;
case PEN_TCG:
handle_tcg_attribute(state, attr_type, attr, out_msg);
continue;
default:
continue;
}
}
enumerator->destroy(enumerator);
if (fatal_error)
{
result = TNC_RESULT_FATAL;
}
else
{
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
/**
* see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_receivemessage(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_android->get_state(imc_android, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_data(imc_android, state, connection_id,
msg_type, chunk_create(msg, msg_len));
result = receive_message((imc_android_state_t*)state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
*/
static TNC_Result tnc_imc_receivemessagelong(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_VendorID msg_vid,
TNC_MessageSubtype msg_subtype,
TNC_UInt32 src_imv_id,
TNC_UInt32 dst_imc_id)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_android->get_state(imc_android, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_long_data(imc_android, state, connection_id,
src_imv_id, dst_imc_id,msg_vid, msg_subtype,
chunk_create(msg, msg_len));
result = receive_message((imc_android_state_t*)state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_batchending(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_terminate(TNC_IMCID imc_id)
{
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
imc_android->destroy(imc_android);
imc_android = NULL;
libpts_deinit();
return TNC_RESULT_SUCCESS;
}
/**
* see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_providebindfunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
{
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return imc_android->bind_functions(imc_android, bind_function);
}
/*
* Described in header
*/
bool imc_android_register(plugin_t *plugin, plugin_feature_t *feature,
bool reg, void *data)
{
JNIEnv *env;
jmethodID method_id;
jobject obj, context = (jobject)data;
jclass cls;
bool success = TRUE;
androidjni_attach_thread(&env);
if (reg)
{
cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/imc/AndroidImc");
if (!cls)
{
goto failed;
}
android_imc_cls = (*env)->NewGlobalRef(env, cls);
method_id = (*env)->GetMethodID(env, cls, "<init>",
"(Landroid/content/Context;)V");
if (!method_id)
{
goto failed;
}
obj = (*env)->NewObject(env, cls, method_id, context);
if (!obj)
{
goto failed;
}
android_imc = (*env)->NewGlobalRef(env, obj);
androidjni_detach_thread();
if (tnc->imcs->load_from_functions(tnc->imcs, "Android",
tnc_imc_initialize, tnc_imc_notifyconnectionchange,
tnc_imc_beginhandshake, tnc_imc_receivemessage,
tnc_imc_receivemessagelong, tnc_imc_batchending,
tnc_imc_terminate, tnc_imc_providebindfunction))
{
return TRUE;
}
failed:
DBG1(DBG_IMC, "initialization of Android IMC failed");
androidjni_exception_occurred(env);
success = FALSE;
}
if (android_imc)
{
(*env)->DeleteGlobalRef(env, android_imc);
android_imc = NULL;
}
if (android_imc_cls)
{
(*env)->DeleteGlobalRef(env, android_imc_cls);
android_imc_cls = NULL;
}
androidjni_detach_thread();
return success;
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 android_imc android_imc
* @{ @ingroup android_byod
*/
#ifndef ANDROID_IMC_H_
#define ANDROID_IMC_H_
/**
* Callback for the Android IMC plugin
*/
bool imc_android_register(plugin_t *plugin, plugin_feature_t *feature,
bool reg, void *data);
#endif /** ANDROID_IMC_H_ @}*/
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012 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.
*/
#include "imc_android_state.h"
#include <tncif_names.h>
#include <utils/debug.h>
typedef struct private_imc_android_state_t private_imc_android_state_t;
/**
* Private data of an imc_state_t object.
*/
struct private_imc_android_state_t {
/**
* Public interface
*/
imc_android_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Assessment/Evaluation Result
*/
TNC_IMV_Evaluation_Result result;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
u_int32_t max_msg_len;
/**
* TCG Platform Trust Service (PTS)
*/
pts_t *pts;
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
private_imc_android_state_t *this)
{
return this->connection_id;
}
METHOD(imc_state_t, has_long, bool,
private_imc_android_state_t *this)
{
return this->has_long;
}
METHOD(imc_state_t, has_excl, bool,
private_imc_android_state_t *this)
{
return this->has_excl;
}
METHOD(imc_state_t, set_flags, void,
private_imc_android_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imc_state_t, set_max_msg_len, void,
private_imc_android_state_t *this, u_int32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imc_state_t, get_max_msg_len, u_int32_t,
private_imc_android_state_t *this)
{
return this->max_msg_len;
}
METHOD(imc_state_t, change_state, void,
private_imc_android_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imc_state_t, set_result, void,
private_imc_android_state_t *this, TNC_IMCID id, TNC_IMV_Evaluation_Result result)
{
this->result = result;
}
METHOD(imc_state_t, get_result, bool,
private_imc_android_state_t *this, TNC_IMCID id, TNC_IMV_Evaluation_Result *result)
{
if (result)
{
*result = this->result;
}
return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
}
METHOD(imc_state_t, destroy, void,
private_imc_android_state_t *this)
{
this->pts->destroy(this->pts);
free(this);
}
METHOD(imc_android_state_t, get_pts, pts_t*,
private_imc_android_state_t *this)
{
return this->pts;
}
/**
* Described in header.
*/
imc_state_t *imc_android_state_create(TNC_ConnectionID connection_id)
{
private_imc_android_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.change_state = _change_state,
.set_result = _set_result,
.get_result = _get_result,
.destroy = _destroy,
},
.get_pts = _get_pts,
},
.state = TNC_CONNECTION_STATE_CREATE,
.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.pts = pts_create(TRUE),
);
return &this->public.interface;
}
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2012 Tobias Brunner
* 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 imc_android_state imc_android_state
* @{ @ingroup android_byod
*/
#ifndef IMC_ANDROID_STATE_H_
#define IMC_ANDROID_STATE_H_
#include <imc/imc_state.h>
#include <pts/pts.h>
typedef struct imc_android_state_t imc_android_state_t;
/**
* Internal state of an imc_android_t connection instance
*/
struct imc_android_state_t {
/**
* imc_state_t interface
*/
imc_state_t interface;
/**
* Get TCG Platform Trust Service (PTS) object
*/
pts_t *(*get_pts)(imc_android_state_t *this);
};
/**
* Create an imc_android_state_t instance
*
* @param id connection ID
*/
imc_state_t* imc_android_state_create(TNC_ConnectionID id);
#endif /** IMC_ANDROID_STATE_H_ @}*/
@@ -30,6 +30,10 @@
#include "kernel/android_ipsec.h"
#include "kernel/android_net.h"
#ifdef USE_BYOD
#include "byod/imc_android.h"
#endif
#include <daemon.h>
#include <hydra.h>
#include <ipsec.h>
@@ -158,6 +162,61 @@ failed:
return success;
}
METHOD(charonservice_t, update_imc_state, bool,
private_charonservice_t *this, android_imc_state_t state)
{
JNIEnv *env;
jmethodID method_id;
bool success = FALSE;
androidjni_attach_thread(&env);
method_id = (*env)->GetMethodID(env, android_charonvpnservice_class,
"updateImcState", "(I)V");
if (!method_id)
{
goto failed;
}
(*env)->CallVoidMethod(env, this->vpn_service, method_id, (jint)state);
success = !androidjni_exception_occurred(env);
failed:
androidjni_exception_occurred(env);
androidjni_detach_thread();
return success;
}
METHOD(charonservice_t, add_remediation_instr, bool,
private_charonservice_t *this, char *instr)
{
JNIEnv *env;
jmethodID method_id;
jstring jinstr;
bool success = FALSE;
androidjni_attach_thread(&env);
method_id = (*env)->GetMethodID(env, android_charonvpnservice_class,
"addRemediationInstruction",
"(Ljava/lang/String;)V");
if (!method_id)
{
goto failed;
}
jinstr = (*env)->NewStringUTF(env, instr);
if (!jinstr)
{
goto failed;
}
(*env)->CallVoidMethod(env, this->vpn_service, method_id, jinstr);
success = !androidjni_exception_occurred(env);
failed:
androidjni_exception_occurred(env);
androidjni_detach_thread();
return success;
}
/**
* Bypass a single socket
*/
@@ -357,7 +416,7 @@ static void initiate(char *type, char *gateway, char *username, char *password)
/**
* Initialize/deinitialize Android backend
*/
static bool charonservice_register(void *plugin, plugin_feature_t *feature,
static bool charonservice_register(plugin_t *plugin, plugin_feature_t *feature,
bool reg, void *data)
{
private_charonservice_t *this = (private_charonservice_t*)charonservice;
@@ -434,25 +493,37 @@ static void set_options(char *logfile)
lib->settings->set_str(lib->settings,
"charon.interfaces_ignore", "lo, tun0, tun1, tun2, tun3, "
"tun4");
#ifdef USE_BYOD
lib->settings->set_str(lib->settings,
"charon.plugins.eap-tnc.protocol", "tnccs-2.0");
lib->settings->set_bool(lib->settings,
"android.imc.send_os_info", TRUE);
lib->settings->set_str(lib->settings,
"libtnccs.tnc_config", "");
#endif
}
/**
* Initialize the charonservice object
*/
static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
static void charonservice_init(JNIEnv *env, jobject service, jobject builder,
jboolean byod)
{
private_charonservice_t *this;
static plugin_feature_t features[] = {
PLUGIN_CALLBACK(kernel_ipsec_register, kernel_android_ipsec_create),
PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
PLUGIN_CALLBACK((plugin_feature_callback_t)charonservice_register, NULL),
PLUGIN_PROVIDE(CUSTOM, "Android backend"),
PLUGIN_CALLBACK(charonservice_register, NULL),
PLUGIN_PROVIDE(CUSTOM, "android-backend"),
PLUGIN_DEPENDS(CUSTOM, "libcharon"),
};
INIT(this,
.public = {
.update_status = _update_status,
.update_imc_state = _update_imc_state,
.add_remediation_instr = _add_remediation_instr,
.bypass_socket = _bypass_socket,
.get_trusted_certificates = _get_trusted_certificates,
.get_user_certificate = _get_user_certificate,
@@ -471,6 +542,21 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
lib->plugins->add_static_features(lib->plugins, "androidbridge", features,
countof(features), TRUE);
#ifdef USE_BYOD
if (byod)
{
plugin_feature_t byod_features[] = {
PLUGIN_CALLBACK(imc_android_register, this->vpn_service),
PLUGIN_PROVIDE(CUSTOM, "android-imc"),
PLUGIN_DEPENDS(CUSTOM, "android-backend"),
PLUGIN_DEPENDS(CUSTOM, "imc-manager"),
};
lib->plugins->add_static_features(lib->plugins, "android-byod",
byod_features, countof(byod_features), TRUE);
}
#endif
}
/**
@@ -504,11 +590,11 @@ static void segv_handler(int signal)
* Initialize charon and the libraries via JNI
*/
JNI_METHOD(CharonVpnService, initializeCharon, void,
jobject builder, jstring jlogfile)
jobject builder, jstring jlogfile, jboolean byod)
{
struct sigaction action;
struct utsname utsname;
char *logfile;
char *logfile, *plugins;
/* logging for library during initialization, as we have no bus yet */
dbg = dbg_android;
@@ -551,7 +637,7 @@ JNI_METHOD(CharonVpnService, initializeCharon, void,
charon->load_loggers(charon, NULL, FALSE);
charonservice_init(env, this, builder);
charonservice_init(env, this, builder, byod);
if (uname(&utsname) != 0)
{
@@ -560,7 +646,18 @@ JNI_METHOD(CharonVpnService, initializeCharon, void,
DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)",
utsname.sysname, utsname.release, utsname.machine);
if (!charon->initialize(charon, PLUGINS))
#ifdef PLUGINS_BYOD
if (byod)
{
plugins = PLUGINS " " PLUGINS_BYOD;
}
else
#endif
{
plugins = PLUGINS;
}
if (!charon->initialize(charon, plugins))
{
libcharon_deinit();
charonservice_deinit(env);
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
@@ -21,6 +21,9 @@
* @defgroup android_backend backend
* @ingroup libandroidbridge
*
* @defgroup android_byod byod
* @ingroup libandroidbridge
*
* @defgroup android_kernel kernel
* @ingroup libandroidbridge
*
@@ -38,6 +41,7 @@
#include <collections/linked_list.h>
typedef enum android_vpn_state_t android_vpn_state_t;
typedef enum android_imc_state_t android_imc_state_t;
typedef struct charonservice_t charonservice_t;
/**
@@ -53,6 +57,16 @@ enum android_vpn_state_t {
CHARONSERVICE_GENERIC_ERROR,
};
/**
* Final IMC state as defined in ImcState.java
*/
enum android_imc_state_t {
ANDROID_IMC_STATE_UNKNOWN = 0,
ANDROID_IMC_STATE_ALLOW = 1,
ANDROID_IMC_STATE_BLOCK = 2,
ANDROID_IMC_STATE_ISOLATE = 3,
};
/**
* Public interface of charonservice.
*
@@ -68,6 +82,22 @@ struct charonservice_t {
*/
bool (*update_status)(charonservice_t *this, android_vpn_state_t code);
/**
* Update final IMC state in the Java domain (UI)
*
* @param state IMC state
* @return TRUE on success
*/
bool (*update_imc_state)(charonservice_t *this, android_imc_state_t state);
/**
* Add a remediation instruction via JNI
*
* @param instr remediation instruction
* @return TRUE on success
*/
bool (*add_remediation_instr)(charonservice_t *this, char *instr);
/**
* Install a bypass policy for the given socket using the protect() Method
* of the Android VpnService interface.
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid
android:color="@color/panel_separator" />
</shape>
</item>
<item android:left="2dp">
<shape>
<solid
android:color="@color/panel_background" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012-2013 Tobias Brunner
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid
android:color="@color/panel_separator" />
</shape>
</item>
<item android:bottom="2dp">
<shape>
<solid
android:color="@color/panel_background" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false" >
<fragment
class="org.strongswan.android.ui.RemediationInstructionsFragment"
android:id="@+id/remediation_instructions_fragment"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_width="0dp" />
<FrameLayout
android:layout_height="match_parent"
android:layout_weight="2"
android:layout_width="0dp"
android:background="@drawable/remediation_instruction_background_large"
android:padding="5dp" >
<fragment
class="org.strongswan.android.ui.RemediationInstructionFragment"
android:id="@+id/remediation_instruction_fragment"
android:layout_height="match_parent"
android:layout_width="match_parent" />
</FrameLayout>
</LinearLayout>
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="2dp"
android:background="@drawable/state_background"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/imc_state_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:text="@string/imc_state_label"
android:textColor="?android:textColorPrimary"
android:textSize="20sp" />
<TextView
android:id="@+id/imc_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="?android:textColorSecondary"
android:textSize="20sp" />
</LinearLayout>
<TextView
android:id="@+id/action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="@string/show_remediation_instructions"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
</LinearLayout>
+7 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Tobias Brunner
Copyright (C) 2012-2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
@@ -24,6 +24,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
class="org.strongswan.android.ui.ImcStateFragment"
android:id="@+id/imc_state_frag"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
class="org.strongswan.android.ui.VpnProfileListFragment"
android:id="@+id/profile_list_frag"
@@ -65,6 +65,11 @@
android:spinnerMode="dropdown"
android:entries="@array/vpn_types" />
<include
android:id="@+id/tnc_notice"
layout="@layout/two_line_button"
android:visibility="gone" />
<LinearLayout
android:id="@+id/username_password_group"
android:layout_width="match_parent"
@@ -114,7 +119,7 @@
<include
android:id="@+id/select_user_certificate"
layout="@layout/certificate_selector" />
layout="@layout/two_line_button" />
</LinearLayout>
@@ -132,7 +137,7 @@
<include
android:id="@+id/select_certificate"
layout="@layout/certificate_selector" />
layout="@layout/two_line_button" />
</LinearLayout>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textIsSelectable="true"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textIsSelectable="true"
android:textColor="?android:textColorSecondary"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/list_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="20dp"
android:textIsSelectable="true"
android:textAppearance="?android:attr/textAppearanceMedium" />
<include
layout="@android:layout/list_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="5dp" />
</LinearLayout>
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
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.
-->
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dip"
android:paddingTop="8dip"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeight"
android:mode="twoLine" >
<TextView
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false" />
<TextView
android:id="@android:id/text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/text1"
android:layout_alignLeft="@android:id/text1"
android:layout_alignRight="@android:id/text1"
android:textColor="?android:textColorSecondary"
android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
android:ellipsize="end"
android:textIsSelectable="false" />
</TwoLineListItem>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Tobias Brunner
Copyright (C) 2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
@@ -13,9 +13,9 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment_container">
<solid
android:color="#333" />
</shape>
</FrameLayout>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Tobias Brunner
Copyright (C) 2012-2013 Tobias Brunner
Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager
Hochschule fuer Technik Rapperswil
@@ -18,8 +18,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:background="@drawable/vpn_state_background"
android:paddingBottom="2dp"
android:background="@drawable/state_background"
android:orientation="vertical" >
<GridLayout
@@ -83,9 +83,4 @@
style="?android:attr/borderlessButtonStyle" >
</Button>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="?android:attr/listDivider" />
</LinearLayout>
@@ -19,5 +19,6 @@
<item>IKEv2 EAP (Benutzername/Passwort)</item>
<item>IKEv2 Zertifikat</item>
<item>IKEv2 Zertifikat + EAP (Benutzername/Passwort)</item>
<item>IKEv2 EAP-TNC (Benutzername/Passwort)</item>
</string-array>
</resources>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Tobias Brunner
Copyright (C) 2012-2013 Tobias Brunner
Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager
Hochschule fuer Technik Rapperswil
@@ -69,6 +69,9 @@
<string name="alert_text_no_input_username">Bitte geben Sie hier Ihren Benutzernamen ein</string>
<string name="alert_text_nocertfound_title">Kein CA-Zertifikat ausgewählt</string>
<string name="alert_text_nocertfound">Bitte wählen Sie eines aus oder aktivieren Sie <i>Automatisch wählen</i></string>
<string name="tnc_notice_title">EAP-TNC kann Ihre Privatsphäre beeinträchtigen</string>
<string name="tnc_notice_subtitle">Gerätedaten werden an den Gateway-Betreiber gesendet</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) erlaubt Gateway-Betreibern den Gesundheitszustand von Endgeräten zu prüfen.&lt;/p>&lt;p>Dazu kann der Betreiber Daten verlangen, wie etwa eine eindeutige Identifikationsnummer, eine Liste der installierten Pakete, Systemeinstellungen oder kryptografische Prüfsummen von Dateien.&lt;/p>&lt;b>Solche Daten werden nur übermittelt nachdem die Identität des Gateways geprüft wurde.&lt;/b></string>
<!-- Trusted certificate selection -->
<string name="trusted_certs_title">CA-Zertifikate</string>
@@ -86,6 +89,15 @@
<string name="state_disabled">Kein aktives Profil</string>
<string name="state_error">Fehler</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Eingeschränkt</string>
<string name="imc_state_block">Fehlgeschlagen</string>
<string name="show_remediation_instructions">Korrekturanweisungen anzeigen</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Korrekturanweisungen</string>
<!-- Dialogs -->
<string name="login_title">Passwort eingeben um zu verbinden</string>
<string name="login_confirm">Verbinden</string>
@@ -94,6 +106,7 @@
<string name="error_unreachable">Gateway ist nicht erreichbar.</string>
<string name="error_peer_auth_failed">Authentifizierung des Gateway ist fehlgeschlagen.</string>
<string name="error_auth_failed">Benutzerauthentifizierung ist fehlgeschlagen.</string>
<string name="error_assessment_failed">Sicherheitsassessment ist fehlgeschlagen.</string>
<string name="error_generic">Unbekannter Fehler während des Verbindens.</string>
<string name="connecting_title">Verbinden: %1$s</string>
<string name="connecting_message">Verbinde mit \""%1$s\".</string>
@@ -19,5 +19,6 @@
<item>IKEv2 EAP (użytkownik/hasło)</item>
<item>IKEv2 certyfikat</item>
<item>IKEv2 certyfikat + EAP (użytkownik/hasło)</item>
<item>IKEv2 EAP-TNC (użytkownik/hasło)</item>
</string-array>
</resources>
@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager
Copyright (C) 2012 Andreas Steffen
HSR Hochschule fuer Technik Rapperswil
@@ -71,6 +69,9 @@
<string name="alert_text_no_input_username">Wprowadź swoją nazwę użytkownika</string>
<string name="alert_text_nocertfound_title">Nie wybrano żadnego certyfikatu CA</string>
<string name="alert_text_nocertfound">Wybierz lub uaktywnij jeden <i>Wybierz automatycznie</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection -->
<string name="trusted_certs_title">Certyfikaty CA</string>
@@ -88,6 +89,15 @@
<string name="state_disabled">Brak aktywnego VPN</string>
<string name="state_error">Błąd</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs -->
<string name="login_title">Wprowadż hasło</string>
<string name="login_confirm">Połącz</string>
@@ -96,6 +106,7 @@
<string name="error_unreachable">Bramka jest nieosiągalna</string>
<string name="error_peer_auth_failed">Błąd przy weryfikacji bramki</string>
<string name="error_auth_failed">Błąd przy autoryzacji użytkownika</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Nieznany błąd w czasie połączenia</string>
<string name="connecting_title">Łączenie: %1$s</string>
<string name="connecting_message">Tworzenie tunelu VPN z \""%1$s\".</string>
@@ -18,5 +18,6 @@
<item>IKEv2 EAP (Логин/Пароль)</item>
<item>IKEv2 Сертификат</item>
<item>IKEv2 Сертификат + EAP (Логин/Пароль)</item>
<item>IKEv2 EAP-TNC (Логин/Пароль)</item>
</string-array>
</resources>
@@ -66,6 +66,9 @@
<string name="alert_text_no_input_username">Пожалуйста введите имя пользователя</string>
<string name="alert_text_nocertfound_title">Не выбран сертификат CA</string>
<string name="alert_text_nocertfound">Пожалуйста выберите один <i>Выбрать автоматически</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection -->
<string name="trusted_certs_title">Сертификаты CA</string>
@@ -83,6 +86,15 @@
<string name="state_disabled">Нет активных VPN</string>
<string name="state_error">Ошибка</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs -->
<string name="login_title">Введите пароль для соединения</string>
<string name="login_confirm">Соединить</string>
@@ -91,6 +103,7 @@
<string name="error_unreachable">Шлюз недоступен.</string>
<string name="error_peer_auth_failed">Ошибка авторизаци при подключении к шлюзу.</string>
<string name="error_auth_failed">Ошибка авторизации пользователя.</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Неизвестная ошибка.</string>
<string name="connecting_title">Подключение: %1$s</string>
<string name="connecting_message">Подключение к VPN с \""%1$s\".</string>
@@ -18,5 +18,6 @@
<item>IKEv2 EAP (Логін/Пароль)</item>
<item>IKEv2 Сертифікати</item>
<item>IKEv2 Сертифікати + EAP (Логін/Пароль)</item>
<item>IKEv2 EAP-TNC (Логін/Пароль)</item>
</string-array>
</resources>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Dmitry Korzhevin
Copyright (C) 2013 Pavel Kopchyk
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
@@ -67,6 +67,9 @@
<string name="alert_text_no_input_username">Введіть ім\'я користувача тут</string>
<string name="alert_text_nocertfound_title">Не вибрано сертифікат CA</string>
<string name="alert_text_nocertfound">Будь ласка виберіть один <i>Вибрати автоматично</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection -->
<string name="trusted_certs_title">Сертифікати CA</string>
@@ -84,6 +87,15 @@
<string name="state_disabled">Немає активних VPN</string>
<string name="state_error">Помилка</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs -->
<string name="login_title">Введіть пароль для з\'єднання</string>
<string name="login_confirm">Підключити</string>
@@ -92,6 +104,7 @@
<string name="error_unreachable">Немає зв\'язку зі шлюзом.</string>
<string name="error_peer_auth_failed">Помилка перевірки данних аутентифікації шлюза.</string>
<string name="error_auth_failed">Помилка аутентифікації користувача.</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Невідома помилка під час підключення.</string>
<string name="connecting_title">Підключення: %1$s</string>
<string name="connecting_message">Підключення VPN з \""%1$s\".</string>
@@ -19,5 +19,6 @@
<item>IKEv2 EAP (Username/Password)</item>
<item>IKEv2 Certificate</item>
<item>IKEv2 Certificate + EAP (Username/Password)</item>
<item>IKEv2 EAP-TNC (Username/Password)</item>
</string-array>
</resources>
+10 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Tobias Brunner
Copyright (C) 2012-2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
@@ -18,7 +18,16 @@
<color
name="error_text">#D9192C</color>
<color
name="warning_text">#FF9909</color>
<color
name="success_text">#99CC00</color>
<color
name="panel_background">#333333</color>
<color
name="panel_separator">#5a5a5a</color>
</resources>
+14 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Tobias Brunner
Copyright (C) 2012-2013 Tobias Brunner
Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager
Hochschule fuer Technik Rapperswil
@@ -69,6 +69,9 @@
<string name="alert_text_no_input_username">Please enter your username here</string>
<string name="alert_text_nocertfound_title">No CA certificate selected</string>
<string name="alert_text_nocertfound">Please select one or activate <i>Select automatically</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection -->
<string name="trusted_certs_title">CA certificates</string>
@@ -86,6 +89,15 @@
<string name="state_disabled">No active VPN</string>
<string name="state_error">Error</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs -->
<string name="login_title">Enter password to connect</string>
<string name="login_confirm">Connect</string>
@@ -94,6 +106,7 @@
<string name="error_unreachable">Gateway is unreachable.</string>
<string name="error_peer_auth_failed">Verifying gateway authentication failed.</string>
<string name="error_auth_failed">User authentication failed.</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Unspecified failure while connecting.</string>
<string name="connecting_title">Connecting: %1$s</string>
<string name="connecting_message">Establishing VPN with \""%1$s\".</string>
@@ -20,11 +20,13 @@ public enum VpnType
/* the order here must match the items in R.array.vpn_types */
IKEV2_EAP("ikev2-eap", true, false),
IKEV2_CERT("ikev2-cert", false, true),
IKEV2_CERT_EAP("ikev2-cert-eap", true, true);
IKEV2_CERT_EAP("ikev2-cert-eap", true, true),
IKEV2_BYOD_EAP("ikev2-byod-eap", true, false, true);
private String mIdentifier;
private boolean mCertificate;
private boolean mUsernamePassword;
private boolean mBYOD;
/**
* Enum which provides additional information about the supported VPN types.
@@ -34,10 +36,24 @@ public enum VpnType
* @param certificate true if a client certificate is required
*/
VpnType(String id, boolean userpass, boolean certificate)
{
this(id, userpass, certificate, false);
}
/**
* Enum which provides additional information about the supported VPN types.
*
* @param id identifier used to store and transmit this specific type
* @param userpass true if username and password are required
* @param certificate true if a client certificate is required
* @param byod true to enable BYOD features
*/
VpnType(String id, boolean userpass, boolean certificate, boolean byod)
{
mIdentifier = id;
mUsernamePassword = userpass;
mCertificate = certificate;
mBYOD = byod;
}
/**
@@ -69,6 +85,16 @@ public enum VpnType
return mCertificate;
}
/**
* Whether BYOD features should be enabled.
*
* @return true if BYOD features are to be enabled
*/
public boolean getEnableBYOD()
{
return mBYOD;
}
/**
* Get the enum entry with the given identifier.
*
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
@@ -27,6 +27,8 @@ import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.data.VpnProfileDataSource;
import org.strongswan.android.logic.VpnStateService.ErrorState;
import org.strongswan.android.logic.VpnStateService.State;
import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.logic.imc.RemediationInstruction;
import org.strongswan.android.ui.MainActivity;
import android.app.PendingIntent;
@@ -208,10 +210,11 @@ public class CharonVpnService extends VpnService implements Runnable
setProfile(mCurrentProfile);
setError(ErrorState.NO_ERROR);
setState(State.CONNECTING);
setImcState(ImcState.UNKNOWN);
mIsDisconnecting = false;
BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName());
initializeCharon(builder, mLogFile);
initializeCharon(builder, mLogFile, mCurrentProfile.getVpnType().getEnableBYOD());
Log.i(TAG, "charon started");
initiate(mCurrentProfile.getVpnType().getIdentifier(),
@@ -296,6 +299,23 @@ public class CharonVpnService extends VpnService implements Runnable
}
}
/**
* Set the IMC state on the state service. Called by the handler thread and
* any of charon's threads.
*
* @param state IMC state
*/
private void setImcState(ImcState state)
{
synchronized (mServiceLock)
{
if (mService != null)
{
mService.setImcState(state);
}
}
}
/**
* Set an error on the state service and disconnect the current connection.
* This is not done by calling stopCurrentConnection() above, but instead
@@ -355,6 +375,41 @@ public class CharonVpnService extends VpnService implements Runnable
}
}
/**
* Updates the IMC state of the current connection.
* Called via JNI by different threads (but not concurrently).
*
* @param value new state
*/
public void updateImcState(int value)
{
ImcState state = ImcState.fromValue(value);
if (state != null)
{
setImcState(state);
}
}
/**
* Add a remediation instruction to the VPN state service.
* Called via JNI by different threads (but not concurrently).
*
* @param xml XML text
*/
public void addRemediationInstruction(String xml)
{
for (RemediationInstruction instruction : RemediationInstruction.fromXml(xml))
{
synchronized (mServiceLock)
{
if (mService != null)
{
mService.addRemediationInstruction(instruction);
}
}
}
}
/**
* Function called via JNI to generate a list of DER encoded CA certificates
* as byte array.
@@ -461,8 +516,9 @@ public class CharonVpnService extends VpnService implements Runnable
*
* @param builder BuilderAdapter for this connection
* @param logfile absolute path to the logfile
* @param boyd enable BYOD features
*/
public native void initializeCharon(BuilderAdapter builder, String logfile);
public native void initializeCharon(BuilderAdapter builder, String logfile, boolean byod);
/**
* Deinitialize charon, provided by libandroidbridge.so
@@ -600,6 +656,15 @@ public class CharonVpnService extends VpnService implements Runnable
{
System.loadLibrary("crypto");
System.loadLibrary("strongswan");
if (MainActivity.USE_BYOD)
{
System.loadLibrary("tncif");
System.loadLibrary("tnccs");
System.loadLibrary("imcv");
System.loadLibrary("pts");
}
System.loadLibrary("hydra");
System.loadLibrary("charon");
System.loadLibrary("ipsec");
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -16,10 +16,14 @@
package org.strongswan.android.logic;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.app.Service;
import android.content.Context;
@@ -36,6 +40,8 @@ public class VpnStateService extends Service
private VpnProfile mProfile;
private State mState = State.DISABLED;
private ErrorState mError = ErrorState.NO_ERROR;
private ImcState mImcState = ImcState.UNKNOWN;
private final LinkedList<RemediationInstruction> mRemediationInstructions = new LinkedList<RemediationInstruction>();
public enum State
{
@@ -146,6 +152,26 @@ public class VpnStateService extends Service
return mError;
}
/**
* Get the current IMC state, if any.
*
* @return imc state
*/
public ImcState getImcState()
{ /* only updated from the main thread so no synchronization needed */
return mImcState;
}
/**
* Get the remediation instructions, if any.
*
* @return read-only list of instructions
*/
public List<RemediationInstruction> getRemediationInstructions()
{ /* only updated from the main thread so no synchronization needed */
return Collections.unmodifiableList(mRemediationInstructions);
}
/**
* Disconnect any existing connection and shutdown the daemon, the
* VpnService is not stopped but it is reset so new connections can be
@@ -261,4 +287,54 @@ public class VpnStateService extends Service
}
});
}
/**
* Set the current IMC state and notify all listeners, if changed.
*
* Setting the state to UNKNOWN clears all remediation instructions.
*
* May be called from threads other than the main thread.
*
* @param error error state
*/
public void setImcState(final ImcState state)
{
notifyListeners(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception
{
if (state == ImcState.UNKNOWN)
{
VpnStateService.this.mRemediationInstructions.clear();
}
if (VpnStateService.this.mImcState != state)
{
VpnStateService.this.mImcState = state;
return true;
}
return false;
}
});
}
/**
* Add the given remediation instruction to the internal list. Listeners
* are not notified.
*
* Instructions are cleared if the IMC state is set to UNKNOWN.
*
* May be called from threads other than the main thread.
*
* @param instruction remediation instruction
*/
public void addRemediationInstruction(final RemediationInstruction instruction)
{
mHandler.post(new Runnable() {
@Override
public void run()
{
VpnStateService.this.mRemediationInstructions.add(instruction);
}
});
}
}
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.AttributeType;
import org.strongswan.android.logic.imc.collectors.Collector;
import org.strongswan.android.logic.imc.collectors.DeviceIdCollector;
import org.strongswan.android.logic.imc.collectors.InstalledPackagesCollector;
import org.strongswan.android.logic.imc.collectors.PortFilterCollector;
import org.strongswan.android.logic.imc.collectors.ProductInformationCollector;
import org.strongswan.android.logic.imc.collectors.SettingsCollector;
import org.strongswan.android.logic.imc.collectors.StringVersionCollector;
import android.content.Context;
public class AndroidImc
{
private final Context mContext;
public AndroidImc(Context context)
{
mContext = context;
}
/**
* Get a measurement (the binary encoding of the requested attribute) for
* the given vendor specific attribute type.
*
* @param vendor vendor ID
* @param type vendor specific attribute type
* @return encoded attribute, or null if not available or failed
*/
public byte[] getMeasurement(int vendor, int type)
{
return getMeasurement(vendor, type, null);
}
/**
* Get a measurement (the binary encoding of the requested attribute) for
* the given vendor specific attribute type.
*
* @param vendor vendor ID
* @param type vendor specific attribute type
* @param args optional arguments for a measurement
* @return encoded attribute, or null if not available or failed
*/
public byte[] getMeasurement(int vendor, int type, String[] args)
{
AttributeType attributeType = AttributeType.fromValues(vendor, type);
Collector collector = null;
switch (attributeType)
{
case IETF_PRODUCT_INFORMATION:
collector = new ProductInformationCollector();
break;
case IETF_STRING_VERSION:
collector = new StringVersionCollector();
break;
case IETF_PORT_FILTER:
collector = new PortFilterCollector();
break;
case IETF_INSTALLED_PACKAGES:
collector = new InstalledPackagesCollector(mContext);
break;
case ITA_SETTINGS:
collector = new SettingsCollector(mContext, args);
break;
case ITA_DEVICE_ID:
collector = new DeviceIdCollector(mContext);
break;
default:
break;
}
if (collector != null)
{
Attribute attribute = collector.getMeasurement();
if (attribute != null)
{
return attribute.getEncoding();
}
}
return null;
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc;
public enum ImcState
{
UNKNOWN(0),
ALLOW(1),
BLOCK(2),
ISOLATE(3);
private final int mValue;
private ImcState(int value)
{
mValue = value;
}
/**
* Get the numeric value of the IMC state.
* @return numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Get the enum entry from a numeric value, if defined
*
* @param value numeric value
* @return the enum entry or null
*/
public static ImcState fromValue(int value)
{
for (ImcState state : ImcState.values())
{
if (state.mValue == value)
{
return state;
}
}
return null;
}
}
@@ -0,0 +1,273 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Xml;
public class RemediationInstruction implements Parcelable
{
private String mTitle;
private String mDescription;
private String mHeader;
private final List<String> mItems = new LinkedList<String>();
@Override
public int describeContents()
{
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeString(mTitle);
dest.writeString(mDescription);
dest.writeString(mHeader);
dest.writeStringList(mItems);
}
public static final Parcelable.Creator<RemediationInstruction> CREATOR = new Creator<RemediationInstruction>() {
@Override
public RemediationInstruction[] newArray(int size)
{
return new RemediationInstruction[size];
}
@Override
public RemediationInstruction createFromParcel(Parcel source)
{
return new RemediationInstruction(source);
}
};
private RemediationInstruction()
{
}
private RemediationInstruction(Parcel source)
{
mTitle = source.readString();
mDescription = source.readString();
mHeader = source.readString();
source.readStringList(mItems);
}
public String getTitle()
{
return mTitle;
}
private void setTitle(String title)
{
mTitle = title;
}
public String getDescription()
{
return mDescription;
}
private void setDescription(String description)
{
mDescription = description;
}
public String getHeader()
{
return mHeader;
}
private void setHeader(String header)
{
mHeader = header;
}
public List<String> getItems()
{
return Collections.unmodifiableList(mItems);
}
private void addItem(String item)
{
mItems.add(item);
}
/**
* Create a list of RemediationInstruction objects from the given XML data.
*
* @param xml XML data
* @return list of RemediationInstruction objects
*/
public static List<RemediationInstruction> fromXml(String xml)
{
List<RemediationInstruction> instructions = new LinkedList<RemediationInstruction>();
XmlPullParser parser = Xml.newPullParser();
try
{
parser.setInput(new StringReader(xml));
parser.nextTag();
readInstructions(parser, instructions);
}
catch (XmlPullParserException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return instructions;
}
/**
* Read a &lt;remediationinstructions&gt; element and store the extracted
* RemediationInstruction objects in the given list.
*
* @param parser
* @param instructions
* @throws XmlPullParserException
* @throws IOException
*/
private static void readInstructions(XmlPullParser parser, List<RemediationInstruction> instructions) throws XmlPullParserException, IOException
{
parser.require(XmlPullParser.START_TAG, null, "remediationinstructions");
while (parser.next() != XmlPullParser.END_TAG)
{
if (parser.getEventType() != XmlPullParser.START_TAG)
{
continue;
}
if (parser.getName().equals("instruction"))
{
RemediationInstruction instruction = new RemediationInstruction();
readInstruction(parser, instruction);
instructions.add(instruction);
}
else
{
skipTag(parser);
}
}
}
/**
* Read an &lt;instruction&gt; element and store the information in the
* given RemediationInstruction object.
*
* @param parser
* @param instruction
* @throws XmlPullParserException
* @throws IOException
*/
private static void readInstruction(XmlPullParser parser, RemediationInstruction instruction) throws XmlPullParserException, IOException
{
parser.require(XmlPullParser.START_TAG, null, "instruction");
while (parser.next() != XmlPullParser.END_TAG)
{
if (parser.getEventType() != XmlPullParser.START_TAG)
{
continue;
}
String name = parser.getName();
if (name.equals("title"))
{
instruction.setTitle(parser.nextText());
}
else if (name.equals("description"))
{
instruction.setDescription(parser.nextText());
}
else if (name.equals("itemsheader"))
{
instruction.setHeader(parser.nextText());
}
else if (name.equals("items"))
{
readItems(parser, instruction);
}
else
{
skipTag(parser);
}
}
}
/**
* Read all items of an &lt;items&gt; node and add them to the given
* RemediationInstruction object.
*
* @param parser
* @param instruction
* @throws XmlPullParserException
* @throws IOException
*/
private static void readItems(XmlPullParser parser, RemediationInstruction instruction) throws XmlPullParserException, IOException
{
while (parser.next() != XmlPullParser.END_TAG)
{
if (parser.getEventType() != XmlPullParser.START_TAG)
{
continue;
}
if (parser.getName().equals("item"))
{
instruction.addItem(parser.nextText());
}
else
{
skipTag(parser);
}
}
}
/**
* Skip the current tag and all child elements.
*
* @param parser
* @throws XmlPullParserException
* @throws IOException
*/
private static void skipTag(XmlPullParser parser) throws XmlPullParserException, IOException
{
int depth = 1;
parser.require(XmlPullParser.START_TAG, null, null);
while (depth != 0)
{
switch (parser.next())
{
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
/**
* Interface to be implemented by attribute classes
*/
public interface Attribute
{
/**
* Returns the binary encoding of the attribute
* @return binary encoding
*/
public byte[] getEncoding();
}
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
public enum AttributeType
{
/* IETF standard PA-TNC attribute types defined by RFC 5792 */
IETF_TESTING(PrivateEnterpriseNumber.IETF, 0),
IETF_ATTRIBUTE_REQUEST(PrivateEnterpriseNumber.IETF, 1),
IETF_PRODUCT_INFORMATION(PrivateEnterpriseNumber.IETF, 2),
IETF_NUMERIC_VERSION(PrivateEnterpriseNumber.IETF, 3),
IETF_STRING_VERSION(PrivateEnterpriseNumber.IETF, 4),
IETF_OPERATIONAL_STATUS(PrivateEnterpriseNumber.IETF, 5),
IETF_PORT_FILTER(PrivateEnterpriseNumber.IETF, 6),
IETF_INSTALLED_PACKAGES(PrivateEnterpriseNumber.IETF, 7),
IETF_PA_TNC_ERROR(PrivateEnterpriseNumber.IETF, 8),
IETF_ASSESSMENT_RESULT(PrivateEnterpriseNumber.IETF, 9),
IETF_REMEDIATION_INSTRUCTIONS(PrivateEnterpriseNumber.IETF, 10),
IETF_FORWARDING_ENABLED(PrivateEnterpriseNumber.IETF, 11),
IETF_FACTORY_DEFAULT_PWD_ENABLED(PrivateEnterpriseNumber.IETF, 12),
IETF_RESERVED(PrivateEnterpriseNumber.IETF, 0xffffffff),
/* ITA attributes */
ITA_SETTINGS(PrivateEnterpriseNumber.ITA, 4),
ITA_DEVICE_ID(PrivateEnterpriseNumber.ITA, 8);
private PrivateEnterpriseNumber mVendor;
private int mType;
/**
* Enum type for vendor specific attributes (defined in their namespace)
*
* @param vendor private enterprise number of vendor
* @param type vendor specific attribute type
*/
private AttributeType(PrivateEnterpriseNumber vendor, int type)
{
mVendor = vendor;
mType = type;
}
/**
* Get private enterprise number of vendor
*
* @return PEN
*/
public PrivateEnterpriseNumber getVendor()
{
return mVendor;
}
/**
* Get vendor specific type
*
* @return type
*/
public int getType()
{
return mType;
}
/**
* Get the enum entry from the given numeric values, if defined
*
* @param vendor vendor id
* @param type vendor specific type
* @return enum entry or null
*/
public static AttributeType fromValues(int vendor, int type)
{
PrivateEnterpriseNumber pen = PrivateEnterpriseNumber.fromValue(vendor);
if (pen == null)
{
return null;
}
for (AttributeType attr : AttributeType.values())
{
if (attr.mVendor == pen && attr.mType == type)
{
return attr;
}
}
return null;
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
/**
* ITA Device ID attribute
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Device ID (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class DeviceIdAttribute implements Attribute
{
private String mDeviceId;
/**
* Set the device ID
* @param version version number
*/
public void setDeviceId(String deviceId)
{
this.mDeviceId = deviceId;
}
@Override
public byte[] getEncoding()
{
return mDeviceId.getBytes();
}
}
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
import java.util.LinkedList;
import org.strongswan.android.utils.BufferedByteWriter;
import android.util.Pair;
/**
* PA-TNC Installed Packages attribute (see section 4.2.7 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved | Package Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Pkg Name Len | Package Name (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Version Len | Package Version Number (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class InstalledPackagesAttribute implements Attribute
{
private final short RESERVED = 0;
private final LinkedList<Pair<String, String>> mPackages = new LinkedList<Pair<String, String>>();
/**
* Add an installed package to this attribute.
* @param name name of the package
* @param version version number of the package
*/
public void addPackage(String name, String version)
{
mPackages.add(new Pair<String, String>(name, version));
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.put16(RESERVED);
writer.put16((short)mPackages.size());
for (Pair<String, String> pair : mPackages)
{
writer.putLen8(pair.first.getBytes());
writer.putLen8(pair.second.getBytes());
}
return writer.toByteArray();
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
import java.util.LinkedList;
import org.strongswan.android.logic.imc.collectors.Protocol;
import org.strongswan.android.utils.BufferedByteWriter;
import android.util.Pair;
/**
* PA-TNC Port Filter attribute (see section 4.2.6 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved |B| Protocol | Port Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved |B| Protocol | Port Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class PortFilterAttribute implements Attribute
{
private final LinkedList<Pair<Protocol, Short>> mPorts = new LinkedList<Pair<Protocol, Short>>();
/**
* Add an open port with the given protocol and port number
* @param protocol transport protocol
* @param port port number
*/
public void addPort(Protocol protocol, short port)
{
mPorts.add(new Pair<Protocol, Short>(protocol, port));
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
for (Pair<Protocol, Short> port : mPorts)
{
/* we report open ports, so the BLOCKED flag is not set */
writer.put((byte)0);
writer.put(port.first.getValue());
writer.put16(port.second);
}
return writer.toByteArray();
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
public enum PrivateEnterpriseNumber
{
IETF(0x000000),
GOOGLE(0x002B79),
ITA(0x00902a),
UNASSIGNED(0xfffffe),
RESERVED(0xffffff);
private int mValue;
/**
* Enum for private enterprise numbers (PEN) as allocated by IANA
*
* @param value numeric value
*/
private PrivateEnterpriseNumber(int value)
{
mValue = value;
}
/**
* Get the numeric value of a PEN
*
* @return numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Get the enum entry from a numeric value, if defined
*
* @param value numeric value
* @return the enum entry or null
*/
public static PrivateEnterpriseNumber fromValue(int value)
{
for (PrivateEnterpriseNumber pen : PrivateEnterpriseNumber.values())
{
if (pen.mValue == value)
{
return pen;
}
}
return null;
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
import org.strongswan.android.utils.BufferedByteWriter;
/**
* PA-TNC Product Information attribute (see section 4.2.2 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Product Vendor ID | Product ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Product ID | Product Name (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class ProductInformationAttribute implements Attribute
{
private final String PRODUCT_NAME = "Android";
private final short PRODUCT_ID = 0;
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.put24(PrivateEnterpriseNumber.GOOGLE.getValue());
writer.put16(PRODUCT_ID);
writer.put(PRODUCT_NAME.getBytes());
return writer.toByteArray();
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
import java.util.LinkedList;
import org.strongswan.android.utils.BufferedByteWriter;
import android.util.Pair;
/**
* ITA Settings attribute
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Settings Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Name Length | Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Value Length | Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Name Length | Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Value Length | Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ...........................
*/
public class SettingsAttribute implements Attribute
{
private final LinkedList<Pair<String, String>> mSettings = new LinkedList<Pair<String, String>>();
/**
* Add a setting to this attribute.
* @param name name of the setting
* @param value value of the setting
*/
public void addSetting(String name, String value)
{
mSettings.add(new Pair<String, String>(name, value));
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.put32(mSettings.size());
for (Pair<String, String> pair : mSettings)
{
writer.putLen16(pair.first.getBytes());
writer.putLen16(pair.second.getBytes());
}
return writer.toByteArray();
}
}
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.attributes;
import org.strongswan.android.utils.BufferedByteWriter;
/**
* PA-TNC String Version attribute (see section 4.2.4 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Version Len | Product Version Number (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Build Num Len | Internal Build Number (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Config. Len | Configuration Version Number (Variable Length)|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class StringVersionAttribute implements Attribute
{
private String mVersionNumber;
private String mBuildNumber;
/**
* Set the product version number
* @param version version number
*/
public void setProductVersionNumber(String version)
{
this.mVersionNumber = version;
}
/**
* Set the internal build number
* @param build build number
*/
public void setInternalBuildNumber(String build)
{
this.mBuildNumber = build;
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.putLen8(mVersionNumber.getBytes());
writer.putLen8(mBuildNumber.getBytes());
/* we don't provide a configuration number */
writer.put((byte)0);
return writer.toByteArray();
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
/**
* Interface for measurement collectors
*/
public interface Collector
{
/**
* This method shall return the result of a measurement, if available
* @return attribute or null
*/
public abstract Attribute getMeasurement();
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.DeviceIdAttribute;
import android.content.ContentResolver;
import android.content.Context;
public class DeviceIdCollector implements Collector
{
private final ContentResolver mContentResolver;
public DeviceIdCollector(Context context)
{
mContentResolver = context.getContentResolver();
}
@Override
public Attribute getMeasurement()
{
String id = android.provider.Settings.Secure.getString(mContentResolver, "android_id");
if (id != null)
{
DeviceIdAttribute attribute = new DeviceIdAttribute();
attribute.setDeviceId(id);
return attribute;
}
return null;
}
}
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
import java.util.List;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.InstalledPackagesAttribute;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
public class InstalledPackagesCollector implements Collector
{
private final PackageManager mPackageManager;
public InstalledPackagesCollector(Context context)
{
mPackageManager = context.getPackageManager();
}
@Override
public Attribute getMeasurement()
{
InstalledPackagesAttribute attribute = new InstalledPackagesAttribute();
List<PackageInfo> packages = mPackageManager.getInstalledPackages(0);
for (PackageInfo info : packages)
{
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ||
info.packageName == null || info.versionName == null)
{ /* ignore packages installed in the system image */
continue;
}
attribute.addPackage(info.packageName, info.versionName);
}
return attribute;
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.PortFilterAttribute;
public class PortFilterCollector implements Collector
{
private static Pattern LISTEN = Pattern.compile("\\bLISTEN\\b");
private static Pattern PROTOCOL = Pattern.compile("\\b(tcp|udp)6?\\b");
private static Pattern PORT = Pattern.compile("[:]{1,3}(\\d{1,5})\\b(?!\\.)");
@Override
public Attribute getMeasurement()
{
PortFilterAttribute attribute = null;
try
{
Process netstat = Runtime.getRuntime().exec("netstat -n");
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(netstat.getInputStream()));
String line;
attribute = new PortFilterAttribute();
while ((line = reader.readLine()) != null)
{
if (!LISTEN.matcher(line).find())
{
continue;
}
Matcher protocolMatcher = PROTOCOL.matcher(line);
Matcher portMatcher = PORT.matcher(line);
if (protocolMatcher.find() && portMatcher.find())
{
Protocol protocol = Protocol.fromName(protocolMatcher.group());
if (protocol == null)
{
continue;
}
int port = Integer.parseInt(portMatcher.group(1));
attribute.addPort(protocol, (short)port);
}
}
}
finally
{
netstat.destroy();
}
}
catch (IOException e)
{
e.printStackTrace();
}
return attribute;
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.ProductInformationAttribute;
public class ProductInformationCollector implements Collector
{
@Override
public Attribute getMeasurement()
{ /* this is currently hardcoded in the attribute */
return new ProductInformationAttribute();
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
public enum Protocol
{
TCP((byte)6, "tcp", "tcp6"),
UDP((byte)17, "udp", "udp6");
private final byte mValue;
private String[] mNames;
private Protocol(byte value, String... names)
{
mValue = value;
mNames = names;
}
/**
* Get the numeric value of the protocol.
* @return numeric value
*/
public byte getValue()
{
return mValue;
}
/**
* Get the protocol from the given protocol name, if found.
* @param name protocol name (e.g. "udp" or "tcp")
* @return enum entry or null
*/
public static Protocol fromName(String name)
{
for (Protocol protocol : Protocol.values())
{
for (String keyword : protocol.mNames)
{
if (keyword.equalsIgnoreCase(name))
{
return protocol;
}
}
}
return null;
}
}
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
import java.util.Locale;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.SettingsAttribute;
import android.content.ContentResolver;
import android.content.Context;
public class SettingsCollector implements Collector
{
private final ContentResolver mContentResolver;
private final String[] mSettings;
public SettingsCollector(Context context, String[] args)
{
mContentResolver = context.getContentResolver();
mSettings = args;
}
@Override
public Attribute getMeasurement()
{
if (mSettings == null || mSettings.length == 0)
{
return null;
}
SettingsAttribute attribute = new SettingsAttribute();
for (String name : mSettings)
{
String value = android.provider.Settings.Secure.getString(mContentResolver, name.toLowerCase(Locale.US));
if (value == null)
{
value = android.provider.Settings.System.getString(mContentResolver, name.toLowerCase(Locale.US));
}
if (value != null)
{
attribute.addSetting(name, value);
}
}
return attribute;
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* 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.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.StringVersionAttribute;
public class StringVersionCollector implements Collector
{
@Override
public Attribute getMeasurement()
{
StringVersionAttribute attribute = new StringVersionAttribute();
attribute.setProductVersionNumber(android.os.Build.VERSION.RELEASE);
attribute.setInternalBuildNumber(android.os.Build.DISPLAY);
return attribute;
}
}
@@ -0,0 +1,181 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.ui;
import java.util.ArrayList;
import org.strongswan.android.R;
import org.strongswan.android.logic.VpnStateService;
import org.strongswan.android.logic.VpnStateService.VpnStateListener;
import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ImcStateFragment extends Fragment implements VpnStateListener
{
private TextView mStateView;
private TextView mAction;
private LinearLayout mButton;
private VpnStateService mService;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((VpnStateService.LocalBinder)service).getService();
mService.registerListener(ImcStateFragment.this);
updateView();
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
/* bind to the service only seems to work from the ApplicationContext */
Context context = getActivity().getApplicationContext();
context.bindService(new Intent(context, VpnStateService.class),
mServiceConnection, Service.BIND_AUTO_CREATE);
/* hide it initially */
getFragmentManager().beginTransaction().hide(this).commit();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.imc_state_fragment, null);
mButton = (LinearLayout)view.findViewById(R.id.imc_state_button);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
Intent intent;
if (mService != null && !mService.getRemediationInstructions().isEmpty())
{
intent = new Intent(getActivity(), RemediationInstructionsActivity.class);
intent.putParcelableArrayListExtra(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS,
new ArrayList<RemediationInstruction>(mService.getRemediationInstructions()));
}
else
{
intent = new Intent(getActivity(), LogActivity.class);
}
startActivity(intent);
}
});
final GestureDetector gestures = new GestureDetector(getActivity(), new GestureDetector.SimpleOnGestureListener() {
/* a better value would be getScaledTouchExplorationTapSlop() but that is hidden */
private final int mMinDistance = ViewConfiguration.get(getActivity()).getScaledTouchSlop() * 4;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
if (Math.abs(e1.getX() - e2.getX()) >= mMinDistance)
{ /* only if the user swiped a minimum horizontal distance */
if (mService != null)
{
mService.setImcState(ImcState.UNKNOWN);
}
return true;
}
return false;
}
});
mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event)
{
return gestures.onTouchEvent(event);
}
});
mStateView = (TextView)view.findViewById(R.id.imc_state);
mAction = (TextView)view.findViewById(R.id.action);
return view;
}
@Override
public void onDestroy()
{
super.onDestroy();
if (mService != null)
{
mService.unregisterListener(this);
getActivity().getApplicationContext().unbindService(mServiceConnection);
}
}
@Override
public void stateChanged()
{
updateView();
}
public void updateView()
{
FragmentTransaction ft = getFragmentManager().beginTransaction();
switch (mService.getImcState())
{
case UNKNOWN:
case ALLOW:
ft.hide(this);
break;
case ISOLATE:
mStateView.setText(R.string.imc_state_isolate);
mStateView.setTextColor(getResources().getColor(R.color.warning_text));
ft.show(this);
break;
case BLOCK:
mStateView.setText(R.string.imc_state_block);
mStateView.setTextColor(getResources().getColor(R.color.error_text));
ft.show(this);
break;
}
ft.commit();
mAction.setText(mService.getRemediationInstructions().isEmpty() ? R.string.show_log
: R.string.show_remediation_instructions);
}
}
@@ -58,6 +58,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
public static final String CONTACT_EMAIL = "[email protected]";
public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE";
public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
/** Use "bring your own device" (BYOD) features */
public static final boolean USE_BYOD = true;
private static final int PREPARE_VPN_SERVICE = 0;
private static final String PROFILE_NAME = "org.strongswan.android.MainActivity.PROFILE_NAME";
private static final String PROFILE_REQUIRES_PASSWORD = "org.strongswan.android.MainActivity.REQUIRES_PASSWORD";
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.ui;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class RemediationInstructionFragment extends ListFragment
{
public static final String ARG_REMEDIATION_INSTRUCTION = "instruction";
private RemediationInstruction mInstruction = null;
private TextView mTitle;
private TextView mDescription;
private TextView mHeader;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.remediation_instruction, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null)
{
mInstruction = savedInstanceState.getParcelable(ARG_REMEDIATION_INSTRUCTION);
}
/* show dividers only between list items */
getListView().setHeaderDividersEnabled(false);
getListView().setFooterDividersEnabled(false);
/* don't show loader while adapter is not set */
setListShown(true);
mTitle = (TextView)getView().findViewById(R.id.title);
mDescription = (TextView)getView().findViewById(R.id.description);
mHeader = (TextView)getView().findViewById(R.id.list_header);
}
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelable(ARG_REMEDIATION_INSTRUCTION, mInstruction);
}
@Override
public void onStart()
{
super.onStart();
Bundle args = getArguments();
if (args != null)
{
mInstruction = args.getParcelable(ARG_REMEDIATION_INSTRUCTION);
}
updateView(mInstruction);
}
public void updateView(RemediationInstruction instruction)
{
mInstruction = instruction;
if (mInstruction != null)
{
mTitle.setText(mInstruction.getTitle());
mDescription.setText(mInstruction.getDescription());
if (mInstruction.getHeader() != null)
{
mHeader.setText(mInstruction.getHeader());
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, mInstruction.getItems()));
}
else
{
mHeader.setText("");
setListAdapter(null);
}
}
else
{
mTitle.setText("");
mDescription.setText("");
mHeader.setText("");
setListAdapter(null);
}
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.ui;
import java.util.ArrayList;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import org.strongswan.android.ui.RemediationInstructionsFragment.OnRemediationInstructionSelectedListener;
import android.app.Activity;
import android.os.Bundle;
import android.view.MenuItem;
public class RemediationInstructionsActivity extends Activity implements OnRemediationInstructionSelectedListener
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.remediation_instructions);
getActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState != null)
{ /* only update if we're not restoring */
return;
}
RemediationInstructionsFragment frag = (RemediationInstructionsFragment)getFragmentManager().findFragmentById(R.id.remediation_instructions_fragment);
if (frag != null)
{ /* two-pane layout, update fragment */
Bundle extras = getIntent().getExtras();
ArrayList<RemediationInstruction> list = extras.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS);
frag.updateView(list);
}
else
{ /* one-pane layout, create fragment */
frag = new RemediationInstructionsFragment();
frag.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(R.id.fragment_container, frag).commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
/* one-pane layout, pop possible fragment from stack, finish otherwise */
if (!getFragmentManager().popBackStackImmediate())
{
finish();
}
getActionBar().setTitle(getTitle());
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onRemediationInstructionSelected(RemediationInstruction instruction)
{
RemediationInstructionFragment frag = (RemediationInstructionFragment)getFragmentManager().findFragmentById(R.id.remediation_instruction_fragment);
if (frag != null)
{ /* two-pane layout, update directly */
frag.updateView(instruction);
}
else
{ /* one-pane layout, replace fragment */
frag = new RemediationInstructionFragment();
Bundle args = new Bundle();
args.putParcelable(RemediationInstructionFragment.ARG_REMEDIATION_INSTRUCTION, instruction);
frag.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.fragment_container, frag).addToBackStack(null).commit();
getActionBar().setTitle(instruction.getTitle());
}
}
}
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.ui;
import java.util.ArrayList;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import org.strongswan.android.ui.adapter.RemediationInstructionAdapter;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
public class RemediationInstructionsFragment extends ListFragment
{
public static final String EXTRA_REMEDIATION_INSTRUCTIONS = "instructions";
private static final String KEY_POSITION = "position";
private ArrayList<RemediationInstruction> mInstructions = null;
private OnRemediationInstructionSelectedListener mListener;
private RemediationInstructionAdapter mAdapter;
private int mCurrentPosition = -1;
/**
* The activity containing this fragment should implement this interface
*/
public interface OnRemediationInstructionSelectedListener
{
public void onRemediationInstructionSelected(RemediationInstruction instruction);
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null)
{
mInstructions = savedInstanceState.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS);
mCurrentPosition = savedInstanceState.getInt(KEY_POSITION);
}
}
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS, mInstructions);
outState.putInt(KEY_POSITION, mCurrentPosition);
}
@Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
if (activity instanceof OnRemediationInstructionSelectedListener)
{
mListener = (OnRemediationInstructionSelectedListener)activity;
}
}
@Override
public void onStart()
{
super.onStart();
boolean two_pane = getFragmentManager().findFragmentById(R.id.remediation_instruction_fragment) != null;
if (two_pane)
{ /* two-pane layout, make list items selectable */
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
Bundle args = getArguments();
if (mInstructions == null && args != null)
{
mInstructions = args.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS);
}
updateView(mInstructions);
if (two_pane && mCurrentPosition == -1 && mInstructions.size() > 0)
{ /* two-pane layout, select first instruction */
mCurrentPosition = 0;
mListener.onRemediationInstructionSelected(mInstructions.get(0));
}
getListView().setItemChecked(mCurrentPosition, true);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id)
{
mCurrentPosition = position;
mListener.onRemediationInstructionSelected(mInstructions.get(position));
getListView().setItemChecked(position, true);
}
public void updateView(ArrayList<RemediationInstruction> instructions)
{
if (mAdapter == null)
{
mAdapter = new RemediationInstructionAdapter(getActivity());
setListAdapter(mAdapter);
}
mInstructions = instructions;
mAdapter.setData(mInstructions);
}
}
@@ -28,6 +28,8 @@ import org.strongswan.android.logic.TrustedCertificateManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -36,6 +38,7 @@ import android.os.Bundle;
import android.security.KeyChain;
import android.security.KeyChainAliasCallback;
import android.security.KeyChainException;
import android.text.Html;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -73,6 +76,7 @@ public class VpnProfileDetailActivity extends Activity
private TwoLineListItem mSelectUserCert;
private CheckBox mCheckAuto;
private TwoLineListItem mSelectCert;
private TwoLineListItem mTncNotice;
@Override
public void onCreate(Bundle savedInstanceState)
@@ -90,6 +94,7 @@ public class VpnProfileDetailActivity extends Activity
mName = (EditText)findViewById(R.id.name);
mGateway = (EditText)findViewById(R.id.gateway);
mSelectVpnType = (Spinner)findViewById(R.id.vpn_type);
mTncNotice = (TwoLineListItem)findViewById(R.id.tnc_notice);
mUsernamePassword = (ViewGroup)findViewById(R.id.username_password_group);
mUsername = (EditText)findViewById(R.id.username);
@@ -117,6 +122,16 @@ public class VpnProfileDetailActivity extends Activity
}
});
mTncNotice.getText1().setText(R.string.tnc_notice_title);
mTncNotice.getText2().setText(R.string.tnc_notice_subtitle);
mTncNotice.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
new TncNoticeDialog().show(VpnProfileDetailActivity.this.getFragmentManager(), "TncNotice");
}
});
mSelectUserCert.setOnClickListener(new SelectUserCertOnClickListener());
mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@@ -225,6 +240,7 @@ public class VpnProfileDetailActivity extends Activity
{
mUsernamePassword.setVisibility(mVpnType.getRequiresUsernamePassword() ? View.VISIBLE : View.GONE);
mUserCertificate.setVisibility(mVpnType.getRequiresCertificate() ? View.VISIBLE : View.GONE);
mTncNotice.setVisibility(mVpnType.getEnableBYOD() ? View.VISIBLE : View.GONE);
if (mVpnType.getRequiresCertificate())
{
@@ -536,4 +552,25 @@ public class VpnProfileDetailActivity extends Activity
updateCredentialView();
}
}
/**
* Dialog with notification message if EAP-TNC is used.
*/
public static class TncNoticeDialog extends DialogFragment
{
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.tnc_notice_title)
.setMessage(Html.fromHtml(getString(R.string.tnc_notice_details)))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id)
{
dialog.dismiss();
}
}).create();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
@@ -17,12 +17,17 @@
package org.strongswan.android.ui;
import java.util.ArrayList;
import java.util.List;
import org.strongswan.android.R;
import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.logic.VpnStateService;
import org.strongswan.android.logic.VpnStateService.ErrorState;
import org.strongswan.android.logic.VpnStateService.State;
import org.strongswan.android.logic.VpnStateService.VpnStateListener;
import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.app.AlertDialog;
import android.app.Fragment;
@@ -45,6 +50,7 @@ import android.widget.TextView;
public class VpnStateFragment extends Fragment implements VpnStateListener
{
private static final String KEY_ERROR = "error";
private static final String KEY_IMC_STATE = "imc_state";
private static final String KEY_NAME = "name";
private TextView mProfileNameView;
@@ -56,6 +62,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
private State mState;
private AlertDialog mErrorDialog;
private ErrorState mError;
private ImcState mImcState;
private String mErrorProfileName;
private VpnStateService mService;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@@ -85,9 +92,11 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
mServiceConnection, Service.BIND_AUTO_CREATE);
mError = ErrorState.NO_ERROR;
mImcState = ImcState.UNKNOWN;
if (savedInstanceState != null && savedInstanceState.containsKey(KEY_ERROR))
{
mError = (ErrorState)savedInstanceState.getSerializable(KEY_ERROR);
mImcState = (ImcState)savedInstanceState.getSerializable(KEY_IMC_STATE);
mErrorProfileName = savedInstanceState.getString(KEY_NAME);
}
}
@@ -98,6 +107,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
super.onSaveInstanceState(outState);
outState.putSerializable(KEY_ERROR, mError);
outState.putSerializable(KEY_IMC_STATE, mImcState);
outState.putString(KEY_NAME, mErrorProfileName);
}
@@ -167,6 +177,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
{
State state = mService.getState();
ErrorState error = ErrorState.NO_ERROR;
ImcState imcState = ImcState.UNKNOWN;
String name = "", gateway = "";
if (state != State.DISABLED)
@@ -178,9 +189,10 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
gateway = profile.getGateway();
}
error = mService.getErrorState();
imcState = mService.getImcState();
}
if (reportError(name, state, error))
if (reportError(name, state, error, imcState))
{
return;
}
@@ -223,16 +235,18 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
}
}
private boolean reportError(String name, State state, ErrorState error)
private boolean reportError(String name, State state, ErrorState error, ImcState imcState)
{
if (mError != ErrorState.NO_ERROR)
{ /* we are currently reporting an error which was not yet dismissed */
error = mError;
imcState = mImcState;
name = mErrorProfileName;
}
else if (error != ErrorState.NO_ERROR && (state == State.CONNECTING || state == State.CONNECTED))
{ /* while initiating we report errors */
mError = error;
mImcState = imcState;
mErrorProfileName = name;
}
else
@@ -257,7 +271,14 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
switch (error)
{
case AUTH_FAILED:
showErrorDialog(R.string.error_auth_failed);
if (imcState == ImcState.BLOCK)
{
showErrorDialog(R.string.error_assessment_failed);
}
else
{
showErrorDialog(R.string.error_auth_failed);
}
break;
case PEER_AUTH_FAILED:
showErrorDialog(R.string.error_peer_auth_failed);
@@ -305,6 +326,13 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
}
}
private void clearError()
{
mError = ErrorState.NO_ERROR;
mImcState = ImcState.UNKNOWN;
updateView();
}
private void showConnectDialog(String profile, String gateway)
{
mProgressDialog = new ProgressDialog(getActivity());
@@ -338,32 +366,46 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
private void showErrorDialog(int textid)
{
final List<RemediationInstruction> instructions = mService.getRemediationInstructions();
final boolean show_instructions = mImcState == ImcState.BLOCK && !instructions.isEmpty();
int text = show_instructions ? R.string.show_remediation_instructions : R.string.show_log;
mErrorDialog = new AlertDialog.Builder(getActivity())
.setMessage(getString(R.string.error_introduction) + " " + getString(textid))
.setCancelable(false)
.setNeutralButton(R.string.show_log, new DialogInterface.OnClickListener() {
.setNeutralButton(text, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which)
{
clearError();
dialog.dismiss();
Intent logIntent = new Intent(getActivity(), LogActivity.class);
startActivity(logIntent);
Intent intent;
if (show_instructions)
{
intent = new Intent(getActivity(), RemediationInstructionsActivity.class);
intent.putParcelableArrayListExtra(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS,
new ArrayList<RemediationInstruction>(instructions));
}
else
{
intent = new Intent(getActivity(), LogActivity.class);
}
startActivity(intent);
}
})
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id)
{
clearError();
dialog.dismiss();
}
}).create();
mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog)
{ /* clear the error */
mError = ErrorState.NO_ERROR;
{
mErrorDialog = null;
updateView();
}
});
mErrorDialog.show();
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.ui.adapter;
import java.util.List;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class RemediationInstructionAdapter extends ArrayAdapter<RemediationInstruction>
{
public RemediationInstructionAdapter(Context context)
{
super(context, 0);
}
/**
* Set new data for this adapter.
*
* @param data the new data (null to clear)
*/
public void setData(List<RemediationInstruction> data)
{
clear();
if (data != null)
{
addAll(data);
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View view;
if (convertView != null)
{
view = convertView;
}
else
{
LayoutInflater inflater = LayoutInflater.from(getContext());
view = inflater.inflate(R.layout.remediation_instruction_item, parent, false);
}
RemediationInstruction item = getItem(position);
TextView text = (TextView)view.findViewById(android.R.id.text1);
text.setText(item.getTitle());
text = (TextView)view.findViewById(android.R.id.text2);
text.setText(item.getDescription());
return view;
}
}
@@ -0,0 +1,185 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
package org.strongswan.android.utils;
import java.nio.ByteBuffer;
/**
* Very similar to ByteBuffer (although with a stripped interface) but it
* automatically resizes the underlying buffer.
*/
public class BufferedByteWriter
{
/**
* The underlying byte buffer
*/
private byte[] mBuffer;
/**
* ByteBuffer used as wrapper around the buffer to easily convert values
*/
private ByteBuffer mWriter;
/**
* Create a writer with a default initial capacity
*/
public BufferedByteWriter()
{
this(0);
}
/**
* Create a writer with the given initial capacity (helps avoid expensive
* resizing if known).
* @param capacity initial capacity
*/
public BufferedByteWriter(int capacity)
{
capacity = capacity > 4 ? capacity : 32;
mBuffer = new byte[capacity];
mWriter = ByteBuffer.wrap(mBuffer);
}
/**
* Ensure that there is enough space available to write the requested
* number of bytes. If necessary the internal buffer is resized.
* @param required required number of bytes
*/
private void ensureCapacity(int required)
{
if (mWriter.remaining() >= required)
{
return;
}
byte[] buffer = new byte[(mBuffer.length + required) * 2];
System.arraycopy(mBuffer, 0, buffer, 0, mWriter.position());
mBuffer = buffer;
ByteBuffer writer = ByteBuffer.wrap(buffer);
writer.position(mWriter.position());
mWriter = writer;
}
/**
* Write the given byte array to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put(byte[] value)
{
ensureCapacity(value.length);
mWriter.put(value);
return this;
}
/**
* Write the given byte to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put(byte value)
{
ensureCapacity(1);
mWriter.put(value);
return this;
}
/**
* Write the 8-bit length of the given data followed by the data itself
* @param value
* @return the writer
*/
public BufferedByteWriter putLen8(byte[] value)
{
ensureCapacity(1 + value.length);
mWriter.put((byte)value.length);
mWriter.put(value);
return this;
}
/**
* Write the 16-bit length of the given data followed by the data itself
* @param value
* @return the writer
*/
public BufferedByteWriter putLen16(byte[] value)
{
ensureCapacity(2 + value.length);
mWriter.putShort((short)value.length);
mWriter.put(value);
return this;
}
/**
* Write the given short value (16-bit) in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put16(short value)
{
ensureCapacity(2);
mWriter.putShort(value);
return this;
}
/**
* Write 24-bit of the given value in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put24(int value)
{
ensureCapacity(3);
mWriter.put((byte)(value >> 16));
mWriter.putShort((short)value);
return this;
}
/**
* Write the given int value (32-bit) in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put32(int value)
{
ensureCapacity(4);
mWriter.putInt(value);
return this;
}
/**
* Write the given long value (64-bit) in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put64(long value)
{
ensureCapacity(8);
mWriter.putLong(value);
return this;
}
/**
* Convert the internal buffer to a new byte array.
* @return byte array
*/
public byte[] toByteArray()
{
int length = mWriter.position();
byte[] bytes = new byte[length];
System.arraycopy(mBuffer, 0, bytes, 0, length);
return bytes;
}
}
+31 -2
View File
@@ -186,8 +186,11 @@ endif
LOCAL_SRC_FILES += $(call add_plugin, eap-peap)
# adding libtls if any of the three plugins above is enabled
ifneq ($(or $(call plugin_enabled, eap-tls), $(call plugin_enabled, eap-ttls), $(call plugin_enabled, eap-peap)),)
LOCAL_SRC_FILES += $(call add_plugin, eap-tnc)
# adding libtls if any of the four plugins above is enabled
ifneq ($(or $(call plugin_enabled, eap-tls), $(call plugin_enabled, eap-ttls), \
$(call plugin_enabled, eap-peap), $(call plugin_enabled, eap-tnc)),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtls/
LOCAL_SRC_FILES += $(addprefix ../libtls/, \
tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \
@@ -207,6 +210,32 @@ ifneq ($(call plugin_enabled, stroke),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../stroke/
endif
LOCAL_SRC_FILES += $(call add_plugin, tnc-imc)
ifneq ($(call plugin_enabled, tnc-imc),)
LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_SRC_FILES += $(call add_plugin, tnc-tnccs)
LOCAL_SRC_FILES += $(call add_plugin, tnccs-20)
LOCAL_SRC_FILES += $(call add_plugin_subdirs, tnccs-20, batch messages state_machine)
ifneq ($(call plugin_enabled, tnccs-20),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/plugins/tnccs_20/
# for tls.h
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtls/
endif
ifneq ($(or $(call plugin_enabled, eap-tnc), $(call plugin_enabled, tnc-imc), \
$(call plugin_enabled, tnc-tnccs), $(call plugin_enabled, tnccs-20)),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtnccs/
LOCAL_SHARED_LIBRARIES += libtnccs
endif
ifneq ($(or $(call plugin_enabled, tnc-imc), $(call plugin_enabled, tnc-tnccs), \
$(call plugin_enabled, tnccs-20)),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtncif/
LOCAL_SHARED_LIBRARIES += libtncif
endif
# build libcharon --------------------------------------------------------------
@@ -782,7 +782,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
enumerator = enumerator_create_token(message, " ", " ");
while (enumerator->enumerate(enumerator, &token))
{
if (strneq(token, "S=", 2))
if (strpfx(token, "S="))
{
chunk_t hex;
token += 2;
@@ -795,7 +795,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
hex = chunk_create(token, AUTH_RESPONSE_LEN - 2);
auth_string = chunk_from_hex(hex, NULL);
}
else if (strneq(token, "M=", 2))
else if (strpfx(token, "M="))
{
token += 2;
msg = strdup(token);
@@ -864,16 +864,16 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
enumerator = enumerator_create_token(message, " ", " ");
while (enumerator->enumerate(enumerator, &token))
{
if (strneq(token, "E=", 2))
if (strpfx(token, "E="))
{
token += 2;
error = atoi(token);
}
else if (strneq(token, "R=", 2))
else if (strpfx(token, "R="))
{
/* ignore retriable */
}
else if (strneq(token, "C=", 2))
else if (strpfx(token, "C="))
{
chunk_t hex;
token += 2;
@@ -886,11 +886,11 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
hex = chunk_create(token, 2 * CHALLENGE_LEN);
challenge = chunk_from_hex(hex, NULL);
}
else if (strneq(token, "V=", 2))
else if (strpfx(token, "V="))
{
/* ignore version */
}
else if (strneq(token, "M=", 2))
else if (strpfx(token, "M="))
{
token += 2;
msg = strdup(token);
@@ -355,7 +355,7 @@ static void generate_auth_cfg(private_load_tester_config_t *this, char *str,
}
}
}
else if (strneq(str, "eap", strlen("eap")))
else if (strpfx(str, "eap"))
{ /* EAP authentication, use a NAI */
class = AUTH_CLASS_EAP;
if (*(str + strlen("eap")) == '-')
+5 -5
View File
@@ -559,9 +559,9 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
}
/* authentication metod (class, actually) */
if (strneq(auth, "pubkey", strlen("pubkey")) ||
strneq(auth, "rsa", strlen("rsa")) ||
strneq(auth, "ecdsa", strlen("ecdsa")))
if (strpfx(auth, "pubkey") ||
strpfx(auth, "rsa") ||
strpfx(auth, "ecdsa"))
{
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
build_crl_policy(cfg, local, msg->add_conn.crl_policy);
@@ -572,7 +572,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
{
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
}
else if (strneq(auth, "xauth", 5))
else if (strpfx(auth, "xauth"))
{
char *pos;
@@ -588,7 +588,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
identification_create_from_string(msg->add_conn.xauth_identity));
}
}
else if (strneq(auth, "eap", 3))
else if (strpfx(auth, "eap"))
{
eap_vendor_type_t *type;
+6 -7
View File
@@ -175,7 +175,7 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
certificate_t *cert = NULL;
char path[PATH_MAX];
if (strneq(filename, "%smartcard", strlen("%smartcard")))
if (strpfx(filename, "%smartcard"))
{
smartcard_format_t format;
char module[SC_PART_LEN], keyid[SC_PART_LEN];
@@ -239,7 +239,7 @@ METHOD(stroke_cred_t, load_peer, certificate_t*,
certificate_t *cert = NULL;
char path[PATH_MAX];
if (strneq(filename, "%smartcard", strlen("%smartcard")))
if (strpfx(filename, "%smartcard"))
{
smartcard_format_t format;
char module[SC_PART_LEN], keyid[SC_PART_LEN];
@@ -787,7 +787,7 @@ static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
}
chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{
free(secret.ptr);
if (!prompt)
@@ -880,7 +880,7 @@ static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
return FALSE;
}
}
if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{
callback_cred_t *cb;
passphrase_cb_data_t pp_data = {
@@ -1142,8 +1142,7 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
{
continue;
}
if (line.len > strlen("include ") &&
strneq(line.ptr, "include ", strlen("include ")))
if (line.len > strlen("include ") && strpfx(line.ptr, "include "))
{
char **expanded, *dir, pattern[PATH_MAX];
u_char *pos;
@@ -1211,7 +1210,7 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
continue;
}
if (line.len > 2 && strneq(": ", line.ptr, 2))
if (line.len > 2 && strpfx(line.ptr, ": "))
{
/* no ids, skip the ':' */
ids = chunk_empty;
@@ -78,7 +78,7 @@
/** this is the default number of ipsec devices */
#define DEFAULT_IPSEC_DEV_COUNT 4
/** TRUE if the given name matches an ipsec device */
#define IS_IPSEC_DEV(name) (strneq((name), IPSEC_DEV_PREFIX, sizeof(IPSEC_DEV_PREFIX) - 1))
#define IS_IPSEC_DEV(name) (strpfx((name), IPSEC_DEV_PREFIX))
/** the following stuff is from ipsec_tunnel.h */
struct ipsectunnelconf
@@ -2332,7 +2332,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
while (fgets(line, sizeof(line), file))
{
if (strneq(line, said, strlen(said)))
if (strpfx(line, said))
{
/* fine we found the correct line, now find the idle time */
u_int32_t idle_time;
@@ -126,7 +126,7 @@ static void remove_nameserver(private_resolve_handler_t *this,
/* copy all, but matching line */
while (fgets(line, sizeof(line), in))
{
if (strneq(line, matcher, strlen(matcher)))
if (strpfx(line, matcher))
{
DBG1(DBG_IKE, "removing DNS server %H from %s",
addr, this->file);
+65
View File
@@ -0,0 +1,65 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# copy-n-paste from Makefile.am
libimcv_la_SOURCES := \
imcv.h imcv.c \
imc/imc_agent.h imc/imc_agent.c imc/imc_state.h \
imc/imc_msg.h imc/imc_msg.c \
imv/imv_agent.h imv/imv_agent.c imv/imv_state.h \
imv/imv_agent_if.h imv/imv_if.h \
imv/imv_database.h imv/imv_database.c \
imv/imv_msg.h imv/imv_msg.c \
imv/imv_lang_string.h imv/imv_lang_string.c \
imv/imv_reason_string.h imv/imv_reason_string.c \
imv/imv_remediation_string.h imv/imv_remediation_string.c \
imv/imv_session.h imv/imv_session.c \
imv/imv_workitem.h imv/imv_workitem.c \
imv/tables.sql imv/data.sql \
ietf/ietf_attr.h ietf/ietf_attr.c \
ietf/ietf_attr_assess_result.h ietf/ietf_attr_assess_result.c \
ietf/ietf_attr_attr_request.h ietf/ietf_attr_attr_request.c \
ietf/ietf_attr_fwd_enabled.h ietf/ietf_attr_fwd_enabled.c \
ietf/ietf_attr_default_pwd_enabled.h ietf/ietf_attr_default_pwd_enabled.c \
ietf/ietf_attr_installed_packages.h ietf/ietf_attr_installed_packages.c \
ietf/ietf_attr_numeric_version.h ietf/ietf_attr_numeric_version.c \
ietf/ietf_attr_op_status.h ietf/ietf_attr_op_status.c \
ietf/ietf_attr_pa_tnc_error.h ietf/ietf_attr_pa_tnc_error.c \
ietf/ietf_attr_port_filter.h ietf/ietf_attr_port_filter.c \
ietf/ietf_attr_product_info.h ietf/ietf_attr_product_info.c \
ietf/ietf_attr_remediation_instr.h ietf/ietf_attr_remediation_instr.c \
ietf/ietf_attr_string_version.h ietf/ietf_attr_string_version.c \
ita/ita_attr.h ita/ita_attr.c \
ita/ita_attr_command.h ita/ita_attr_command.c \
ita/ita_attr_dummy.h ita/ita_attr_dummy.c \
ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
ita/ita_attr_settings.h ita/ita_attr_settings.c \
ita/ita_attr_angel.h ita/ita_attr_angel.c \
ita/ita_attr_device_id.h ita/ita_attr_device_id.c \
os_info/os_info.h os_info/os_info.c \
pa_tnc/pa_tnc_attr.h \
pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c
LOCAL_SRC_FILES := $(filter %.c,$(libimcv_la_SOURCES))
# build libimcv ----------------------------------------------------------------
LOCAL_C_INCLUDES += \
$(libvstr_PATH) \
$(strongswan_PATH)/src/libtncif \
$(strongswan_PATH)/src/libstrongswan
LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libimcv
LOCAL_MODULE_TAGS := optional
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES += libstrongswan libtncif
include $(BUILD_SHARED_LIBRARY)
+1
View File
@@ -174,6 +174,7 @@ void libimcv_deinit(void)
imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF);
imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA);
DESTROY_IF(imcv_pa_tnc_attributes);
imcv_pa_tnc_attributes = NULL;
DESTROY_IF(imcv_db);
DBG1(DBG_LIB, "libimcv terminated");
}
+2 -2
View File
@@ -182,8 +182,8 @@ METHOD(os_info_t, get_setting, chunk_t,
size_t i = 0;
chunk_t value;
if (!strneq(name, "/etc/", 5) && !strneq(name, "/proc/", 6) &&
!strneq(name, "/sys/", 5) && !strneq(name, "/var/", 5))
if (!strpfx(name, "/etc/") && !strpfx(name, "/proc/") &&
!strpfx(name, "/sys/") && !strpfx(name, "/var/"))
{
/**
* In order to guarantee privacy, only settings from the
@@ -282,7 +282,10 @@ METHOD(imv_state_t, get_reason_string, bool,
/* Instantiate a TNC Reason String object */
DESTROY_IF(this->reason_string);
this->reason_string = imv_reason_string_create(*reason_language);
this->reason_string->add_reason(this->reason_string, reasons);
if (this->rec != TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
{
this->reason_string->add_reason(this->reason_string, reasons);
}
*reason_string = this->reason_string->get_encoding(this->reason_string);
return TRUE;
+70
View File
@@ -0,0 +1,70 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# copy-n-paste from Makefile.am
libpts_la_SOURCES := \
libpts.h libpts.c \
pts/pts.h pts/pts.c \
pts/pts_error.h pts/pts_error.c \
pts/pts_pcr.h pts/pts_pcr.c \
pts/pts_proto_caps.h \
pts/pts_req_func_comp_evid.h \
pts/pts_simple_evid_final.h \
pts/pts_creds.h pts/pts_creds.c \
pts/pts_database.h pts/pts_database.c \
pts/pts_dh_group.h pts/pts_dh_group.c \
pts/pts_file_meas.h pts/pts_file_meas.c \
pts/pts_file_meta.h pts/pts_file_meta.c \
pts/pts_file_type.h pts/pts_file_type.c \
pts/pts_meas_algo.h pts/pts_meas_algo.c \
pts/components/pts_component.h \
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \
pts/components/pts_comp_func_name.h pts/components/pts_comp_func_name.c \
pts/components/ita/ita_comp_func_name.h pts/components/ita/ita_comp_func_name.c \
pts/components/ita/ita_comp_ima.h pts/components/ita/ita_comp_ima.c \
pts/components/ita/ita_comp_tboot.h pts/components/ita/ita_comp_tboot.c \
pts/components/ita/ita_comp_tgrub.h pts/components/ita/ita_comp_tgrub.c \
pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
tcg/tcg_attr.h tcg/tcg_attr.c \
tcg/tcg_pts_attr_proto_caps.h tcg/tcg_pts_attr_proto_caps.c \
tcg/tcg_pts_attr_dh_nonce_params_req.h tcg/tcg_pts_attr_dh_nonce_params_req.c \
tcg/tcg_pts_attr_dh_nonce_params_resp.h tcg/tcg_pts_attr_dh_nonce_params_resp.c \
tcg/tcg_pts_attr_dh_nonce_finish.h tcg/tcg_pts_attr_dh_nonce_finish.c \
tcg/tcg_pts_attr_meas_algo.h tcg/tcg_pts_attr_meas_algo.c \
tcg/tcg_pts_attr_get_tpm_version_info.h tcg/tcg_pts_attr_get_tpm_version_info.c \
tcg/tcg_pts_attr_tpm_version_info.h tcg/tcg_pts_attr_tpm_version_info.c \
tcg/tcg_pts_attr_get_aik.h tcg/tcg_pts_attr_get_aik.c \
tcg/tcg_pts_attr_aik.h tcg/tcg_pts_attr_aik.c \
tcg/tcg_pts_attr_req_func_comp_evid.h tcg/tcg_pts_attr_req_func_comp_evid.c \
tcg/tcg_pts_attr_gen_attest_evid.h tcg/tcg_pts_attr_gen_attest_evid.c \
tcg/tcg_pts_attr_simple_comp_evid.h tcg/tcg_pts_attr_simple_comp_evid.c \
tcg/tcg_pts_attr_simple_evid_final.h tcg/tcg_pts_attr_simple_evid_final.c \
tcg/tcg_pts_attr_req_file_meas.h tcg/tcg_pts_attr_req_file_meas.c \
tcg/tcg_pts_attr_file_meas.h tcg/tcg_pts_attr_file_meas.c \
tcg/tcg_pts_attr_req_file_meta.h tcg/tcg_pts_attr_req_file_meta.c \
tcg/tcg_pts_attr_unix_file_meta.h tcg/tcg_pts_attr_unix_file_meta.c
LOCAL_SRC_FILES := $(filter %.c,$(libpts_la_SOURCES))
# build libpts -----------------------------------------------------------------
LOCAL_C_INCLUDES += \
$(libvstr_PATH) \
$(strongswan_PATH)/src/libtncif \
$(strongswan_PATH)/src/libimcv \
$(strongswan_PATH)/src/libstrongswan
LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libpts
LOCAL_MODULE_TAGS := optional
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES += libstrongswan libimcv
include $(BUILD_SHARED_LIBRARY)
+2 -16
View File
@@ -302,20 +302,7 @@ pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id,
return NULL;
}
measurement = chunk_create(hash, hasher->get_hash_size(hasher));
INIT(this,
.public = {
.get_request_id = _get_request_id,
.get_file_count = _get_file_count,
.add = _add,
.create_enumerator = _create_enumerator,
.check = _check,
.verify = _verify,
.destroy = _destroy,
},
.request_id = request_id,
.list = linked_list_create(),
);
this = (private_pts_file_meas_t*)pts_file_meas_create(request_id);
if (is_dir)
{
@@ -338,8 +325,7 @@ pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id,
{
if (!hash_file(hasher, abs_name, hash))
{
success = FALSE;
break;
continue;
}
filename = use_rel_name ? rel_name : abs_name;
DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
@@ -112,7 +112,7 @@ METHOD(fetcher_t, fetch, status_t,
status_t status = FAILED;
chunk_t *result = userdata;
if (!strneq(url, "ldap", 4))
if (!strpfx(url, "ldap"))
{
return NOT_SUPPORTED;
}
@@ -666,7 +666,7 @@ mysql_database_t *mysql_database_create(char *uri)
conn_t *conn;
private_mysql_database_t *this;
if (!strneq(uri, "mysql://", 8))
if (!strpfx(uri, "mysql://"))
{
return NULL;
}
@@ -319,7 +319,7 @@ sqlite_database_t *sqlite_database_create(char *uri)
/**
* parse sqlite:///path/to/file.db uri
*/
if (!strneq(uri, "sqlite://", 9))
if (!strpfx(uri, "sqlite://"))
{
return NULL;
}
@@ -85,7 +85,7 @@ static sshkey_public_key_t *parse_public_key(chunk_t blob)
BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
}
else if (format.len > strlen(ECDSA_PREFIX) &&
strneq(format.ptr, ECDSA_PREFIX, strlen(ECDSA_PREFIX)))
strpfx(format.ptr, ECDSA_PREFIX))
{
chunk_t ec_blob, identifier, q, oid, encoded;
sshkey_public_key_t *key;
+23 -6
View File
@@ -81,9 +81,20 @@ static inline bool streq(const char *x, const char *y)
}
/**
* Macro compares two strings for equality, length limited
* Helper function that compares two strings for equality, length limited
*/
#define strneq(x,y,len) (strncmp(x, y, len) == 0)
static inline bool strneq(const char *x, const char *y, size_t len)
{
return strncmp(x, y, len) == 0;
}
/**
* Helper function that checks if a string starts with a given prefix
*/
static inline bool strpfx(const char *x, const char *prefix)
{
return strneq(x, prefix, strlen(prefix));
}
/**
* Helper function that compares two strings for equality ignoring case
@@ -94,9 +105,12 @@ static inline bool strcaseeq(const char *x, const char *y)
}
/**
* Macro compares two strings for equality ignoring case, length limited
* Helper function that compares two strings for equality ignoring case, length limited
*/
#define strncaseeq(x,y,len) (strncasecmp(x, y, len) == 0)
static inline bool strncaseeq(const char *x, const char *y, size_t len)
{
return strncasecmp(x, y, len) == 0;
}
/**
* NULL-safe strdup variant
@@ -107,9 +121,12 @@ static inline char *strdupnull(const char *s)
}
/**
* Macro compares two binary blobs for equality
* Helper function that compares two binary blobs for equality
*/
#define memeq(x,y,len) (memcmp(x, y, len) == 0)
static inline bool memeq(const void *x, const void *y, size_t len)
{
return memcmp(x, y, len) == 0;
}
/**
* Macro gives back larger of two values.
+5
View File
@@ -100,6 +100,11 @@ static bool load_imcvs_from_config(char *filename, bool is_imc)
void *addr;
char *label;
if (!filename || !*filename)
{
return TRUE;
}
label = is_imc ? "IMC" : "IMV";
DBG1(DBG_TNC, "loading %ss from '%s'", label, filename);