Merge branch 'charon-xpc'

Implement a charon daemon controlled by the Apple specific XPC mechanism,
acting as a backend for a yet to build unprivileged GUI. The keychain plugin
coming with this merge provides certificates from the OS X keychain service.
This commit is contained in:
Martin Willi 2013-07-18 12:18:32 +02:00
commit 569d114de8
25 changed files with 2358 additions and 40 deletions

View File

@ -218,6 +218,7 @@ ARG_ENABL_SET([padlock], [enables VIA Padlock crypto plugin.])
ARG_ENABL_SET([openssl], [enables the OpenSSL crypto plugin.])
ARG_ENABL_SET([gcrypt], [enables the libgcrypt plugin.])
ARG_ENABL_SET([agent], [enables the ssh-agent signing plugin.])
ARG_ENABL_SET([keychain], [enables OS X Keychain Services credential set.])
ARG_ENABL_SET([pkcs11], [enables the PKCS11 token support plugin.])
ARG_ENABL_SET([ctr], [enables the Counter Mode wrapper crypto plugin.])
ARG_ENABL_SET([ccm], [enables the CCM AEAD wrapper crypto plugin.])
@ -1012,6 +1013,7 @@ ADD_PLUGIN([af-alg], [s charon openac scepclient pki scripts medsr
ADD_PLUGIN([fips-prf], [s charon nm cmd])
ADD_PLUGIN([gmp], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([agent], [s charon nm cmd])
ADD_PLUGIN([keychain], [s charon cmd])
ADD_PLUGIN([xcbc], [s charon nm cmd])
ADD_PLUGIN([cmac], [s charon nm cmd])
ADD_PLUGIN([hmac], [s charon scripts nm cmd])
@ -1148,6 +1150,7 @@ AM_CONDITIONAL(USE_PADLOCK, test x$padlock = xtrue)
AM_CONDITIONAL(USE_OPENSSL, test x$openssl = xtrue)
AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue)
AM_CONDITIONAL(USE_AGENT, test x$agent = xtrue)
AM_CONDITIONAL(USE_KEYCHAIN, test x$keychain = xtrue)
AM_CONDITIONAL(USE_PKCS11, test x$pkcs11 = xtrue)
AM_CONDITIONAL(USE_CTR, test x$ctr = xtrue)
AM_CONDITIONAL(USE_CCM, test x$ccm = xtrue)
@ -1349,6 +1352,7 @@ AC_CONFIG_FILES([
src/libstrongswan/plugins/openssl/Makefile
src/libstrongswan/plugins/gcrypt/Makefile
src/libstrongswan/plugins/agent/Makefile
src/libstrongswan/plugins/keychain/Makefile
src/libstrongswan/plugins/pkcs11/Makefile
src/libstrongswan/plugins/ctr/Makefile
src/libstrongswan/plugins/ccm/Makefile

2
src/frontends/osx/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
xcuserdata
*.xcworkspace

View File

@ -0,0 +1,98 @@
# strongSwan OS X App #
## Introduction ##
The strongSwan OS X App consists of two components:
* A frontend to configure and control connections
* A privileged helper daemon, controlled using XPC, called charon-xpc
The privileged helper daemon gets installed automatically using SMJobBless
functionality on its first use, and gets started automatically by Launchd when
needed.
charon-xpc is a special build linking statically against strongSwan components.
## Building strongSwan ##
strongSwan on OS X requires the libvstr library. The simplest way to install
it is using MacPorts. It gets statically linked to charon-xpc, hence it is not
needed to run the built App.
Before building the Xcode project, the strongSwan base tree must be built using
a monolithic and static build. This can be achieved on OS X by using:
LDFLAGS="-all_load -L/opt/local/lib" \
CFLAGS="-idirafter /opt/local/include -O2 -Wall -Wno-format -Wno-pointer-sign" \
./configure --enable-monolithic --disable-shared --enable-static \
--disable-defaults \
--enable-openssl --enable-kernel-pfkey --enable-kernel-pfroute \
--enable-eap-mschapv2 --enable-eap-identity --enable-nonce \
--enable-random --enable-pkcs1 --enable-pem --enable-socket-default \
--enable-xauth-generic --enable-keychain --enable-charon \
--enable-ikev1 --enable-ikev2
followed by calling make (no need to make install).
Building charon-xpc using the Xcode project yields a single binary without
any non OS X dependencies.
Both charon-xpc and the App must be code-signed to allow the installation of
the privileged helper. git-grep for "Joe Developer" to change the signing
identity.
## XPC application protocol ##
charon-xpc provides a Mach service under the name _org.strongswan.charon-xpc_.
Clients can connect to this service to control the daemon. All messages
on all connections use the following string dictionary keys/values:
* _type_: XPC message type, currently either
* _rpc_ for a remote procedure call, expects a response
* _event_ for application specific event messages
* _rpc_: defines the name of the RPC function to call (for _type_ = _rpc_)
* _event_: defines a name for the event (for _type_ = _event_)
Additional arguments and return values are specified by the call and can have
any type. Keys are directly attached to the message dictionary.
On the Mach service connection, the following RPC messages are currently
defined:
* string version = get_version()
* _version_: strongSwan version of charon-xpc
* bool success = start_connection(string name, string host, string id,
endpoint channel)
* _success_: TRUE if initiation started successfully
* _name_: connection name to initiate
* _host_: server hostname (and identity)
* _id_: client identity to use
* _channel_: XPC endpoint for this connection
The start_connection() RPC returns just after the initation of the call and
does not wait for the connection to establish. Nonetheless does it have a
return value to indicate if connection initiation could be triggered.
The App passes an (anonymous) XPC endpoint to start_connection(). If the call
succeeds, charon-xpc connects to this endpoint to establish a channel used for
this specific IKE connection.
On this channel, the following RPC calls are currently defined from charon-xpc
to the App:
* string password = get_password(string username)
* _password_: user password returned
* _username_: username to query a password for
And the following from the App to charon-xpc:
* bool success = stop_connection()
* _success_: TRUE if termination of connection initiated
The following events are currently defined from charon-xpc to the App:
* up(): IKE_SA has been established
* down(): IKE_SA has been closed or failed to establish
* child_up(string local_ts, string remote_ts): CHILD_SA has been established
* child_down(string local_ts, string remote_ts): CHILD_SA has been closed
* log(string message): debug log message for this connection

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>org.strongswan.charon-xpc</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>charon-xpc</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>SMAuthorizedClients</key>
<array>
<string>identifier org.strongswan.osx and certificate leaf[subject.CN] = "Joe Developer"</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.strongswan.charon-xpc</string>
<key>MachServices</key>
<dict>
<key>org.strongswan.charon-xpc</key>
<true/>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,207 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <sys/types.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <library.h>
#include <hydra.h>
#include <daemon.h>
#include <threading/thread.h>
#include <utils/backtrace.h>
#include "xpc_dispatch.h"
/**
* XPC dispatcher class
*/
static xpc_dispatch_t *dispatcher;
/**
* atexit() cleanup for dispatcher
*/
void dispatcher_cleanup()
{
DESTROY_IF(dispatcher);
}
/**
* Loglevel configuration
*/
static level_t levels[DBG_MAX];
/**
* hook in library for debugging messages
*/
extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
/**
* Logging hook for library logs, using stderr output
*/
static void dbg_stderr(debug_t group, level_t level, char *fmt, ...)
{
va_list args;
if (level <= 1)
{
va_start(args, fmt);
fprintf(stderr, "00[%N] ", debug_names, group);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
}
/**
* Run the daemon and handle unix signals
*/
static int run()
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGTERM);
sigprocmask(SIG_BLOCK, &set, NULL);
while (TRUE)
{
int sig;
if (sigwait(&set, &sig))
{
DBG1(DBG_DMN, "error while waiting for a signal");
return 1;
}
switch (sig)
{
case SIGINT:
DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
return 0;
case SIGTERM:
DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
return 0;
default:
DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
break;
}
}
}
/**
* Handle SIGSEGV/SIGILL signals raised by threads
*/
static void segv_handler(int signal)
{
backtrace_t *backtrace;
DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
backtrace = backtrace_create(2);
backtrace->log(backtrace, NULL, TRUE);
backtrace->destroy(backtrace);
DBG1(DBG_DMN, "killing ourself, received critical signal");
abort();
}
/**
* Main function, starts the daemon.
*/
int main(int argc, char *argv[])
{
struct sigaction action;
struct utsname utsname;
int group;
dbg = dbg_stderr;
atexit(library_deinit);
if (!library_init(NULL))
{
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
}
if (lib->integrity)
{
if (!lib->integrity->check_file(lib->integrity, "charon-xpc", argv[0]))
{
exit(SS_RC_DAEMON_INTEGRITY);
}
}
atexit(libhydra_deinit);
if (!libhydra_init("charon-xpc"))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
atexit(libcharon_deinit);
if (!libcharon_init("charon-xpc"))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
for (group = 0; group < DBG_MAX; group++)
{
levels[group] = LEVEL_CTRL;
}
charon->load_loggers(charon, levels, TRUE);
lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0");
lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0");
lib->settings->set_default_str(lib->settings,
"charon-cmd.close_ike_on_child_failure", "yes");
if (!charon->initialize(charon,
lib->settings->get_str(lib->settings, "charon-xpc.load",
"random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute "
"keychain socket-default eap-identity eap-mschapv2 osx-attr")))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
if (uname(&utsname) != 0)
{
memset(&utsname, 0, sizeof(utsname));
}
DBG1(DBG_DMN, "Starting charon-xpc IKE daemon (strongSwan %s, %s %s, %s)",
VERSION, utsname.sysname, utsname.release, utsname.machine);
/* add handler for SEGV and ILL,
* INT, TERM and HUP are handled by sigwait() in run() */
action.sa_handler = segv_handler;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGINT);
sigaddset(&action.sa_mask, SIGTERM);
sigaddset(&action.sa_mask, SIGHUP);
sigaction(SIGSEGV, &action, NULL);
sigaction(SIGILL, &action, NULL);
sigaction(SIGBUS, &action, NULL);
action.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &action, NULL);
pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
dispatcher = xpc_dispatch_create();
if (!dispatcher)
{
exit(SS_RC_INITIALIZATION_FAILED);
}
atexit(dispatcher_cleanup);
charon->start(charon);
return run();
}

View File

@ -0,0 +1,540 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "xpc_channels.h"
#include "xpc_logger.h"
#include <credentials/sets/callback_cred.h>
#include <collections/hashtable.h>
#include <threading/rwlock.h>
#include <daemon.h>
typedef struct private_xpc_channels_t private_xpc_channels_t;
/**
* Private data of an xpc_channels_t object.
*/
struct private_xpc_channels_t {
/**
* Public xpc_channels_t interface.
*/
xpc_channels_t public;
/**
* Registered channels, IKE_SA unique ID => entry_t
*/
hashtable_t *channels;
/**
* Lock for channels list
*/
rwlock_t *lock;
/**
* Callback credential set for passwords
*/
callback_cred_t *creds;
};
/**
* Channel entry
*/
typedef struct {
/* XPC channel to App */
xpc_connection_t conn;
/* associated IKE_SA unique identifier */
uintptr_t sa;
/* did we already ask for a password? */
bool passworded;
/* channel specific logger */
xpc_logger_t *logger;
} entry_t;
/**
* Clean up an entry, cancelling connection
*/
static void destroy_entry(entry_t *entry)
{
charon->bus->remove_logger(charon->bus, &entry->logger->logger);
entry->logger->destroy(entry->logger);
xpc_connection_suspend(entry->conn);
xpc_release(entry->conn);
free(entry);
}
/**
* Find an IKE_SA unique identifier by a given XPC channel
*/
static u_int32_t find_ike_sa_by_conn(private_xpc_channels_t *this,
xpc_connection_t conn)
{
enumerator_t *enumerator;
entry_t *entry;
u_int32_t ike_sa = 0;
this->lock->read_lock(this->lock);
enumerator = this->channels->create_enumerator(this->channels);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
if (entry->conn == conn)
{
ike_sa = entry->sa;
break;
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
return ike_sa;
}
/**
* Remove an entry for a given XPC connection
*/
static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn)
{
uintptr_t ike_sa;
entry_t *entry;
ike_sa = find_ike_sa_by_conn(this, conn);
if (ike_sa)
{
this->lock->write_lock(this->lock);
entry = this->channels->remove(this->channels, (void*)ike_sa);
this->lock->unlock(this->lock);
if (entry)
{
destroy_entry(entry);
}
}
}
/**
* Trigger termination of a connection
*/
static void stop_connection(private_xpc_channels_t *this, u_int32_t ike_sa,
xpc_object_t request, xpc_object_t reply)
{
status_t status;
status = charon->controller->terminate_ike(charon->controller, ike_sa,
NULL, NULL, 0);
xpc_dictionary_set_bool(reply, "success", status != NOT_FOUND);
}
/**
* XPC RPC command dispatch table
*/
static struct {
char *name;
void (*handler)(private_xpc_channels_t *this, u_int32_t ike_sa,
xpc_object_t request, xpc_object_t reply);
} commands[] = {
{ "stop_connection", stop_connection },
};
/**
* Handle a request message from App
*/
static void handle(private_xpc_channels_t *this, xpc_connection_t conn,
xpc_object_t request)
{
xpc_object_t reply;
const char *type, *rpc;
bool found = FALSE;
u_int32_t ike_sa;
int i;
type = xpc_dictionary_get_string(request, "type");
if (type)
{
if (streq(type, "rpc"))
{
reply = xpc_dictionary_create_reply(request);
rpc = xpc_dictionary_get_string(request, "rpc");
ike_sa = find_ike_sa_by_conn(this, conn);
if (reply && rpc && ike_sa)
{
for (i = 0; i < countof(commands); i++)
{
if (streq(commands[i].name, rpc))
{
found = TRUE;
commands[i].handler(this, ike_sa, request, reply);
break;
}
}
}
if (!found)
{
DBG1(DBG_CFG, "received invalid XPC rpc command: %s", rpc);
}
if (reply)
{
xpc_connection_send_message(conn, reply);
xpc_release(reply);
}
}
else
{
DBG1(DBG_CFG, "received unknown XPC message type: %s", type);
}
}
else
{
DBG1(DBG_CFG, "received XPC message without a type");
}
}
METHOD(xpc_channels_t, add, void,
private_xpc_channels_t *this, xpc_connection_t conn, u_int32_t ike_sa)
{
entry_t *entry;
INIT(entry,
.conn = conn,
.sa = ike_sa,
.logger = xpc_logger_create(conn),
);
xpc_connection_set_event_handler(entry->conn, ^(xpc_object_t event)
{
if (event == XPC_ERROR_CONNECTION_INVALID ||
event == XPC_ERROR_CONNECTION_INTERRUPTED)
{
remove_conn(this, conn);
}
else if (xpc_get_type(event) == XPC_TYPE_DICTIONARY)
{
handle(this, conn, event);
}
});
entry->logger->set_ike_sa(entry->logger, entry->sa);
charon->bus->add_logger(charon->bus, &entry->logger->logger);
this->lock->write_lock(this->lock);
this->channels->put(this->channels, (void*)entry->sa, entry);
this->lock->unlock(this->lock);
xpc_connection_resume(conn);
}
METHOD(listener_t, alert, bool,
private_xpc_channels_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
{
const char *desc;
switch (alert)
{
case ALERT_LOCAL_AUTH_FAILED:
desc = "local-auth";
break;
case ALERT_PEER_AUTH_FAILED:
desc = "remote-auth";
break;
case ALERT_PEER_ADDR_FAILED:
desc = "dns";
break;
case ALERT_PEER_INIT_UNREACHABLE:
desc = "unreachable";
break;
case ALERT_RETRANSMIT_SEND_TIMEOUT:
desc = "timeout";
break;
case ALERT_PROPOSAL_MISMATCH_IKE:
case ALERT_PROPOSAL_MISMATCH_CHILD:
desc = "proposal-mismatch";
break;
case ALERT_TS_MISMATCH:
desc = "ts-mismatch";
break;
default:
return TRUE;
}
if (ike_sa)
{
entry_t *entry;
uintptr_t sa;
sa = ike_sa->get_unique_id(ike_sa);
this->lock->read_lock(this->lock);
entry = this->channels->get(this->channels, (void*)sa);
if (entry)
{
xpc_object_t msg;
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "type", "event");
xpc_dictionary_set_string(msg, "event", "alert");
xpc_dictionary_set_string(msg, "alert", desc);
xpc_connection_send_message(entry->conn, msg);
xpc_release(msg);
}
this->lock->unlock(this->lock);
}
return TRUE;
}
METHOD(listener_t, ike_rekey, bool,
private_xpc_channels_t *this, ike_sa_t *old, ike_sa_t *new)
{
entry_t *entry;
uintptr_t sa;
sa = old->get_unique_id(old);
this->lock->write_lock(this->lock);
entry = this->channels->remove(this->channels, (void*)sa);
if (entry)
{
entry->sa = new->get_unique_id(new);
entry->logger->set_ike_sa(entry->logger, entry->sa);
this->channels->put(this->channels, (void*)entry->sa, entry);
}
this->lock->unlock(this->lock);
return TRUE;
}
METHOD(listener_t, ike_state_change, bool,
private_xpc_channels_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
{
if (state == IKE_CONNECTING)
{
entry_t *entry;
uintptr_t sa;
sa = ike_sa->get_unique_id(ike_sa);
this->lock->read_lock(this->lock);
entry = this->channels->get(this->channels, (void*)sa);
if (entry)
{
xpc_object_t msg;
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "type", "event");
xpc_dictionary_set_string(msg, "event", "connecting");
xpc_connection_send_message(entry->conn, msg);
xpc_release(msg);
}
this->lock->unlock(this->lock);
}
return TRUE;
}
METHOD(listener_t, child_updown, bool,
private_xpc_channels_t *this, ike_sa_t *ike_sa,
child_sa_t *child_sa, bool up)
{
entry_t *entry;
uintptr_t sa;
sa = ike_sa->get_unique_id(ike_sa);
this->lock->read_lock(this->lock);
entry = this->channels->get(this->channels, (void*)sa);
if (entry)
{
xpc_object_t msg;
linked_list_t *list;
char buf[256];
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "type", "event");
if (up)
{
xpc_dictionary_set_string(msg, "event", "child_up");
}
else
{
xpc_dictionary_set_string(msg, "event", "child_down");
}
list = child_sa->get_traffic_selectors(child_sa, TRUE);
snprintf(buf, sizeof(buf), "%#R", list);
xpc_dictionary_set_string(msg, "ts_local", buf);
list = child_sa->get_traffic_selectors(child_sa, FALSE);
snprintf(buf, sizeof(buf), "%#R", list);
xpc_dictionary_set_string(msg, "ts_remote", buf);
xpc_connection_send_message(entry->conn, msg);
xpc_release(msg);
}
this->lock->unlock(this->lock);
return TRUE;
}
METHOD(listener_t, ike_updown, bool,
private_xpc_channels_t *this, ike_sa_t *ike_sa, bool up)
{
xpc_object_t msg;
entry_t *entry;
uintptr_t sa;
sa = ike_sa->get_unique_id(ike_sa);
if (up)
{
this->lock->read_lock(this->lock);
entry = this->channels->get(this->channels, (void*)sa);
if (entry)
{
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "type", "event");
xpc_dictionary_set_string(msg, "event", "up");
xpc_connection_send_message(entry->conn, msg);
xpc_release(msg);
}
this->lock->unlock(this->lock);
}
else
{
this->lock->write_lock(this->lock);
entry = this->channels->remove(this->channels, (void*)sa);
this->lock->unlock(this->lock);
if (entry)
{
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "type", "event");
xpc_dictionary_set_string(msg, "event", "down");
xpc_connection_send_message(entry->conn, msg);
xpc_release(msg);
xpc_connection_send_barrier(entry->conn, ^() {
destroy_entry(entry);
});
}
}
return TRUE;
}
/**
* Query password from App using XPC channel
*/
static shared_key_t *query_password(xpc_connection_t conn, identification_t *id)
{
char buf[128], *password;
xpc_object_t request, response;
shared_key_t *shared = NULL;
request = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(request, "type", "rpc");
xpc_dictionary_set_string(request, "rpc", "get_password");
snprintf(buf, sizeof(buf), "%Y", id);
xpc_dictionary_set_string(request, "username", buf);
response = xpc_connection_send_message_with_reply_sync(conn, request);
xpc_release(request);
if (xpc_get_type(response) == XPC_TYPE_DICTIONARY)
{
password = (char*)xpc_dictionary_get_string(response, "password");
if (password)
{
shared = shared_key_create(SHARED_EAP,
chunk_clone(chunk_from_str(password)));
}
}
xpc_release(response);
return shared;
}
/**
* Password query callback
*/
static shared_key_t* password_cb(private_xpc_channels_t *this,
shared_key_type_t type,
identification_t *me, identification_t *other,
id_match_t *match_me, id_match_t *match_other)
{
shared_key_t *shared = NULL;
ike_sa_t *ike_sa;
entry_t *entry;
u_int32_t sa;
switch (type)
{
case SHARED_EAP:
break;
default:
return NULL;
}
ike_sa = charon->bus->get_sa(charon->bus);
if (ike_sa)
{
sa = ike_sa->get_unique_id(ike_sa);
this->lock->read_lock(this->lock);
entry = this->channels->get(this->channels, (void*)sa);
if (entry && !entry->passworded)
{
entry->passworded = TRUE;
shared = query_password(entry->conn, me);
if (shared)
{
if (match_me)
{
*match_me = ID_MATCH_PERFECT;
}
if (match_other)
{
*match_other = ID_MATCH_PERFECT;
}
}
}
this->lock->unlock(this->lock);
}
return shared;
}
METHOD(xpc_channels_t, destroy, void,
private_xpc_channels_t *this)
{
lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
this->creds->destroy(this->creds);
this->channels->destroy(this->channels);
this->lock->destroy(this->lock);
free(this);
}
/**
* See header
*/
xpc_channels_t *xpc_channels_create()
{
private_xpc_channels_t *this;
INIT(this,
.public = {
.listener = {
.alert = _alert,
.ike_updown = _ike_updown,
.ike_rekey = _ike_rekey,
.ike_state_change = _ike_state_change,
.child_updown = _child_updown,
},
.add = _add,
.destroy = _destroy,
},
.channels = hashtable_create(hashtable_hash_ptr,
hashtable_equals_ptr, 4),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
this->creds = callback_cred_create_shared(
(callback_cred_shared_cb_t)password_cb, this);
lib->credmgr->add_set(lib->credmgr, &this->creds->set);
return &this->public;
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup xpc_channels xpc_channels
* @{ @ingroup xpc
*/
#ifndef XPC_CHANNELS_H_
#define XPC_CHANNELS_H_
#include <xpc/xpc.h>
#include <bus/bus.h>
typedef struct xpc_channels_t xpc_channels_t;
/**
* XPC to App channel management.
*/
struct xpc_channels_t {
/**
* Implements listener_t.
*/
listener_t listener;
/**
* Associate an IKE_SA unique identifier to an XPC connection.
*
* @param conn XPC connection to channel
* @param ike_sa IKE_SA unique identifier to associate to connection
*/
void (*add)(xpc_channels_t *this, xpc_connection_t conn, u_int32_t ike_sa);
/**
* Destroy a xpc_channels_t.
*/
void (*destroy)(xpc_channels_t *this);
};
/**
* Create a xpc_channels instance.
*/
xpc_channels_t *xpc_channels_create();
#endif /** XPC_CHANNELS_H_ @}*/

View File

@ -0,0 +1,341 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "xpc_dispatch.h"
#include "xpc_channels.h"
#include <xpc/xpc.h>
#include <signal.h>
#include <unistd.h>
#include <daemon.h>
#include <processing/jobs/callback_job.h>
typedef struct private_xpc_dispatch_t private_xpc_dispatch_t;
/**
* Private data of an xpc_dispatch_t object.
*/
struct private_xpc_dispatch_t {
/**
* Public xpc_dispatch_t interface.
*/
xpc_dispatch_t public;
/**
* XPC service we offer
*/
xpc_connection_t service;
/**
* XPC IKE_SA specific channels to App
*/
xpc_channels_t *channels;
/**
* GCD queue for XPC events
*/
dispatch_queue_t queue;
/**
* Number of active App connections
*/
refcount_t refcount;
/**
* PID of main thread
*/
pid_t pid;
};
/**
* Return version of this helper
*/
static void get_version(private_xpc_dispatch_t *this,
xpc_object_t request, xpc_object_t reply)
{
xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION);
}
/**
* Create peer config with associated ike config
*/
static peer_cfg_t* create_peer_cfg(char *name, char *host)
{
ike_cfg_t *ike_cfg;
peer_cfg_t *peer_cfg;
u_int16_t local_port, remote_port = IKEV2_UDP_PORT;
local_port = charon->socket->get_port(charon->socket, FALSE);
if (local_port != IKEV2_UDP_PORT)
{
remote_port = IKEV2_NATT_PORT;
}
ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE, "0.0.0.0", FALSE, local_port,
host, FALSE, remote_port, FRAGMENTATION_NO, 0);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
peer_cfg = peer_cfg_create(name, ike_cfg,
CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */
36000, 0, /* rekey 10h, reauth none */
600, 600, /* jitter, over 10min */
TRUE, FALSE, /* mobike, aggressive */
30, 0, /* DPD delay, timeout */
FALSE, NULL, NULL); /* mediation */
peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
return peer_cfg;
}
/**
* Add a single auth cfg of given class to peer cfg
*/
static void add_auth_cfg(peer_cfg_t *peer_cfg, bool local,
char *id, auth_class_t class)
{
auth_cfg_t *auth;
auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, class);
auth->add(auth, AUTH_RULE_IDENTITY, identification_create_from_string(id));
peer_cfg->add_auth_cfg(peer_cfg, auth, local);
}
/**
* Attach child config to peer config
*/
static child_cfg_t* create_child_cfg(char *name)
{
child_cfg_t *child_cfg;
traffic_selector_t *ts;
lifetime_cfg_t lifetime = {
.time = {
.life = 10800 /* 3h */,
.rekey = 10200 /* 2h50min */,
.jitter = 300 /* 5min */
}
};
child_cfg = child_cfg_create(name, &lifetime,
NULL, FALSE, MODE_TUNNEL, /* updown, hostaccess */
ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
0, 0, NULL, NULL, 0);
child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
ts = traffic_selector_create_dynamic(0, 0, 65535);
child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
"0.0.0.0", 0, "255.255.255.255", 65535);
child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
return child_cfg;
}
/**
* Controller initiate callback
*/
static bool initiate_cb(u_int32_t *sa, debug_t group, level_t level,
ike_sa_t *ike_sa, const char *message)
{
if (ike_sa)
{
*sa = ike_sa->get_unique_id(ike_sa);
return FALSE;
}
return TRUE;
}
/**
* Start initiating an IKE connection
*/
void start_connection(private_xpc_dispatch_t *this,
xpc_object_t request, xpc_object_t reply)
{
peer_cfg_t *peer_cfg;
child_cfg_t *child_cfg;
char *name, *id, *host;
bool success = FALSE;
xpc_endpoint_t endpoint;
xpc_connection_t channel;
u_int32_t ike_sa;
name = (char*)xpc_dictionary_get_string(request, "name");
host = (char*)xpc_dictionary_get_string(request, "host");
id = (char*)xpc_dictionary_get_string(request, "id");
endpoint = xpc_dictionary_get_value(request, "channel");
channel = xpc_connection_create_from_endpoint(endpoint);
if (name && id && host && channel)
{
peer_cfg = create_peer_cfg(name, host);
add_auth_cfg(peer_cfg, TRUE, id, AUTH_CLASS_EAP);
add_auth_cfg(peer_cfg, FALSE, host, AUTH_CLASS_ANY);
child_cfg = create_child_cfg(name);
peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg));
if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
(controller_cb_t)initiate_cb, &ike_sa, 0) == NEED_MORE)
{
this->channels->add(this->channels, channel, ike_sa);
success = TRUE;
}
}
xpc_dictionary_set_bool(reply, "success", success);
}
/**
* XPC RPC command dispatch table
*/
static struct {
char *name;
void (*handler)(private_xpc_dispatch_t *this,
xpc_object_t request, xpc_object_t reply);
} commands[] = {
{ "get_version", get_version },
{ "start_connection", start_connection },
};
/**
* Handle a received XPC request message
*/
static void handle(private_xpc_dispatch_t *this, xpc_object_t request)
{
xpc_connection_t client;
xpc_object_t reply;
const char *type, *rpc;
bool found = FALSE;
int i;
type = xpc_dictionary_get_string(request, "type");
if (type)
{
if (streq(type, "rpc"))
{
reply = xpc_dictionary_create_reply(request);
rpc = xpc_dictionary_get_string(request, "rpc");
if (reply && rpc)
{
for (i = 0; i < countof(commands); i++)
{
if (streq(commands[i].name, rpc))
{
found = TRUE;
commands[i].handler(this, request, reply);
break;
}
}
}
if (!found)
{
DBG1(DBG_CFG, "received invalid XPC rpc command: %s", rpc);
}
if (reply)
{
client = xpc_dictionary_get_remote_connection(request);
xpc_connection_send_message(client, reply);
xpc_release(reply);
}
}
else
{
DBG1(DBG_CFG, "received unknown XPC message type: %s", type);
}
}
else
{
DBG1(DBG_CFG, "received XPC message without a type");
}
}
/**
* Finalizer for client connections
*/
static void cleanup_connection(private_xpc_dispatch_t *this)
{
if (ref_put(&this->refcount))
{
DBG1(DBG_CFG, "no XPC connections, raising SIGTERM");
kill(this->pid, SIGTERM);
}
}
/**
* Set up GCD handler for XPC events
*/
static void set_handler(private_xpc_dispatch_t *this)
{
xpc_connection_set_event_handler(this->service, ^(xpc_object_t conn)
{
xpc_connection_set_event_handler(conn, ^(xpc_object_t event)
{
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY)
{
handle(this, event);
}
});
ref_get(&this->refcount);
xpc_connection_set_context(conn, this);
xpc_connection_set_finalizer_f(conn, (void*)cleanup_connection);
xpc_connection_resume(conn);
});
xpc_connection_resume(this->service);
}
METHOD(xpc_dispatch_t, destroy, void,
private_xpc_dispatch_t *this)
{
charon->bus->remove_listener(charon->bus, &this->channels->listener);
this->channels->destroy(this->channels);
if (this->service)
{
xpc_connection_suspend(this->service);
xpc_release(this->service);
}
free(this);
}
/**
* See header
*/
xpc_dispatch_t *xpc_dispatch_create()
{
private_xpc_dispatch_t *this;
INIT(this,
.public = {
.destroy = _destroy,
},
.channels = xpc_channels_create(),
.queue = dispatch_queue_create("org.strongswan.charon-xpc.q",
DISPATCH_QUEUE_CONCURRENT),
.pid = getpid(),
);
charon->bus->add_listener(charon->bus, &this->channels->listener);
this->service = xpc_connection_create_mach_service(
"org.strongswan.charon-xpc", this->queue,
XPC_CONNECTION_MACH_SERVICE_LISTENER);
if (!this->service)
{
destroy(this);
return NULL;
}
set_handler(this);
return &this->public;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup xpc_dispatch xpc_dispatch
* @{ @ingroup xpc
*/
#ifndef XPC_DISPATCH_H_
#define XPC_DISPATCH_H_
typedef struct xpc_dispatch_t xpc_dispatch_t;
/**
* XPC dispatcher to control the daemon.
*/
struct xpc_dispatch_t {
/**
* Destroy a xpc_dispatch_t.
*/
void (*destroy)(xpc_dispatch_t *this);
};
/**
* Create a xpc_dispatch instance.
*/
xpc_dispatch_t *xpc_dispatch_create();
#endif /** XPC_DISPATCH_H_ @}*/

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "xpc_logger.h"
typedef struct private_xpc_logger_t private_xpc_logger_t;
/**
* Private data of an xpc_logger_t object.
*/
struct private_xpc_logger_t {
/**
* Public xpc_logger_t interface.
*/
xpc_logger_t public;
/**
* XPC channel to send logging messages to
*/
xpc_connection_t conn;
/**
* IKE_SA we log for
*/
u_int32_t ike_sa;
};
METHOD(logger_t, log_, void,
private_xpc_logger_t *this, debug_t group, level_t level, int thread,
ike_sa_t* ike_sa, const char *message)
{
if (ike_sa && ike_sa->get_unique_id(ike_sa) == this->ike_sa)
{
xpc_object_t msg;
msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, "type", "event");
xpc_dictionary_set_string(msg, "event", "log");
xpc_dictionary_set_string(msg, "message", message);
xpc_connection_send_message(this->conn, msg);
xpc_release(msg);
}
}
METHOD(logger_t, get_level, level_t,
private_xpc_logger_t *this, debug_t group)
{
return LEVEL_CTRL;
}
METHOD(xpc_logger_t, set_ike_sa, void,
private_xpc_logger_t *this, u_int32_t ike_sa)
{
this->ike_sa = ike_sa;
}
METHOD(xpc_logger_t, destroy, void,
private_xpc_logger_t *this)
{
free(this);
}
/**
* See header
*/
xpc_logger_t *xpc_logger_create(xpc_connection_t conn)
{
private_xpc_logger_t *this;
INIT(this,
.public = {
.logger = {
.log = _log_,
.get_level = _get_level,
},
.set_ike_sa = _set_ike_sa,
.destroy = _destroy,
},
.conn = conn,
);
return &this->public;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup xpc_logger xpc_logger
* @{ @ingroup xpc
*/
#ifndef XPC_LOGGER_H_
#define XPC_LOGGER_H_
#include <xpc/xpc.h>
#include <daemon.h>
typedef struct xpc_logger_t xpc_logger_t;
/**
* Connection specific logger over XPC.
*/
struct xpc_logger_t {
/**
* Implements logger_t.
*/
logger_t logger;
/**
* Set the IKE_SA unique identifier this logger logs for.
*
* @param ike_sa IKE_SA unique identifier
*/
void (*set_ike_sa)(xpc_logger_t *this, u_int32_t ike_sa);
/**
* Destroy a xpc_logger_t.
*/
void (*destroy)(xpc_logger_t *this);
};
/**
* Create a xpc_logger instance.
*
* @param conn XPC connection to send logging events to
* @return XPC logger
*/
xpc_logger_t *xpc_logger_create(xpc_connection_t conn);
#endif /** XPC_LOGGER_H_ @}*/

View File

@ -0,0 +1,333 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
5B74989217311B200041971E /* xpc_channels.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74989117311B200041971E /* xpc_channels.c */; };
5B7498B8173275D10041971E /* xpc_logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B7498B7173275D10041971E /* xpc_logger.c */; };
5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; };
5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; };
5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; };
5BF60F3E1734070A00E5D608 /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; };
5BF60F631743C57500E5D608 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BF60F621743C57500E5D608 /* SystemConfiguration.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
5B74984C172AA3550041971E /* xpc_dispatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_dispatch.c; sourceTree = "<group>"; };
5B74984E172AA3670041971E /* xpc_dispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_dispatch.h; sourceTree = "<group>"; };
5B74989017311AFC0041971E /* xpc_channels.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_channels.h; sourceTree = "<group>"; };
5B74989117311B200041971E /* xpc_channels.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_channels.c; sourceTree = "<group>"; };
5B7498B7173275D10041971E /* xpc_logger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_logger.c; sourceTree = "<group>"; };
5B7498B9173275DD0041971E /* xpc_logger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_logger.h; sourceTree = "<group>"; };
5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = "<group>"; };
5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Launchd.plist"; sourceTree = "<group>"; };
5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Info.plist"; sourceTree = "<group>"; };
5BD1CCEA1727CCA400587077 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = "<group>"; };
5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
5BD1CCF21727DE3E00587077 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
5BF60F621743C57500E5D608 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
5BD1CCCE1726DB4000587077 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5BF60F631743C57500E5D608 /* SystemConfiguration.framework in Frameworks */,
5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */,
5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
5BD1CCA11726DB0100587077 = {
isa = PBXGroup;
children = (
5BD1CCEA1727CCA400587077 /* README.md */,
5BD1CCD51726DB4000587077 /* charon-xpc */,
5BD1CCAF1726DB0100587077 /* Frameworks */,
5BD1CCAD1726DB0100587077 /* Products */,
);
sourceTree = "<group>";
};
5BD1CCAD1726DB0100587077 /* Products */ = {
isa = PBXGroup;
children = (
5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */,
);
name = Products;
sourceTree = "<group>";
};
5BD1CCAF1726DB0100587077 /* Frameworks */ = {
isa = PBXGroup;
children = (
5BF60F621743C57500E5D608 /* SystemConfiguration.framework */,
5BD1CCF21727DE3E00587077 /* Security.framework */,
5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */,
5BD1CCD31726DB4000587077 /* CoreFoundation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
5BD1CCD51726DB4000587077 /* charon-xpc */ = {
isa = PBXGroup;
children = (
5BD1CCD61726DB4000587077 /* charon-xpc.c */,
5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */,
5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */,
5B74984C172AA3550041971E /* xpc_dispatch.c */,
5B74984E172AA3670041971E /* xpc_dispatch.h */,
5B74989017311AFC0041971E /* xpc_channels.h */,
5B74989117311B200041971E /* xpc_channels.c */,
5B7498B7173275D10041971E /* xpc_logger.c */,
5B7498B9173275DD0041971E /* xpc_logger.h */,
);
path = "charon-xpc";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
5BD1CCD01726DB4000587077 /* charon-xpc */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5BD1CCDA1726DB4000587077 /* Build configuration list for PBXNativeTarget "charon-xpc" */;
buildPhases = (
5BD1CCCD1726DB4000587077 /* Sources */,
5BD1CCCE1726DB4000587077 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "charon-xpc";
productName = "charon-xpc";
productReference = 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
5BD1CCA31726DB0100587077 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0450;
ORGANIZATIONNAME = "revosec AG";
};
buildConfigurationList = 5BD1CCA61726DB0100587077 /* Build configuration list for PBXProject "strongSwan" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 5BD1CCA11726DB0100587077;
productRefGroup = 5BD1CCAD1726DB0100587077 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
5BD1CCD01726DB4000587077 /* charon-xpc */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
5BD1CCCD1726DB4000587077 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */,
5B74989217311B200041971E /* xpc_channels.c in Sources */,
5BF60F3E1734070A00E5D608 /* xpc_dispatch.c in Sources */,
5B7498B8173275D10041971E /* xpc_logger.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
5BD1CCC81726DB0200587077 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
5BD1CCC91726DB0200587077 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx;
};
name = Release;
};
5BD1CCDB1726DB4000587077 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Joe Developer";
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO;
HEADER_SEARCH_PATHS = (
/usr/include,
../../libstrongswan,
../../libcharon,
../../libhydra,
/opt/local/include,
);
INFOPLIST_FILE = "charon-xpc/charon-xpc-Info.plist";
INSTALL_PATH = /;
LIBRARY_SEARCH_PATHS = (
/usr/lib,
../../libstrongswan/.libs,
../../libcharon/.libs,
../../libhydra/.libs,
/opt/local/lib,
);
OTHER_CFLAGS = (
"-include",
../../../config.h,
"-DVSTR_COMPILE_INLINE=0",
);
OTHER_LDFLAGS = (
"-lcrypto",
/opt/local/lib/libvstr.a,
"-force_load",
../../libstrongswan/.libs/libstrongswan.a,
"-force_load",
../../libhydra/.libs/libhydra.a,
"-force_load",
../../libcharon/.libs/libcharon.a,
"-sectcreate",
__TEXT,
__info_plist,
"charon-xpc/charon-xpc-Info.plist",
"-sectcreate",
__TEXT,
__launchd_plist,
"charon-xpc/charon-xpc-Launchd.plist",
);
PRODUCT_NAME = "org.strongswan.charon-xpc";
PROVISIONING_PROFILE = "";
STRIP_STYLE = "non-global";
};
name = Debug;
};
5BD1CCDC1726DB4000587077 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Joe Developer";
COPY_PHASE_STRIP = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO;
HEADER_SEARCH_PATHS = (
/usr/include,
../../libstrongswan,
../../libcharon,
../../libhydra,
/opt/local/include,
);
INFOPLIST_FILE = "charon-xpc/charon-xpc-Info.plist";
INSTALL_PATH = /;
LIBRARY_SEARCH_PATHS = (
/usr/lib,
../../libstrongswan/.libs,
../../libcharon/.libs,
../../libhydra/.libs,
/opt/local/lib,
);
OTHER_CFLAGS = (
"-include",
../../../config.h,
"-DVSTR_COMPILE_INLINE=0",
);
OTHER_LDFLAGS = (
"-lcrypto",
/opt/local/lib/libvstr.a,
"-force_load",
../../libstrongswan/.libs/libstrongswan.a,
"-force_load",
../../libhydra/.libs/libhydra.a,
"-force_load",
../../libcharon/.libs/libcharon.a,
"-sectcreate",
__TEXT,
__info_plist,
"charon-xpc/charon-xpc-Info.plist",
"-sectcreate",
__TEXT,
__launchd_plist,
"charon-xpc/charon-xpc-Launchd.plist",
);
PRODUCT_NAME = "org.strongswan.charon-xpc";
PROVISIONING_PROFILE = "";
STRIP_STYLE = "non-global";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
5BD1CCA61726DB0100587077 /* Build configuration list for PBXProject "strongSwan" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5BD1CCC81726DB0200587077 /* Debug */,
5BD1CCC91726DB0200587077 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5BD1CCDA1726DB4000587077 /* Build configuration list for PBXNativeTarget "charon-xpc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5BD1CCDB1726DB4000587077 /* Debug */,
5BD1CCDC1726DB4000587077 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 5BD1CCA31726DB0100587077 /* Project object */;
}

View File

@ -173,6 +173,7 @@ sys_logger_t *sys_logger_create(int facility)
);
set_level(this, DBG_ANY, LEVEL_SILENT);
setlogmask(LOG_UPTO(LOG_INFO));
return &this->public;
}

View File

@ -423,6 +423,13 @@ if MONOLITHIC
endif
endif
if USE_KEYCHAIN
SUBDIRS += plugins/keychain
if MONOLITHIC
libstrongswan_la_LIBADD += plugins/keychain/libstrongswan-keychain.la
endif
endif
if USE_PKCS11
SUBDIRS += plugins/pkcs11
if MONOLITHIC

View File

@ -16,6 +16,8 @@
#include "hashtable.h"
#include <utils/chunk.h>
/** The maximum capacity of the hash table (MUST be a power of 2) */
#define MAX_CAPACITY (1 << 30)
@ -146,9 +148,40 @@ struct private_enumerator_t {
* previous pair (used by remove_at)
*/
pair_t *prev;
};
/*
* See header.
*/
u_int hashtable_hash_ptr(void *key)
{
return chunk_hash(chunk_from_thing(key));
}
/*
* See header.
*/
u_int hashtable_hash_str(void *key)
{
return chunk_hash(chunk_from_str((char*)key));
}
/*
* See header.
*/
bool hashtable_equals_ptr(void *key, void *other_key)
{
return key == other_key;
}
/*
* See header.
*/
bool hashtable_equals_str(void *key, void *other_key)
{
return streq(key, other_key);
}
/**
* This function returns the next-highest power of two for the given number.
* The algorithm works by setting all bits on the right-hand side of the most
@ -441,4 +474,3 @@ hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
return &this->public;
}

View File

@ -33,6 +33,22 @@ typedef struct hashtable_t hashtable_t;
*/
typedef u_int (*hashtable_hash_t)(void *key);
/**
* Hashtable hash function calculation the hash solely based on the key pointer.
*
* @param key key to hash
* @return hash of key
*/
u_int hashtable_hash_ptr(void *key);
/**
* Hashtable hash function calculation the hash for char* keys.
*
* @param key key to hash, a char*
* @return hash of key
*/
u_int hashtable_hash_str(void *key);
/**
* Prototype for a function that compares the two keys for equality.
*
@ -42,6 +58,24 @@ typedef u_int (*hashtable_hash_t)(void *key);
*/
typedef bool (*hashtable_equals_t)(void *key, void *other_key);
/**
* Hashtable equals function comparing pointers.
*
* @param key key to compare
* @param other_key other key to compare
* @return TRUE if key == other_key
*/
bool hashtable_equals_ptr(void *key, void *other_key);
/**
* Hashtable equals function comparing char* keys.
*
* @param key key to compare
* @param other_key other key to compare
* @return TRUE if streq(key, other_key)
*/
bool hashtable_equals_str(void *key, void *other_key);
/**
* Class implementing a hash table.
*
@ -121,7 +155,6 @@ struct hashtable_t {
* Destroys a hash table object.
*/
void (*destroy) (hashtable_t *this);
};
/**

View File

@ -378,8 +378,8 @@ METHOD(credential_manager_t, get_shared, shared_key_t*,
identification_t *me, identification_t *other)
{
shared_key_t *current, *found = NULL;
id_match_t *best_me = ID_MATCH_NONE, *best_other = ID_MATCH_NONE;
id_match_t *match_me, *match_other;
id_match_t best_me = ID_MATCH_NONE, best_other = ID_MATCH_NONE;
id_match_t match_me, match_other;
enumerator_t *enumerator;
enumerator = create_shared_enumerator(this, type, me, other);
@ -393,6 +393,10 @@ METHOD(credential_manager_t, get_shared, shared_key_t*,
best_me = match_me;
best_other = match_other;
}
if (best_me == ID_MATCH_PERFECT && best_other == ID_MATCH_PERFECT)
{
break;
}
}
enumerator->destroy(enumerator);
return found;

View File

@ -0,0 +1,17 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan
AM_CFLAGS = -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-keychain.la
else
plugin_LTLIBRARIES = libstrongswan-keychain.la
endif
libstrongswan_keychain_la_SOURCES = \
keychain_plugin.h keychain_plugin.c \
keychain_creds.h keychain_creds.c
libstrongswan_keychain_la_LDFLAGS = -module -avoid-version \
-framework Security -framework CoreFoundation

View File

@ -0,0 +1,203 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "keychain_creds.h"
#include <utils/debug.h>
#include <credentials/sets/mem_cred.h>
#include <processing/jobs/callback_job.h>
#include <Security/Security.h>
/**
* System Roots keychain
*/
#define SYSTEM_ROOTS "/System/Library/Keychains/SystemRootCertificates.keychain"
/**
* System keychain
*/
#define SYSTEM "/Library/Keychains/System.keychain"
typedef struct private_keychain_creds_t private_keychain_creds_t;
/**
* Private data of an keychain_creds_t object.
*/
struct private_keychain_creds_t {
/**
* Public keychain_creds_t interface.
*/
keychain_creds_t public;
/**
* Active in-memory credential set
*/
mem_cred_t *set;
/**
* System roots credential set
*/
mem_cred_t *roots;
/**
* Run loop of event monitoring thread
*/
CFRunLoopRef loop;
};
/**
* Load a credential sets with certificates from a keychain path
*/
static mem_cred_t* load_certs(private_keychain_creds_t *this, char *path)
{
SecKeychainRef keychain;
SecKeychainSearchRef search;
SecKeychainItemRef item;
mem_cred_t *set;
OSStatus status;
set = mem_cred_create();
DBG1(DBG_CFG, "loading certificates from %s:", path);
status = SecKeychainOpen(path, &keychain);
if (status == errSecSuccess)
{
status = SecKeychainSearchCreateFromAttributes(keychain,
kSecCertificateItemClass, NULL, &search);
if (status == errSecSuccess)
{
while (SecKeychainSearchCopyNext(search, &item) == errSecSuccess)
{
certificate_t *cert;
UInt32 len;
void *data;
if (SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL,
&len, &data) == errSecSuccess)
{
cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB_ASN1_DER, chunk_create(data, len),
BUILD_END);
if (cert)
{
DBG1(DBG_CFG, " loaded '%Y'", cert->get_subject(cert));
set->add_cert(set, TRUE, cert);
}
SecKeychainItemFreeAttributesAndData(NULL, data);
}
CFRelease(item);
}
CFRelease(search);
}
CFRelease(keychain);
}
return set;
}
/**
* Callback function reloading keychain on changes
*/
static OSStatus keychain_cb(SecKeychainEvent keychainEvent,
SecKeychainCallbackInfo *info,
private_keychain_creds_t *this)
{
mem_cred_t *new;
DBG1(DBG_CFG, "received keychain event, reloading credentials");
/* register new before removing old */
new = load_certs(this, SYSTEM);
lib->credmgr->add_set(lib->credmgr, &new->set);
lib->credmgr->remove_set(lib->credmgr, &this->set->set);
lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
this->set->destroy(this->set);
this->set = new;
return errSecSuccess;
}
/**
* Wait for changes in the keychain and handle them
*/
static job_requeue_t monitor_changes(private_keychain_creds_t *this)
{
if (SecKeychainAddCallback((SecKeychainCallback)keychain_cb,
kSecAddEventMask | kSecDeleteEventMask |
kSecUpdateEventMask | kSecTrustSettingsChangedEventMask,
this) == errSecSuccess)
{
this->loop = CFRunLoopGetCurrent();
/* does not return until cancelled */
CFRunLoopRun();
this->loop = NULL;
SecKeychainRemoveCallback((SecKeychainCallback)keychain_cb);
}
return JOB_REQUEUE_NONE;
}
/**
* Cancel the monitoring thread in its RunLoop
*/
static bool cancel_monitor(private_keychain_creds_t *this)
{
if (this->loop)
{
CFRunLoopStop(this->loop);
}
return TRUE;
}
METHOD(keychain_creds_t, destroy, void,
private_keychain_creds_t *this)
{
lib->credmgr->remove_set(lib->credmgr, &this->set->set);
lib->credmgr->remove_set(lib->credmgr, &this->roots->set);
this->set->destroy(this->set);
this->roots->destroy(this->roots);
free(this);
}
/**
* See header
*/
keychain_creds_t *keychain_creds_create()
{
private_keychain_creds_t *this;
INIT(this,
.public = {
.destroy = _destroy,
},
);
this->roots = load_certs(this, SYSTEM_ROOTS);
this->set = load_certs(this, SYSTEM);
lib->credmgr->add_set(lib->credmgr, &this->roots->set);
lib->credmgr->add_set(lib->credmgr, &this->set->set);
lib->processor->queue_job(lib->processor,
(job_t*)callback_job_create_with_prio((void*)monitor_changes,
this, NULL, (void*)cancel_monitor, JOB_PRIO_CRITICAL));
return &this->public;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup keychain_creds keychain_creds
* @{ @ingroup keychain
*/
#ifndef KEYCHAIN_CREDS_H_
#define KEYCHAIN_CREDS_H_
typedef struct keychain_creds_t keychain_creds_t;
#include <credentials/credential_manager.h>
/**
* Credential set using OS X Keychain Services.
*/
struct keychain_creds_t {
/**
* Destroy a keychain_creds_t.
*/
void (*destroy)(keychain_creds_t *this);
};
/**
* Create a keychain_creds instance.
*/
keychain_creds_t *keychain_creds_create();
#endif /** KEYCHAIN_CREDS_H_ @}*/

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "keychain_plugin.h"
#include "keychain_creds.h"
#include <library.h>
typedef struct private_keychain_plugin_t private_keychain_plugin_t;
/**
* private data of keychain_plugin
*/
struct private_keychain_plugin_t {
/**
* public functions
*/
keychain_plugin_t public;
/**
* System level Keychain Services credential set
*/
keychain_creds_t *creds;
};
METHOD(plugin_t, get_name, char*,
private_keychain_plugin_t *this)
{
return "keychain";
}
/**
* Load/unload certificates from Keychain.
*/
static bool load_creds(private_keychain_plugin_t *this,
plugin_feature_t *feature, bool reg, void *data)
{
if (reg)
{
this->creds = keychain_creds_create();
}
else
{
this->creds->destroy(this->creds);
}
return TRUE;
}
METHOD(plugin_t, get_features, int,
private_keychain_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_CALLBACK((plugin_feature_callback_t)load_creds, NULL),
PLUGIN_PROVIDE(CUSTOM, "keychain"),
PLUGIN_DEPENDS(CERT_DECODE, CERT_X509),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_keychain_plugin_t *this)
{
free(this);
}
/*
* see header file
*/
plugin_t *keychain_plugin_create()
{
private_keychain_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
return &this->public.plugin;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup keychain keychain
* @ingroup plugins
*
* @defgroup keychain_plugin keychain_plugin
* @{ @ingroup keychain
*/
#ifndef KEYCHAIN_PLUGIN_H_
#define KEYCHAIN_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct keychain_plugin_t keychain_plugin_t;
/**
* Plugin providing OS X Keychain Services support.
*/
struct keychain_plugin_t {
/**
* Implements plugin interface,
*/
plugin_t plugin;
};
#endif /** KEYCHAIN_PLUGIN_H_ @}*/

View File

@ -678,6 +678,41 @@ static bool parse_keyUsage_ext(private_openssl_x509_t *this,
return FALSE;
}
/**
* Parse ExtendedKeyUsage
*/
static bool parse_extKeyUsage_ext(private_openssl_x509_t *this,
X509_EXTENSION *ext)
{
EXTENDED_KEY_USAGE *usage;
int i;
usage = X509V3_EXT_d2i(ext);
if (usage)
{
for (i = 0; i < sk_ASN1_OBJECT_num(usage); i++)
{
switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(usage, i)))
{
case NID_server_auth:
this->flags |= X509_SERVER_AUTH;
break;
case NID_client_auth:
this->flags |= X509_CLIENT_AUTH;
break;
case NID_OCSP_sign:
this->flags |= X509_OCSP_SIGNER;
break;
default:
break;
}
}
sk_ASN1_OBJECT_pop_free(usage, ASN1_OBJECT_free);
return TRUE;
}
return FALSE;
}
/**
* Parse CRL distribution points
*/
@ -963,6 +998,9 @@ static bool parse_extensions(private_openssl_x509_t *this)
case NID_key_usage:
ok = parse_keyUsage_ext(this, ext);
break;
case NID_ext_key_usage:
ok = parse_extKeyUsage_ext(this, ext);
break;
case NID_crl_distribution_points:
ok = parse_crlDistributionPoints_ext(this, ext);
break;
@ -977,7 +1015,12 @@ static bool parse_extensions(private_openssl_x509_t *this)
"libstrongswan.x509.enforce_critical", TRUE);
if (!ok)
{
DBG1(DBG_LIB, "found unsupported critical X.509 extension");
char buf[80] = "";
OBJ_obj2txt(buf, sizeof(buf),
X509_EXTENSION_get_object(ext), 0);
DBG1(DBG_LIB, "found unsupported critical X.509 "
"extension: %s", buf);
}
break;
}
@ -990,38 +1033,6 @@ static bool parse_extensions(private_openssl_x509_t *this)
return TRUE;
}
/**
* Parse ExtendedKeyUsage
*/
static void parse_extKeyUsage(private_openssl_x509_t *this)
{
EXTENDED_KEY_USAGE *usage;
int i;
usage = X509_get_ext_d2i(this->x509, NID_ext_key_usage, NULL, NULL);
if (usage)
{
for (i = 0; i < sk_ASN1_OBJECT_num(usage); i++)
{
switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(usage, i)))
{
case NID_server_auth:
this->flags |= X509_SERVER_AUTH;
break;
case NID_client_auth:
this->flags |= X509_CLIENT_AUTH;
break;
case NID_OCSP_sign:
this->flags |= X509_OCSP_SIGNER;
break;
default:
break;
}
}
sk_ASN1_OBJECT_pop_free(usage, ASN1_OBJECT_free);
}
}
/**
* Parse a DER encoded x509 certificate
*/
@ -1088,7 +1099,6 @@ static bool parse_certificate(private_openssl_x509_t *this)
{
return FALSE;
}
parse_extKeyUsage(this);
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (!hasher || !hasher->allocate_hash(hasher, this->encoding, &this->hash))

View File

@ -341,7 +341,20 @@ thread_t *thread_create(thread_main_t main, void *arg)
*/
thread_t *thread_current()
{
return current_thread->get(current_thread);
private_thread_t *this;
this = (private_thread_t*)current_thread->get(current_thread);
if (!this)
{
this = thread_create_internal();
id_mutex->lock(id_mutex);
this->id = next_id++;
id_mutex->unlock(id_mutex);
current_thread->set(current_thread, (void*)this);
}
return &this->public;
}
/**