diff options
436 files changed, 23923 insertions, 5509 deletions
diff --git a/Android.mk.in b/Android.mk.in index 2ffbe07e6..e1f061350 100644 --- a/Android.mk.in +++ b/Android.mk.in @@ -1,11 +1,17 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -# whether starter is built. allows to control the daemons from the command line -strongswan_BUILD_STARTER := false +# the executables that should be installed on the final system have to be added +# to PRODUCT_PACKAGES in +# build/target/product/core.mk +# possible executables are +# starter - allows to control and configure the daemons from the command line +# charon - the IKEv2 daemon +# pluto - the IKEv1 daemon -# whether pluto (IKEv1 daemon) is built. charon (IKEv2) is always enabled -strongswan_BUILD_PLUTO := false +# if you enable starter and/or pluto (see above) uncomment the proper lines here +# strongswan_BUILD_STARTER := true +# strongswan_BUILD_PLUTO := true # this is the list of plugins that are built into libstrongswan and charon # also these plugins are loaded by default (if not changed in strongswan.conf) diff --git a/Doxyfile.in b/Doxyfile.in index 524d639e0..7fb516190 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -532,6 +532,7 @@ INPUT = @SRC_DIR@/src/libstrongswan \ @SRC_DIR@/src/libcharon \ @SRC_DIR@/src/libsimaka \ @SRC_DIR@/src/libtls \ + @SRC_DIR@/src/libradius \ @SRC_DIR@/src/libtnccs \ @SRC_DIR@/src/libtncif \ @SRC_DIR@/src/libfast \ @@ -5,8 +5,8 @@ Git repository --------------------- -For interested developers, we have a public repository. To check out and -compile the code, you need the following tools: +For interested developers, we have a public repository. To check out and compile +the code, you need the following tools: - Git - a recent GNU C compiler (>= 3.x) @@ -43,7 +43,7 @@ Then you're in, start the build as usual: API documentation ----------------- -Charon and libstrongswan contain inline code documentation. These comments can +Charon and libstrongswan contain inline code documentation. These comments can be extracted using doxygen. It is built using 'make apidoc', which creates an 'apidoc' folder containing the HTML files. @@ -18,7 +18,7 @@ Contents -------- The strongSwan 4.x branch introduces a new build environment featuring - GNU autotools. This should simplify the build process and package + GNU autotools. This should simplify the build process and package maintenance. First check for the availability of required packages on your system (section 2.). You may want to include support for additional features, which @@ -42,9 +42,9 @@ Contents To check if your kernel fullfills the requirements, see section 4. - Next add your connections to "/etc/ipsec.conf" and your secrets to + Next add your connections to "/etc/ipsec.conf" and your secrets to "/etc/ipsec.secrets". Connections that are to be negotiated by the new - IKEv2 charon keying daemon should be designated by "keyexchange=ikev2" and + IKEv2 charon keying daemon should be designated by "keyexchange=ikev2" and those by the IKEv1 pluto keying daemon either by "keyexchange=ikev1" or the default "keyexchange=ike". @@ -118,7 +118,7 @@ Contents --------------------------------- If you want to securely store your X.509 certificates and private RSA keys - on a smart card or a USB crypto token then you will need a PKCS #11 library + on a smart card or a USB crypto token then you will need a PKCS #11 library for the smart card of your choice. The OpenSC PKCS#11 library (use versions >= 0.9.4) available from http://www.opensc.org/ supports quite a selection of cards and tokens (e.g. Aladdin eToken Pro32k, Schlumberger @@ -1,19 +1,56 @@ +strongswan-4.6.3 +---------------- + +- The tnc-pdp plugin implements a RADIUS server interface allowing + a strongSwan TNC server to act as a Policy Decision Point. + +- Added infrastructure to listen to RADIUS Dynamic Authorization + Extension requests. + +- Added support for untruncated MD5 and SHA1 HMACs in ESP as used in + RFC 4595. + + +strongswan-4.6.2 +---------------- + +- Upgraded the TCG IF-IMC and IF-IMV C API to the upcoming version 1.3 + which supports IF-TNCCS 2.0 long message types, the exclusive flags + and multiple IMC/IMV IDs. Both the TNC Client and Server as well as + the "Test", "Scanner", and "Attestation" IMC/IMV pairs were updated. + +- Fully implemented the "TCG Attestation PTS Protocol: Binding to IF-M" + standard (TLV-based messages only). TPM-based remote attestation of + Linux IMA (Integrity Measurement Architecture) possible. Measurement + reference values are automatically stored in an SQLite database. + +- The EAP-RADIUS authentication backend supports RADIUS accounting. It sends + start/stop messages containing Username, Framed-IP and Input/Output-Octets + attributes and has been tested against FreeRADIUS and Microsoft NPS. + +- Added support for PKCS#8 encoded private keys via the libstrongswan + pkcs8 plugin. This is the default format used by some OpenSSL tools since + version 1.0.0 (e.g. openssl req with -keyout). + +- Added session resumption support to the strongSwan TLS stack. + + strongswan-4.6.1 ---------------- - Because of changing checksums before and after installation which caused the integrity tests to fail we avoided directly linking libsimaka, libtls and libtnccs to those libcharon plugins which make use of these dynamic libraries. - Instead we linked the libraries to the charon daemon. Unfortunately the most - recent libtool versions do no keep links to dynamic libraries that are not - actually used by the charon daemon itself, thus causing failures during the - loading of the plugins which depend on these libraries for resolving external - symbols. + Instead we linked the libraries to the charon daemon. Unfortunately Ubuntu + 11.10 activated the --as-needed ld option which discards explicit links + to dynamic libraries that are not actually used by the charon daemon itself, + thus causing failures during the loading of the plugins which depend on these + libraries for resolving external symbols. - Therefore our approach of computing integrity checksums for plugins had to be changed radically by moving the hash generation from the compilation to the post-installation phase. - + strongswan-4.6.0 ---------------- diff --git a/configure.in b/configure.in index 1d28cfac2..b99487aea 100755 --- a/configure.in +++ b/configure.in @@ -92,6 +92,7 @@ ARG_DISBL_SET([revocation], [disable X509 CRL/OCSP revocation check plugin.] ARG_DISBL_SET([constraints], [disable advanced X509 constraint checking plugin.]) ARG_DISBL_SET([pubkey], [disable RAW public key support plugin.]) ARG_DISBL_SET([pkcs1], [disable PKCS1 key decoding plugin.]) +ARG_DISBL_SET([pkcs8], [disable PKCS8 private key decoding plugin.]) ARG_DISBL_SET([pgp], [disable PGP key decoding plugin.]) ARG_DISBL_SET([dnskey], [disable DNS RR key decoding plugin.]) ARG_DISBL_SET([pem], [disable PEM decoding plugin.]) @@ -132,6 +133,7 @@ ARG_ENABL_SET([eap-radius], [enable RADIUS proxy authentication module.]) ARG_ENABL_SET([xauth-generic], [enable generic XAuth backend.]) ARG_ENABL_SET([xauth-eap], [enable XAuth backend using EAP methods to verify passwords.]) ARG_ENABL_SET([tnc-ifmap], [enable TNC IF-MAP module.]) +ARG_ENABL_SET([tnc-pdp], [enable TNC policy decision point module.]) ARG_ENABL_SET([tnc-imc], [enable TNC IMC module.]) ARG_ENABL_SET([tnc-imv], [enable TNC IMV module.]) ARG_ENABL_SET([tnccs-11], [enable TNCCS 1.1 protocol module.]) @@ -194,6 +196,7 @@ ARG_ENABL_SET([certexpire], [enable CSV export of expiration dates of used c ARG_ENABL_SET([led], [enable plugin to control LEDs on IKEv2 activity using the Linux kernel LED subsystem.]) ARG_ENABL_SET([duplicheck], [advanced duplicate checking plugin using liveness checks.]) ARG_ENABL_SET([coupling], [enable IKEv2 plugin to couple peer certificates permanently to authentication.]) +ARG_ENABL_SET([radattr], [enable plugin to inject and process custom RADIUS attributes as IKEv2 client.]) ARG_ENABL_SET([vstr], [enforce using the Vstr string library to replace glibc-like printf hooks.]) ARG_ENABL_SET([monolithic], [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.]) @@ -255,7 +258,11 @@ if test x$eap_tls = xtrue -o x$eap_ttls = xtrue -o x$eap_peap = xtrue; then tls=true; fi -if test x$tnc_imc = xtrue -o x$tnc_imv = xtrue -o x$tnccs_11 = xtrue -o x$tnccs_11 = xtrue -o x$tnccs_dynamic = xtrue; then +if test x$eap_radius = xtrue -o x$radattr = xtrue -o x$tnc_pdp = xtrue; then + radius=true; +fi + +if test x$tnc_imc = xtrue -o x$tnc_imv = xtrue -o x$tnccs_11 = xtrue -o x$tnccs_11 = xtrue -o x$tnccs_dynamic = xtrue -o x$eap_tnc = xtrue; then tnc_tnccs=true; fi @@ -384,6 +391,22 @@ dnl check if native rwlocks are available AC_CHECK_FUNCS(pthread_rwlock_init) LIBS=$saved_LIBS +AC_CHECK_FUNC( + [gettid], + [AC_DEFINE(HAVE_GETTID)], + [AC_MSG_CHECKING([for SYS_gettid]) + AC_TRY_COMPILE( + [#define _GNU_SOURCE + #include <unistd.h> + #include <sys/syscall.h>], + [int main() { + return syscall(SYS_gettid);}], + [AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GETTID]) + AC_DEFINE([HAVE_SYS_GETTID])], + [AC_MSG_RESULT([no])] + )] +) + AC_CHECK_FUNCS(prctl mallinfo getpass closefrom) AC_CHECK_HEADERS(sys/sockio.h glob.h) @@ -570,6 +593,11 @@ if test x$axis2c = xtrue; then AC_SUBST(axis2c_LIBS) fi +if test x$imc_attestation = xtrue -o x$imv_attestation = xtrue; then + AC_HAVE_LIBRARY([tspi],[LIBS="$LIBS"],[AC_MSG_ERROR([TrouSerS library libtspi not found])]) + AC_CHECK_HEADER([trousers/tss.h],,[AC_MSG_ERROR([TrouSerS header trousers/tss.h not found!])]) +fi + if test x$dumm = xtrue; then PKG_CHECK_MODULES(gtk, [gtk+-2.0 vte]) AC_SUBST(gtk_CFLAGS) @@ -762,6 +790,7 @@ libcharon_plugins= pluto_plugins= starter_plugins= pool_plugins= +attest_plugins= openac_plugins= scepclient_plugins= pki_plugins= @@ -780,31 +809,32 @@ ADD_PLUGIN([test-vectors], [s libcharon pluto openac scepclient pki]) ADD_PLUGIN([curl], [s libcharon pluto scepclient scripts]) ADD_PLUGIN([soup], [s libcharon pluto scripts]) ADD_PLUGIN([ldap], [s libcharon pluto scepclient scripts]) -ADD_PLUGIN([mysql], [s libcharon pluto pool manager medsrv]) -ADD_PLUGIN([sqlite], [s libcharon pluto pool manager medsrv]) +ADD_PLUGIN([mysql], [s libcharon pluto pool manager medsrv attest]) +ADD_PLUGIN([sqlite], [s libcharon pluto pool manager medsrv attest]) ADD_PLUGIN([pkcs11], [s libcharon pki]) ADD_PLUGIN([aes], [s libcharon pluto openac scepclient pki scripts]) ADD_PLUGIN([des], [s libcharon pluto openac scepclient pki scripts]) ADD_PLUGIN([blowfish], [s libcharon pluto openac scepclient pki scripts]) -ADD_PLUGIN([sha1], [s libcharon pluto openac scepclient pki scripts medsrv]) -ADD_PLUGIN([sha2], [s libcharon pluto openac scepclient pki scripts medsrv]) +ADD_PLUGIN([sha1], [s libcharon pluto openac scepclient pki scripts medsrv attest]) +ADD_PLUGIN([sha2], [s libcharon pluto openac scepclient pki scripts medsrv attest]) ADD_PLUGIN([md4], [s libcharon openac manager scepclient pki]) -ADD_PLUGIN([md5], [s libcharon pluto openac scepclient pki scripts]) -ADD_PLUGIN([random], [s libcharon pluto openac scepclient pki scripts medsrv]) -ADD_PLUGIN([x509], [s libcharon pluto openac scepclient pki scripts]) +ADD_PLUGIN([md5], [s libcharon pluto openac scepclient pki scripts attest]) +ADD_PLUGIN([random], [s libcharon pluto openac scepclient pki scripts medsrv attest]) +ADD_PLUGIN([x509], [s libcharon pluto openac scepclient pki scripts attest]) ADD_PLUGIN([revocation], [s libcharon]) ADD_PLUGIN([constraints], [s libcharon]) ADD_PLUGIN([pubkey], [s libcharon]) -ADD_PLUGIN([pkcs1], [s libcharon pluto openac scepclient pki scripts manager medsrv]) +ADD_PLUGIN([pkcs1], [s libcharon pluto openac scepclient pki scripts manager medsrv attest]) +ADD_PLUGIN([pkcs8], [s libcharon pluto openac scepclient pki scripts manager medsrv attest]) ADD_PLUGIN([pgp], [s libcharon pluto]) ADD_PLUGIN([dnskey], [s pluto]) -ADD_PLUGIN([pem], [s libcharon pluto openac scepclient pki scripts manager medsrv]) +ADD_PLUGIN([pem], [s libcharon pluto openac scepclient pki scripts manager medsrv attest]) ADD_PLUGIN([padlock], [s libcharon]) -ADD_PLUGIN([openssl], [s libcharon pluto openac scepclient pki scripts manager medsrv]) -ADD_PLUGIN([gcrypt], [s libcharon pluto openac scepclient pki scripts manager medsrv]) -ADD_PLUGIN([af-alg], [s libcharon pluto openac scepclient pki scripts medsrv]) +ADD_PLUGIN([openssl], [s libcharon pluto openac scepclient pki scripts manager medsrv attest]) +ADD_PLUGIN([gcrypt], [s libcharon pluto openac scepclient pki scripts manager medsrv attest]) +ADD_PLUGIN([af-alg], [s libcharon pluto openac scepclient pki scripts medsrv attest]) ADD_PLUGIN([fips-prf], [s libcharon]) -ADD_PLUGIN([gmp], [s libcharon pluto openac scepclient pki scripts manager medsrv]) +ADD_PLUGIN([gmp], [s libcharon pluto openac scepclient pki scripts manager medsrv attest]) ADD_PLUGIN([agent], [s libcharon]) ADD_PLUGIN([xcbc], [s libcharon]) ADD_PLUGIN([hmac], [s libcharon pluto scripts]) @@ -848,6 +878,7 @@ ADD_PLUGIN([eap-tnc], [c libcharon]) ADD_PLUGIN([xauth-generic], [c libcharon]) ADD_PLUGIN([xauth-eap], [c libcharon]) ADD_PLUGIN([tnc-ifmap], [c libcharon]) +ADD_PLUGIN([tnc-pdp], [c libcharon]) ADD_PLUGIN([tnc-imc], [c libcharon]) ADD_PLUGIN([tnc-imv], [c libcharon]) ADD_PLUGIN([tnc-tnccs], [c libcharon]) @@ -865,6 +896,7 @@ ADD_PLUGIN([certexpire], [c libcharon]) ADD_PLUGIN([led], [c libcharon]) ADD_PLUGIN([duplicheck], [c libcharon]) ADD_PLUGIN([coupling], [c libcharon]) +ADD_PLUGIN([radattr], [c libcharon]) ADD_PLUGIN([maemo], [c libcharon]) ADD_PLUGIN([uci], [c libcharon]) ADD_PLUGIN([addrblock], [c libcharon]) @@ -874,6 +906,7 @@ AC_SUBST(libcharon_plugins) AC_SUBST(pluto_plugins) AC_SUBST(starter_plugins) AC_SUBST(pool_plugins) +AC_SUBST(attest_plugins) AC_SUBST(openac_plugins) AC_SUBST(scepclient_plugins) AC_SUBST(pki_plugins) @@ -911,6 +944,7 @@ AM_CONDITIONAL(USE_REVOCATION, test x$revocation = xtrue) AM_CONDITIONAL(USE_CONSTRAINTS, test x$constraints = xtrue) AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue) AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue) +AM_CONDITIONAL(USE_PKCS8, test x$pkcs8 = xtrue) AM_CONDITIONAL(USE_PGP, test x$pgp = xtrue) AM_CONDITIONAL(USE_DNSKEY, test x$dnskey = xtrue) AM_CONDITIONAL(USE_PEM, test x$pem = xtrue) @@ -949,6 +983,7 @@ AM_CONDITIONAL(USE_CERTEXPIRE, test x$certexpire = xtrue) AM_CONDITIONAL(USE_LED, test x$led = xtrue) AM_CONDITIONAL(USE_DUPLICHECK, test x$duplicheck = xtrue) AM_CONDITIONAL(USE_COUPLING, test x$coupling = xtrue) +AM_CONDITIONAL(USE_RADATTR, test x$radattr = xtrue) AM_CONDITIONAL(USE_EAP_SIM, test x$eap_sim = xtrue) AM_CONDITIONAL(USE_EAP_SIM_FILE, test x$eap_sim_file = xtrue) AM_CONDITIONAL(USE_EAP_SIM_PCSC, test x$eap_sim_pcsc = xtrue) @@ -969,6 +1004,7 @@ AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue) AM_CONDITIONAL(USE_XAUTH_GENERIC, test x$xauth_generic = xtrue) AM_CONDITIONAL(USE_XAUTH_EAP, test x$xauth_eap = xtrue) AM_CONDITIONAL(USE_TNC_IFMAP, test x$tnc_ifmap = xtrue) +AM_CONDITIONAL(USE_TNC_PDP, test x$tnc_pdp = xtrue) AM_CONDITIONAL(USE_TNC_IMC, test x$tnc_imc = xtrue) AM_CONDITIONAL(USE_TNC_IMV, test x$tnc_imv = xtrue) AM_CONDITIONAL(USE_TNC_TNCCS, test x$tnc_tnccs = xtrue) @@ -1025,10 +1061,10 @@ AM_CONDITIONAL(USE_CHARON, test x$charon = xtrue) AM_CONDITIONAL(USE_TOOLS, test x$tools = xtrue) AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue) AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue) -AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pluto = xtrue -o x$tools = xtrue -o x$conftest = xtrue) +AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pluto = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue) AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$pluto = xtrue) AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue) -AM_CONDITIONAL(USE_LIBTNCIF, test x$charon = xtrue -o x$conftest = xtrue -o x$imcv = xtrue) +AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue) AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue) AM_CONDITIONAL(USE_FILE_CONFIG, test x$pluto = xtrue -o x$stroke = xtrue) AM_CONDITIONAL(USE_IPSEC_SCRIPT, test x$pluto = xtrue -o x$stroke = xtrue -o x$tools = xtrue -o x$conftest = xtrue) @@ -1036,6 +1072,7 @@ AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap) AM_CONDITIONAL(USE_VSTR, test x$vstr = xtrue) AM_CONDITIONAL(USE_SIMAKA, test x$simaka = xtrue) AM_CONDITIONAL(USE_TLS, test x$tls = xtrue) +AM_CONDITIONAL(USE_RADIUS, test x$radius = xtrue) AM_CONDITIONAL(USE_IMCV, test x$imcv = xtrue) AM_CONDITIONAL(USE_PTS, test x$pts = xtrue) AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue) @@ -1089,6 +1126,7 @@ AC_OUTPUT( src/libstrongswan/plugins/constraints/Makefile src/libstrongswan/plugins/pubkey/Makefile src/libstrongswan/plugins/pkcs1/Makefile + src/libstrongswan/plugins/pkcs8/Makefile src/libstrongswan/plugins/pgp/Makefile src/libstrongswan/plugins/dnskey/Makefile src/libstrongswan/plugins/pem/Makefile @@ -1118,16 +1156,17 @@ AC_OUTPUT( src/libfreeswan/Makefile src/libsimaka/Makefile src/libtls/Makefile + src/libradius/Makefile src/libtncif/Makefile src/libtnccs/Makefile src/libpts/Makefile + src/libpts/plugins/imc_attestation/Makefile + src/libpts/plugins/imv_attestation/Makefile src/libimcv/Makefile src/libimcv/plugins/imc_test/Makefile src/libimcv/plugins/imv_test/Makefile src/libimcv/plugins/imc_scanner/Makefile src/libimcv/plugins/imv_scanner/Makefile - src/libimcv/plugins/imc_attestation/Makefile - src/libimcv/plugins/imv_attestation/Makefile src/pluto/Makefile src/pluto/plugins/xauth/Makefile src/whack/Makefile @@ -1153,6 +1192,7 @@ AC_OUTPUT( src/libcharon/plugins/xauth_generic/Makefile src/libcharon/plugins/xauth_eap/Makefile src/libcharon/plugins/tnc_ifmap/Makefile + src/libcharon/plugins/tnc_pdp/Makefile src/libcharon/plugins/tnc_imc/Makefile src/libcharon/plugins/tnc_imv/Makefile src/libcharon/plugins/tnc_tnccs/Makefile @@ -1176,6 +1216,7 @@ AC_OUTPUT( src/libcharon/plugins/led/Makefile src/libcharon/plugins/duplicheck/Makefile src/libcharon/plugins/coupling/Makefile + src/libcharon/plugins/radattr/Makefile src/libcharon/plugins/android/Makefile src/libcharon/plugins/maemo/Makefile src/libcharon/plugins/stroke/Makefile diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index f6e2c227f..642499fc1 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -1,4 +1,4 @@ -.TH IPSEC.CONF 5 "2010-10-19" "@IPSEC_VERSION@" "strongSwan" +.TH IPSEC.CONF 5 "2011-12-14" "@IPSEC_VERSION@" "strongSwan" .SH NAME ipsec.conf \- IPsec configuration and connections .SH DESCRIPTION @@ -892,7 +892,7 @@ signifying that no IPsec processing should be done at all; signifying that packets should be discarded. .TP .BR xauth " = " client " | server" -specifies the role in the XAUTH protocol if activated by +specifies the role in the XAuth protocol if activated by .B authby=xauthpsk or .B authby=xauthrsasig. @@ -901,6 +901,10 @@ Accepted values are and .B client (the default). +.TP +.BR xauth_identity " = <id>" +defines the identity/username the client uses to reply to an XAuth request. +If not defined, the IKEv1 identity will be used as XAuth identity. .SS "CONN PARAMETERS: IKEv2 MEDIATION EXTENSION" The following parameters are relevant to IKEv2 Mediation Extension @@ -1029,7 +1033,7 @@ A comma separated list containing type/level-pairs may be specified, e.g: .B dmn 3, ike 1, net -1. Acceptable values for types are -.B dmn, mgr, ike, chd, job, cfg, knl, net, enc, lib, tls, tnc, imc, imv, pts +.B dmn, mgr, ike, chd, job, cfg, knl, net, asn, enc, lib, tls, tnc, imc, imv, pts and the level is one of .B -1, 0, 1, 2, 3, 4 (for silent, audit, control, controlmore, raw, private). By default, the level diff --git a/man/ipsec.secrets.5.in b/man/ipsec.secrets.5.in index 875b8e219..aa1b5c9c1 100644 --- a/man/ipsec.secrets.5.in +++ b/man/ipsec.secrets.5.in @@ -1,4 +1,4 @@ -.TH IPSEC.SECRETS 5 "2010-05-30" "@IPSEC_VERSION@" "strongSwan" +.TH IPSEC.SECRETS 5 "2011-12-14" "@IPSEC_VERSION@" "strongSwan" .SH NAME ipsec.secrets \- secrets for IKE/IPsec authentication .SH DESCRIPTION @@ -124,12 +124,17 @@ whitespace). .SS TYPES OF SECRETS .TP .B [ <selectors> ] : PSK <secret> -A preshared secret is most conveniently represented as a sequence of -characters, delimited by double-quote characters (\fB"\fP). -The sequence cannot contain a newline or double-quote. -Strictly speaking, the secret is actually the sequence -of bytes that is used in the file to represent the sequence of -characters (excluding the delimiters). +A preshared \fIsecret\fP is most conveniently represented as a sequence of +characters, which is delimited by double-quote characters (\fB"\fP). +The sequence cannot contain newline or double-quote characters. +.br +Alternatively, preshared secrets can be represented as hexadecimal or Base64 +encoded binary values. A character sequence beginning with +.B 0x +is interpreted as sequence of hexadecimal digits. +Similarly, a character sequence beginning with +.B 0s +is interpreted as Base64 encoded binary data. .TP .B [ <selectors> ] : RSA <private key file> [ <passphrase> | %prompt ] .TQ @@ -142,12 +147,12 @@ can be used which then causes the daemons to ask the user for the password whenever it is required to decrypt the key. .TP .B <user id> : EAP <secret> -As with \fBPSK\fP secrets the \fIsecret\fP is a sequence of characters, -delimited by double-quote characters (\fB"\fP). +The format of \fIsecret\fP is the same as that of \fBPSK\fP secrets. .br \fBEAP\fP secrets are IKEv2 only. .TP .B [ <servername> ] <username> : XAUTH <password> +The format of \fIpassword\fP is the same as that of \fBPSK\fP secrets. \fBXAUTH\fP secrets are IKEv1 only. .TP .B : PIN <smartcard selector> <pin code> | %prompt diff --git a/man/strongswan.conf.5.in b/man/strongswan.conf.5.in index fdc13c172..12528565c 100644 --- a/man/strongswan.conf.5.in +++ b/man/strongswan.conf.5.in @@ -126,6 +126,13 @@ will return The following keys are currently defined (using dot notation). The default value (if any) is listed in brackets after the key. +.SS attest section +.TP +.BR attest.database +Path to database with file measurement information +.TP +.BR attest.load +Plugins to load in ipsec attest tool .SS charon section .TP .BR charon.block_threshold " [5]" @@ -306,6 +313,9 @@ Start phase2 EAP TNC protocol after successful client authentication Request peer authentication based on a client certificate .TP +.BR charon.plugins.eap-radius.accounting " [no]" +Send RADIUS accounting information to RADIUS servers. +.TP .BR charon.plugins.eap-radius.class_group " [no]" Use the .I class @@ -466,6 +476,13 @@ Database URI for charons SQL plugin .BR charon.plugins.sql.loglevel " [-1]" Loglevel for logging to SQL database .TP +.BR charon.plugins.stroke.ignore_missing_ca_basic_constraint " [no]" +Treat certificates in ipsec.d/cacerts and ipsec.conf ca sections as CA +certificates even if they don't contain a CA basic constraint. +.TP +.BR charon.plugins.stroke.max_concurrent " [4]" +Maximum number of stroke messages handled concurrently +.TP .BR charon.plugins.tnc-ifmap.device_name Unique name of strongSwan as a PEP and/or PDP device .TP @@ -487,6 +504,18 @@ Authentication username of strongSwan MAP client .BR charon.plugins.tnc-imc.preferred_language " [en]" Preferred language for TNC recommendations .TP +.BR charon.plugins.tnc-pdp.method " [ttls]" +EAP tunnel method to be used +.TP +.BR charon.plugins.tnc-pdp.port " [1812]" +RADIUS server port the strongSwan PDP is listening on +.TP +.BR charon.plugins.tnc-pdp.secret +Shared RADIUS secret between strongSwan PDP and NAS +.TP +.BR charon.plugins.tnc-pdp.server +name of the strongSwan PDP as contained in the AAA certificate +.TP .BR charon.plugins.whitelist.enable " [yes]" enable loaded whitelist plugin .SS libstrongswan section @@ -580,21 +609,36 @@ Disable output to stderr with a stand-alone libimcv library .BR libimcv.plugins.imc-attestation.platform_info Information on operating system and hardware platform .TP +.BR libimcv.plugins.imc-attestation.aik_blob +AIK encrypted private key blob file +.TP .BR libimcv.plugins.imc-attestation.aik_cert AIK certificate file .TP .BR libimcv.plugins.imc-attestation.aik_key AIK public key file .TP +.BR libimcv.plugins.imv-attestation.nonce_len " [20]" +DH nonce length +.TP +.BR libimcv.plugins.imv-attestation.use_quote2 " [yes]" +Use Quote2 AIK signature instead of Quote signature +.TP .BR libimcv.plugins.imv-attestation.cadir Path to directory with AIK cacerts .TP .BR libimcv.plugins.imv-attestation.database Path to database with file measurement information .TP -.BR libimcv.plugins.imv-attestation.hash_algorithm " [sha1]" +.BR libimcv.plugins.imv-attestation.dh_group " [ecp256]" +Preferred Diffie-Hellman group +.TP +.BR libimcv.plugins.imv-attestation.hash_algorithm " [sha256]" Preferred measurement hash algorithm .TP +.BR libimcv.plugins.imv-attestation.min_nonce_len " [0]" +DH minimum nonce length +.TP .BR libimcv.plugins.imv-attestation.platform_info Information on operating system and hardware platform .TP @@ -607,6 +651,9 @@ List of TCP ports that can be open or must be closed .BR libimcv.plugins.imv-scanner.udp_ports List of UDP ports that can be open or must be closed .TP +.BR libimcv.plugins.imc-test.additional_ids " [0]" +Number of additional IMC IDs +.TP .BR libimcv.plugins.imc-test.command " [none]" Command to be sent to the Test IMV .TP @@ -827,6 +874,9 @@ IPsec/Networking kernel interface .B net IKE network communication .TP +.B asn +Low-level encoding/decoding (ASN.1, X.509 etc.) +.TP .B enc Packet encoding/decoding encryption/decryption operations .TP diff --git a/packages/maemo-strongswan/debian/changelog b/packages/maemo-strongswan/debian/changelog index 3a17de219..fa7ab3966 100644 --- a/packages/maemo-strongswan/debian/changelog +++ b/packages/maemo-strongswan/debian/changelog @@ -1,3 +1,9 @@ +strongswan (4.6.2-1) unstable; urgency=low + + * New upstream release + + -- Tobias Brunner <tobias@strongswan.org> Mon, 27 Feb 2012 17:29:05 +0100 + strongswan (4.6.0-1) unstable; urgency=low * New upstream release diff --git a/scripts/tls_test.c b/scripts/tls_test.c index b4d11e624..560c4a4ba 100644 --- a/scripts/tls_test.c +++ b/scripts/tls_test.c @@ -18,6 +18,8 @@ #include <sys/types.h> #include <sys/socket.h> #include <getopt.h> +#include <errno.h> +#include <string.h> #include <library.h> #include <debug.h> @@ -31,127 +33,102 @@ static void usage(FILE *out, char *cmd) { fprintf(out, "usage:\n"); - fprintf(out, " %s --connect <address> --port <port> [--cert <file>]+\n", cmd); - fprintf(out, " %s --listen <address> --port <port> --key <key> [--cert <file>]+ --oneshot\n", cmd); + fprintf(out, " %s --connect <address> --port <port> [--cert <file>]+ [--times <n>]\n", cmd); + fprintf(out, " %s --listen <address> --port <port> --key <key> [--cert <file>]+ [--times <n>]\n", cmd); } /** - * Stream between stdio and TLS socket + * Client routine */ -static int stream(int fd, tls_socket_t *tls) +static int client(host_t *host, identification_t *server, + int times, tls_cache_t *cache) { - while (TRUE) - { - fd_set set; - chunk_t data; - - FD_ZERO(&set); - FD_SET(fd, &set); - FD_SET(0, &set); + tls_socket_t *tls; + int fd, res; - if (select(fd + 1, &set, NULL, NULL, NULL) == -1) + while (times == -1 || times-- > 0) + { + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + DBG1(DBG_TLS, "opening socket failed: %s", strerror(errno)); return 1; } - if (FD_ISSET(fd, &set)) + if (connect(fd, host->get_sockaddr(host), + *host->get_sockaddr_len(host)) == -1) { - if (!tls->read(tls, &data)) - { - DBG1(DBG_TLS, "TLS read error/end\n"); - return 1; - } - if (data.len) - { - ignore_result(write(1, data.ptr, data.len)); - free(data.ptr); - } + DBG1(DBG_TLS, "connecting to %#H failed: %s", host, strerror(errno)); + close(fd); + return 1; } - if (FD_ISSET(0, &set)) + tls = tls_socket_create(FALSE, server, NULL, fd, cache); + if (!tls) { - char buf[1024]; - ssize_t len; - - len = read(0, buf, sizeof(buf)); - if (len == 0) - { - return 0; - } - if (len > 0) - { - if (!tls->write(tls, chunk_create(buf, len))) - { - DBG1(DBG_TLS, "TLS write error\n"); - return 1; - } - } + close(fd); + return 1; + } + res = tls->splice(tls, 0, 1) ? 0 : 1; + tls->destroy(tls); + close(fd); + if (res) + { + break; } } + return res; } /** - * Client routine + * Server routine */ -static int client(int fd, host_t *host, identification_t *server) +static int serve(host_t *host, identification_t *server, + int times, tls_cache_t *cache) { tls_socket_t *tls; - int res; + int fd, cfd; - if (connect(fd, host->get_sockaddr(host), - *host->get_sockaddr_len(host)) == -1) - { - DBG1(DBG_TLS, "connecting to %#H failed: %m\n", host); - return 1; - } - tls = tls_socket_create(FALSE, server, NULL, fd); - if (!tls) + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + DBG1(DBG_TLS, "opening socket failed: %s", strerror(errno)); return 1; } - res = stream(fd, tls); - tls->destroy(tls); - return res; -} - -/** - * Server routine - */ -static int serve(int fd, host_t *host, identification_t *server, bool oneshot) -{ - tls_socket_t *tls; - int cfd; - if (bind(fd, host->get_sockaddr(host), *host->get_sockaddr_len(host)) == -1) { - DBG1(DBG_TLS, "binding to %#H failed: %m\n", host); + DBG1(DBG_TLS, "binding to %#H failed: %s", host, strerror(errno)); + close(fd); return 1; } if (listen(fd, 1) == -1) { - DBG1(DBG_TLS, "listen to %#H failed: %m\n", host); + DBG1(DBG_TLS, "listen to %#H failed: %m", host, strerror(errno)); + close(fd); return 1; } - do + while (times == -1 || times-- > 0) { cfd = accept(fd, host->get_sockaddr(host), host->get_sockaddr_len(host)); if (cfd == -1) { - DBG1(DBG_TLS, "accept failed: %m\n"); + DBG1(DBG_TLS, "accept failed: %s", strerror(errno)); + close(fd); return 1; } - DBG1(DBG_TLS, "%#H connected\n", host); + DBG1(DBG_TLS, "%#H connected", host); - tls = tls_socket_create(TRUE, server, NULL, cfd); + tls = tls_socket_create(TRUE, server, NULL, cfd, cache); if (!tls) { + close(fd); return 1; } - stream(cfd, tls); - DBG1(DBG_TLS, "%#H disconnected\n", host); + tls->splice(tls, 0, 1); + DBG1(DBG_TLS, "%#H disconnected", host); tls->destroy(tls); } - while (!oneshot); + close(fd); return 0; } @@ -172,7 +149,7 @@ static bool load_certificate(char *filename) BUILD_FROM_FILE, filename, BUILD_END); if (!cert) { - DBG1(DBG_TLS, "loading certificate from '%s' failed\n", filename); + DBG1(DBG_TLS, "loading certificate from '%s' failed", filename); return FALSE; } creds->add_cert(creds, TRUE, cert); @@ -190,7 +167,7 @@ static bool load_key(char *filename) BUILD_FROM_FILE, filename, BUILD_END); if (!key) { - DBG1(DBG_TLS, "loading key from '%s' failed\n", filename); + DBG1(DBG_TLS, "loading key from '%s' failed", filename); return FALSE; } creds->add_key(creds, key); @@ -245,9 +222,10 @@ static void init() int main(int argc, char *argv[]) { char *address = NULL; - bool listen = FALSE, oneshot = FALSE; - int port = 0, fd, res; + bool listen = FALSE; + int port = 0, times = -1, res; identification_t *server; + tls_cache_t *cache; host_t *host; init(); @@ -261,7 +239,7 @@ int main(int argc, char *argv[]) {"port", required_argument, NULL, 'p' }, {"cert", required_argument, NULL, 'x' }, {"key", required_argument, NULL, 'k' }, - {"oneshot", no_argument, NULL, 'o' }, + {"times", required_argument, NULL, 't' }, {"debug", required_argument, NULL, 'd' }, {0,0,0,0 } }; @@ -298,8 +276,8 @@ int main(int argc, char *argv[]) case 'p': port = atoi(optarg); continue; - case 'o': - oneshot = TRUE; + case 't': + times = atoi(optarg); continue; case 'd': tls_level = atoi(optarg); @@ -315,35 +293,23 @@ int main(int argc, char *argv[]) usage(stderr, argv[0]); return 1; } - if (oneshot && !listen) - { - usage(stderr, argv[0]); - return 1; - } - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - DBG1(DBG_TLS, "opening socket failed: %m\n"); - return 1; - } host = host_create_from_dns(address, 0, port); if (!host) { - DBG1(DBG_TLS, "resolving hostname %s failed\n", address); - close(fd); + DBG1(DBG_TLS, "resolving hostname %s failed", address); return 1; } server = identification_create_from_string(address); + cache = tls_cache_create(100, 30); if (listen) { - res = serve(fd, host, server, oneshot); + res = serve(host, server, times, cache); } else { - res = client(fd, host, server); + res = client(host, server, times, cache); } - close(fd); + cache->destroy(cache); host->destroy(host); server->destroy(server); return res; diff --git a/src/Makefile.am b/src/Makefile.am index 5e85a5f88..1440de20f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,10 @@ if USE_TLS SUBDIRS += libtls endif +if USE_RADIUS + SUBDIRS += libradius +endif + if USE_LIBTNCIF SUBDIRS += libtncif endif @@ -24,14 +28,14 @@ if USE_LIBTNCCS SUBDIRS += libtnccs endif -if USE_PTS - SUBDIRS += libpts -endif - if USE_IMCV SUBDIRS += libimcv endif +if USE_PTS + SUBDIRS += libpts +endif + if USE_LIBCHARON SUBDIRS += libcharon endif diff --git a/src/charon/Android.mk b/src/charon/Android.mk index 491d7f946..eb7eca9dd 100644 --- a/src/charon/Android.mk +++ b/src/charon/Android.mk @@ -17,6 +17,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := charon +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/charon/charon.c b/src/charon/charon.c index 141403b89..7a269d7f0 100644 --- a/src/charon/charon.c +++ b/src/charon/charon.c @@ -426,7 +426,7 @@ static void usage(const char *msg) " [--version]\n" " [--use-syslog]\n" " [--debug-<type> <level>]\n" - " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|enc|tnc|imc|imv|pts|tls|lib)\n" + " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|lib)\n" " <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n" " 2 = controlmore, 3 = raw, 4 = private)\n" "\n" @@ -497,6 +497,7 @@ int main(int argc, char *argv[]) { "debug-cfg", required_argument, &group, DBG_CFG }, { "debug-knl", required_argument, &group, DBG_KNL }, { "debug-net", required_argument, &group, DBG_NET }, + { "debug-asn", required_argument, &group, DBG_ASN }, { "debug-enc", required_argument, &group, DBG_ENC }, { "debug-tnc", required_argument, &group, DBG_TNC }, { "debug-imc", required_argument, &group, DBG_IMC }, diff --git a/src/checksum/Makefile.am b/src/checksum/Makefile.am index 036a63715..58292a45a 100644 --- a/src/checksum/Makefile.am +++ b/src/checksum/Makefile.am @@ -45,6 +45,11 @@ if USE_TLS libs += $(DESTDIR)$(ipseclibdir)/libtls.so endif +if USE_RADIUS + deps += $(top_builddir)/src/libradius/libradius.la + libs += $(DESTDIR)$(ipseclibdir)/libradius.so +endif + if USE_LIBTNCCS deps += $(top_builddir)/src/libtnccs/libtnccs.la libs += $(DESTDIR)$(ipseclibdir)/libtnccs.so @@ -55,6 +60,16 @@ if USE_SIMAKA libs += $(DESTDIR)$(ipseclibdir)/libsimaka.so endif +if USE_IMCV + deps += $(top_builddir)/src/libimcv/libimcv.la + libs += $(DESTDIR)$(ipseclibdir)/libimcv.so +endif + +if USE_PTS + deps += $(top_builddir)/src/libpts/libpts.la + libs += $(DESTDIR)$(ipseclibdir)/libpts.so +endif + if USE_CHARON deps += $(top_builddir)/src/libcharon/libcharon.la libs += $(DESTDIR)$(ipseclibdir)/libcharon.so @@ -79,6 +94,10 @@ if USE_ATTR_SQL exes += $(top_builddir)/src/libhydra/plugins/attr_sql/.libs/pool endif +if USE_IMV_ATTESTATION + exes += $(top_builddir)/src/libpts/plugins/imv_attestation/.libs/attest +endif + checksum.c : checksum_builder $(deps) $(exes) ./checksum_builder $(libs) $(exes) > checksum.c diff --git a/src/checksum/checksum_builder.c b/src/checksum/checksum_builder.c index 8311d9a39..670ec76bd 100644 --- a/src/checksum/checksum_builder.c +++ b/src/checksum/checksum_builder.c @@ -151,7 +151,8 @@ int main(int argc, char* argv[]) printf("\n"); printf("integrity_checksum_t checksums[] = {\n"); fprintf(stderr, "integrity test data:\n"); - fprintf(stderr, "module name, file size / checksum segment size / checksum\n"); + fprintf(stderr, "module name, file size / checksum " + "segment size / checksum\n"); for (i = 1; i < argc; i++) { build_binary_checksum(argv[i]); diff --git a/src/ipsec/Android.mk b/src/ipsec/Android.mk index b6a7c714d..d134f7fd2 100644 --- a/src/ipsec/Android.mk +++ b/src/ipsec/Android.mk @@ -5,6 +5,8 @@ include $(CLEAR_VARS) LOCAL_MODULE := ipsec +LOCAL_MODULE_TAGS := optional + LOCAL_MODULE_CLASS := EXECUTABLES GEN := $(local-intermediates-dir)/ipsec diff --git a/src/ipsec/Makefile.am b/src/ipsec/Makefile.am index 8420e1ace..bbf009721 100644 --- a/src/ipsec/Makefile.am +++ b/src/ipsec/Makefile.am @@ -1,7 +1,7 @@ sbin_SCRIPTS = ipsec CLEANFILES = ipsec ipsec.8 dist_man8_MANS = ipsec.8 -EXTRA_DIST = ipsec.in ipsec.8.in +EXTRA_DIST = ipsec.in ipsec.8.in Android.mk ipsec.8 : ipsec.8.in sed \ diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk index 3ba8307c8..f98d36a61 100644 --- a/src/libcharon/Android.mk +++ b/src/libcharon/Android.mk @@ -132,6 +132,8 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libsimaka/ LOCAL_SRC_FILES += $(addprefix ../libsimaka/, \ simaka_message.h simaka_message.c \ simaka_crypto.h simaka_crypto.c \ + simaka_manager.h simaka_manager.c \ + simaka_card.h simaka_provider.h simaka_hooks.h \ ) endif @@ -163,6 +165,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) \ LOCAL_MODULE := libcharon +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index d5e139412..a322b0cce 100755 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -360,6 +360,13 @@ if MONOLITHIC endif endif +if USE_RADIUS +if MONOLITHIC + # otherwise this library is linked to eap_radius + libcharon_la_LIBADD += $(top_builddir)/src/libradius/libradius.la +endif +endif + if USE_TNC_IFMAP SUBDIRS += plugins/tnc_ifmap if MONOLITHIC @@ -367,6 +374,13 @@ if MONOLITHIC endif endif +if USE_TNC_PDP + SUBDIRS += plugins/tnc_pdp +if MONOLITHIC + libcharon_la_LIBADD += plugins/tnc_pdp/libstrongswan-tnc-pdp.la +endif +endif + if USE_TNC_IMC SUBDIRS += plugins/tnc_imc if MONOLITHIC @@ -500,6 +514,13 @@ if MONOLITHIC endif endif +if USE_RADATTR + SUBDIRS += plugins/radattr +if MONOLITHIC + libcharon_la_LIBADD += plugins/radattr/libstrongswan-radattr.la +endif +endif + if USE_UCI SUBDIRS += plugins/uci if MONOLITHIC diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index 343063be5..575627206 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -111,6 +111,12 @@ static void destroy(private_daemon_t *this) } DESTROY_IF(this->public.receiver); DESTROY_IF(this->public.sender); +#ifdef ME + DESTROY_IF(this->public.connect_manager); + DESTROY_IF(this->public.mediation_manager); +#endif /* ME */ + /* make sure the cache is clear before unloading plugins */ + lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); /* unload plugins to release threads */ lib->plugins->unload(lib->plugins); #ifdef CAPABILITIES_LIBCAP @@ -123,10 +129,6 @@ static void destroy(private_daemon_t *this) DESTROY_IF(this->public.controller); DESTROY_IF(this->public.eap); DESTROY_IF(this->public.xauth); -#ifdef ME - DESTROY_IF(this->public.connect_manager); - DESTROY_IF(this->public.mediation_manager); -#endif /* ME */ DESTROY_IF(this->public.backends); DESTROY_IF(this->public.socket); @@ -200,27 +202,6 @@ METHOD(daemon_t, start, void, DEFAULT_THREADS)); } -/** - * Log loaded plugins - */ -static void print_plugins() -{ - char buf[512]; - int len = 0; - enumerator_t *enumerator; - plugin_t *plugin; - - buf[0] = '\0'; - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (len < sizeof(buf) && enumerator->enumerate(enumerator, &plugin, NULL)) - { - len += snprintf(&buf[len], sizeof(buf)-len, "%s ", - plugin->get_name(plugin)); - } - enumerator->destroy(enumerator); - DBG1(DBG_DMN, "loaded plugins: %s", buf); -} - METHOD(daemon_t, initialize, bool, private_daemon_t *this) { @@ -241,8 +222,8 @@ METHOD(daemon_t, initialize, bool, { return FALSE; } - - print_plugins(); + DBG1(DBG_DMN, "loaded plugins: %s", + lib->plugins->loaded_plugins(lib->plugins)); this->public.ike_sa_manager = ike_sa_manager_create(); if (this->public.ike_sa_manager == NULL) diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index ade2d945f..411534491 100755 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -115,15 +115,16 @@ ENUM_NEXT(notify_type_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THE "UNITY_LOAD_BALANCE"); ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE, "USE_BEET_MODE"); -ENUM_NEXT(notify_type_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, +ENUM_NEXT(notify_type_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE, "ME_MEDIATION", "ME_ENDPOINT", "ME_CALLBACK", "ME_CONNECTID", "ME_CONNECTKEY", "ME_CONNECTAUTH", - "ME_RESPONSE"); -ENUM_END(notify_type_names, ME_RESPONSE); + "ME_RESPONSE", + "RADIUS_ATTRIBUTE",); +ENUM_END(notify_type_names, RADIUS_ATTRIBUTE); ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD, @@ -216,15 +217,16 @@ ENUM_NEXT(notify_type_short_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R "UNITY_LB"); ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE, "BEET_MODE"); -ENUM_NEXT(notify_type_short_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, +ENUM_NEXT(notify_type_short_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE, "ME_MED", "ME_EP", "ME_CB", "ME_CID", "ME_CKEY", "ME_CAUTH", - "ME_R"); -ENUM_END(notify_type_short_names, ME_RESPONSE); + "ME_R", + "RADIUS"); +ENUM_END(notify_type_short_names, RADIUS_ATTRIBUTE); typedef struct private_notify_payload_t private_notify_payload_t; diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index 58d85ffae..07fbcb49b 100755 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -154,7 +154,9 @@ enum notify_type_t { ME_CONNECTID = 40965, ME_CONNECTKEY = 40966, ME_CONNECTAUTH = 40967, - ME_RESPONSE = 40968 + ME_RESPONSE = 40968, + /* RADIUS attribute received/to send to a AAA backend */ + RADIUS_ATTRIBUTE = 40969, }; /** diff --git a/src/libcharon/plugins/eap_peap/eap_peap.c b/src/libcharon/plugins/eap_peap/eap_peap.c index 5bae0fa9b..bd426bba7 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap.c +++ b/src/libcharon/plugins/eap_peap/eap_peap.c @@ -166,7 +166,8 @@ static eap_peap_t *eap_peap_create(private_eap_peap_t * this, "charon.plugins.eap-peap.max_message_count", MAX_MESSAGE_COUNT); include_length = lib->settings->get_bool(lib->settings, "charon.plugins.eap-peap.include_length", FALSE); - tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_PEAP, application); + tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_PEAP, + application, NULL); this->tls_eap = tls_eap_create(EAP_PEAP, tls, frag_size, max_msg_count, include_length); if (!this->tls_eap) diff --git a/src/libcharon/plugins/eap_radius/Makefile.am b/src/libcharon/plugins/eap_radius/Makefile.am index afc50bced..181497ab5 100644 --- a/src/libcharon/plugins/eap_radius/Makefile.am +++ b/src/libcharon/plugins/eap_radius/Makefile.am @@ -1,21 +1,21 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libcharon + -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libradius AM_CFLAGS = -rdynamic if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-eap-radius.la else +libstrongswan_eap_radius_la_LIBADD = $(top_builddir)/src/libradius/libradius.la plugin_LTLIBRARIES = libstrongswan-eap-radius.la endif libstrongswan_eap_radius_la_SOURCES = \ eap_radius_plugin.h eap_radius_plugin.c \ eap_radius.h eap_radius.c \ - radius_server.h radius_server.c \ - radius_socket.h radius_socket.c \ - radius_client.h radius_client.c \ - radius_message.h radius_message.c + eap_radius_accounting.h eap_radius_accounting.c \ + eap_radius_dae.h eap_radius_dae.c \ + eap_radius_forward.h eap_radius_forward.c libstrongswan_eap_radius_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c index dfe0e2e09..c0a3703b6 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.c +++ b/src/libcharon/plugins/eap_radius/eap_radius.c @@ -14,14 +14,14 @@ */ #include "eap_radius.h" +#include "eap_radius_plugin.h" +#include "eap_radius_forward.h" -#include "radius_message.h" -#include "radius_client.h" +#include <radius_message.h> +#include <radius_client.h> #include <daemon.h> -#define TUNNEL_TYPE_ESP 9 - typedef struct private_eap_radius_t private_eap_radius_t; /** @@ -162,7 +162,7 @@ METHOD(eap_method_t, initiate, status_t, status_t status = FAILED; chunk_t username; - request = radius_message_create_request(); + request = radius_message_create(RMC_ACCESS_REQUEST); username = chunk_create(this->id_prefix, strlen(this->id_prefix)); username = chunk_cata("cc", username, this->peer->get_encoding(this->peer)); request->add(request, RAT_USER_NAME, username); @@ -175,16 +175,22 @@ METHOD(eap_method_t, initiate, status_t, { add_eap_identity(this, request); } + eap_radius_forward_from_ike(request); response = this->client->request(this->client, request); if (response) { + eap_radius_forward_to_ike(response); if (radius2ike(this, response, out)) { status = NEED_MORE; } response->destroy(response); } + else + { + charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING); + } request->destroy(request); return status; } @@ -253,7 +259,7 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg) tunnel_type = untoh32(data.ptr); DBG1(DBG_IKE, "received RADIUS attribute Tunnel-Type: " "tag = %u, value = %u", tunnel_tag, tunnel_type); - is_esp_tunnel = (tunnel_type == TUNNEL_TYPE_ESP); + is_esp_tunnel = (tunnel_type == RADIUS_TUNNEL_TYPE_ESP); break; case RAT_FILTER_ID: filter_id = data; @@ -282,6 +288,31 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg) } } +/** + * Handle Session-Timeout attribte + */ +static void process_timeout(private_eap_radius_t *this, radius_message_t *msg) +{ + enumerator_t *enumerator; + ike_sa_t *ike_sa; + chunk_t data; + int type; + + enumerator = msg->create_enumerator(msg); + while (enumerator->enumerate(enumerator, &type, &data)) + { + if (type == RAT_SESSION_TIMEOUT && data.len == 4) + { + ike_sa = charon->bus->get_sa(charon->bus); + if (ike_sa) + { + ike_sa->set_auth_lifetime(ike_sa, untoh32(data.ptr)); + } + } + } + enumerator->destroy(enumerator); +} + METHOD(eap_method_t, process, status_t, private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out) { @@ -289,22 +320,25 @@ METHOD(eap_method_t, process, status_t, status_t status = FAILED; chunk_t data; - request = radius_message_create_request(); + request = radius_message_create(RMC_ACCESS_REQUEST); request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer)); data = in->get_data(in); DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &data); - - /* fragment data suitable for RADIUS (not more than 253 bytes) */ - while (data.len > 253) + + /* fragment data suitable for RADIUS */ + while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE) { - request->add(request, RAT_EAP_MESSAGE, chunk_create(data.ptr, 253)); - data = chunk_skip(data, 253); + request->add(request, RAT_EAP_MESSAGE, + chunk_create(data.ptr,MAX_RADIUS_ATTRIBUTE_SIZE)); + data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE); } request->add(request, RAT_EAP_MESSAGE, data); + eap_radius_forward_from_ike(request); response = this->client->request(this->client, request); if (response) { + eap_radius_forward_to_ike(response); switch (response->get_code(response)) { case RMC_ACCESS_CHALLENGE: @@ -324,6 +358,7 @@ METHOD(eap_method_t, process, status_t, { process_filter_id(this, response); } + process_timeout(this, response); DBG1(DBG_IKE, "RADIUS authentication of '%Y' successful", this->peer); status = SUCCESS; @@ -427,7 +462,7 @@ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer "charon.plugins.eap-radius.filter_id", FALSE), ); - this->client = radius_client_create(); + this->client = eap_radius_create_client(); if (!this->client) { free(this); diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c new file mode 100644 index 000000000..243c76304 --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_radius_accounting.h" +#include "eap_radius_plugin.h" + +#include <time.h> + +#include <radius_message.h> +#include <radius_client.h> +#include <daemon.h> +#include <utils/hashtable.h> +#include <threading/mutex.h> + +typedef struct private_eap_radius_accounting_t private_eap_radius_accounting_t; + +/** + * Private data of an eap_radius_accounting_t object. + */ +struct private_eap_radius_accounting_t { + + /** + * Public eap_radius_accounting_t interface. + */ + eap_radius_accounting_t public; + + /** + * Hashtable with sessions, IKE_SA unique id => entry_t + */ + hashtable_t *sessions; + + /** + * Mutex to lock sessions + */ + mutex_t *mutex; + + /** + * Session ID prefix + */ + u_int32_t prefix; +}; + +/** + * Hashtable entry with usage stats + */ +typedef struct { + /** RADIUS accounting session ID */ + char sid[16]; + /** number of octets sent */ + u_int64_t sent; + /** number of octets received */ + u_int64_t received; + /** session creation time */ + time_t created; +} entry_t; + +/** + * Accounting message status types + */ +typedef enum { + ACCT_STATUS_START = 1, + ACCT_STATUS_STOP = 2, + ACCT_STATUS_INTERIM_UPDATE = 3, + ACCT_STATUS_ACCOUNTING_ON = 7, + ACCT_STATUS_ACCOUNTING_OFF = 8, +} radius_acct_status_t; + +/** + * Hashtable hash function + */ +static u_int hash(uintptr_t key) +{ + return key; +} + +/** + * Hashtable equals function + */ +static bool equals(uintptr_t a, uintptr_t b) +{ + return a == b; +} + +/** + * Update usage counter when a CHILD_SA rekeys/goes down + */ +static void update_usage(private_eap_radius_accounting_t *this, + ike_sa_t *ike_sa, child_sa_t *child_sa) +{ + u_int64_t sent, received; + entry_t *entry; + + child_sa->get_usestats(child_sa, FALSE, NULL, &sent); + child_sa->get_usestats(child_sa, TRUE, NULL, &received); + + this->mutex->lock(this->mutex); + entry = this->sessions->get(this->sessions, + (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa)); + if (entry) + { + entry->sent += sent; + entry->received += received; + } + this->mutex->unlock(this->mutex); +} + +/** + * Send a RADIUS message, wait for response + */ +static bool send_message(private_eap_radius_accounting_t *this, + radius_message_t *request) +{ + radius_message_t *response; + radius_client_t *client; + bool ack = FALSE; + + client = eap_radius_create_client(); + if (client) + { + response = client->request(client, request); + if (response) + { + ack = response->get_code(response) == RMC_ACCOUNTING_RESPONSE; + response->destroy(response); + } + else + { + charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING); + } + client->destroy(client); + } + return ack; +} + +/** + * Add common IKE_SA parameters to RADIUS account message + */ +static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa) +{ + host_t *vip; + char buf[64]; + chunk_t data; + + snprintf(buf, sizeof(buf), "%Y", ike_sa->get_other_eap_id(ike_sa)); + message->add(message, RAT_USER_NAME, chunk_create(buf, strlen(buf))); + snprintf(buf, sizeof(buf), "%#H", ike_sa->get_other_host(ike_sa)); + message->add(message, RAT_CALLING_STATION_ID, chunk_create(buf, strlen(buf))); + vip = ike_sa->get_virtual_ip(ike_sa, FALSE); + if (vip && vip->get_family(vip) == AF_INET) + { + message->add(message, RAT_FRAMED_IP_ADDRESS, vip->get_address(vip)); + } + if (vip && vip->get_family(vip) == AF_INET6) + { + /* we currently assign /128 prefixes, only (reserved, length) */ + data = chunk_from_chars(0, 128); + data = chunk_cata("cc", data, vip->get_address(vip)); + message->add(message, RAT_FRAMED_IPV6_PREFIX, data); + } +} + +/** + * Send an accounting start message + */ +static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa) +{ + radius_message_t *message; + entry_t *entry; + u_int32_t id, value; + + id = ike_sa->get_unique_id(ike_sa); + INIT(entry, + .created = time_monotonic(NULL), + ); + snprintf(entry->sid, sizeof(entry->sid), "%u-%u", this->prefix, id); + + message = radius_message_create(RMC_ACCOUNTING_REQUEST); + value = htonl(ACCT_STATUS_START); + message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value)); + message->add(message, RAT_ACCT_SESSION_ID, + chunk_create(entry->sid, strlen(entry->sid))); + add_ike_sa_parameters(message, ike_sa); + if (send_message(this, message)) + { + this->mutex->lock(this->mutex); + entry = this->sessions->put(this->sessions, (void*)(uintptr_t)id, entry); + this->mutex->unlock(this->mutex); + free(entry); + } + message->destroy(message); +} + +/** + * Send an account stop message + */ +static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa) +{ + radius_message_t *message; + entry_t *entry; + u_int32_t id, value; + + id = ike_sa->get_unique_id(ike_sa); + this->mutex->lock(this->mutex); + entry = this->sessions->remove(this->sessions, (void*)(uintptr_t)id); + this->mutex->unlock(this->mutex); + if (entry) + { + message = radius_message_create(RMC_ACCOUNTING_REQUEST); + value = htonl(ACCT_STATUS_STOP); + message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value)); + message->add(message, RAT_ACCT_SESSION_ID, + chunk_create(entry->sid, strlen(entry->sid))); + add_ike_sa_parameters(message, ike_sa); + value = htonl(entry->sent); + message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value)); + value = htonl(entry->sent >> 32); + if (value) + { + message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS, + chunk_from_thing(value)); + } + value = htonl(entry->received); + message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value)); + value = htonl(entry->received >> 32); + if (value) + { + message->add(message, RAT_ACCT_INPUT_GIGAWORDS, + chunk_from_thing(value)); + } + value = htonl(time_monotonic(NULL) - entry->created); + message->add(message, RAT_ACCT_SESSION_TIME, chunk_from_thing(value)); + + send_message(this, message); + message->destroy(message); + free(entry); + } +} + +METHOD(listener_t, ike_updown, bool, + private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, bool up) +{ + if (!up) + { + enumerator_t *enumerator; + child_sa_t *child_sa; + + /* update usage for all children just before sending stop */ + enumerator = ike_sa->create_child_sa_enumerator(ike_sa); + while (enumerator->enumerate(enumerator, &child_sa)) + { + update_usage(this, ike_sa, child_sa); + } + enumerator->destroy(enumerator); + + send_stop(this, ike_sa); + } + return TRUE; +} + +METHOD(listener_t, message_hook, bool, + private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, + message_t *message, bool incoming, bool plain) +{ + /* start accounting here, virtual IP now is set */ + if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + message->get_exchange_type(message) == IKE_AUTH && + !incoming && !message->get_request(message)) + { + send_start(this, ike_sa); + } + return TRUE; +} + +METHOD(listener_t, child_rekey, bool, + private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, + child_sa_t *old, child_sa_t *new) +{ + update_usage(this, ike_sa, old); + + return TRUE; +} + +METHOD(listener_t, child_updown, bool, + private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, + child_sa_t *child_sa, bool up) +{ + if (!up && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED) + { + update_usage(this, ike_sa, child_sa); + } + return TRUE; +} + +METHOD(eap_radius_accounting_t, destroy, void, + private_eap_radius_accounting_t *this) +{ + this->mutex->destroy(this->mutex); + this->sessions->destroy(this->sessions); + free(this); +} + +/** + * See header + */ +eap_radius_accounting_t *eap_radius_accounting_create() +{ + private_eap_radius_accounting_t *this; + + INIT(this, + .public = { + .listener = { + .ike_updown = _ike_updown, + .message = _message_hook, + .child_updown = _child_updown, + .child_rekey = _child_rekey, + }, + .destroy = _destroy, + }, + /* use system time as Session ID prefix */ + .prefix = (u_int32_t)time(NULL), + .sessions = hashtable_create((hashtable_hash_t)hash, + (hashtable_equals_t)equals, 32), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.h b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h new file mode 100644 index 000000000..811a5bb90 --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_radius_accounting eap_radius_accounting + * @{ @ingroup eap_radius + */ + +#ifndef EAP_RADIUS_ACCOUNTING_H_ +#define EAP_RADIUS_ACCOUNTING_H_ + +#include <bus/listeners/listener.h> + +typedef struct eap_radius_accounting_t eap_radius_accounting_t; + +/** + * RADIUS accounting for IKE/IPsec. + */ +struct eap_radius_accounting_t { + + /** + * Implements listener_t. + */ + listener_t listener; + + /** + * Destroy a eap_radius_accounting_t. + */ + void (*destroy)(eap_radius_accounting_t *this); +}; + +/** + * Create a eap_radius_accounting instance. + */ +eap_radius_accounting_t *eap_radius_accounting_create(); + +#endif /** EAP_RADIUS_ACCOUNTING_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.c b/src/libcharon/plugins/eap_radius/eap_radius_dae.c new file mode 100644 index 000000000..5823142cc --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_dae.c @@ -0,0 +1,543 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_radius_dae.h" + +#include <radius_message.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <unistd.h> +#include <errno.h> + +#include <daemon.h> +#include <threading/thread.h> +#include <processing/jobs/callback_job.h> +#include <processing/jobs/delete_ike_sa_job.h> + +#define RADIUS_DAE_PORT 3799 + +typedef struct private_eap_radius_dae_t private_eap_radius_dae_t; + +/** + * Private data of an eap_radius_dae_t object. + */ +struct private_eap_radius_dae_t { + + /** + * Public eap_radius_dae_t interface. + */ + eap_radius_dae_t public; + + /** + * RADIUS session state + */ + eap_radius_accounting_t *accounting; + + /** + * Socket to listen on authorization extension port + */ + int fd; + + /** + * Listen job + */ + callback_job_t *job; + + /** + * RADIUS shared secret for DAE exchanges + */ + chunk_t secret; + + /** + * MD5 hasher + */ + hasher_t *hasher; + + /** + * HMAC MD5 signer, with secret set + */ + signer_t *signer; + + /** + * List of responses for retransmission, as entry_t + */ + linked_list_t *responses; +}; + +/** + * Entry to store responses for retransmit + */ +typedef struct { + /** stored response */ + radius_message_t *response; + /** client that sent the request */ + host_t *client; +} entry_t; + +/** + * Clean up an entry + */ +static void entry_destroy(entry_t *entry) +{ + entry->response->destroy(entry->response); + entry->client->destroy(entry->client); + free(entry); +} + +/** + * Save/Replace response for retransmission + */ +static void save_retransmit(private_eap_radius_dae_t *this, + radius_message_t *response, host_t *client) +{ + enumerator_t *enumerator; + entry_t *entry; + bool found = FALSE; + + enumerator = this->responses->create_enumerator(this->responses); + while (enumerator->enumerate(enumerator, &entry)) + { + if (client->equals(client, entry->client)) + { + entry->response->destroy(entry->response); + entry->response = response; + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + INIT(entry, + .response = response, + .client = client->clone(client), + ); + this->responses->insert_first(this->responses, entry); + } +} + +/** + * Send a RADIUS message to client + */ +static void send_message(private_eap_radius_dae_t *this, + radius_message_t *message, host_t *client) +{ + chunk_t data; + + data = message->get_encoding(message); + if (sendto(this->fd, data.ptr, data.len, 0, client->get_sockaddr(client), + *client->get_sockaddr_len(client)) != data.len) + { + DBG1(DBG_CFG, "sending RADIUS DAE response failed: %s", strerror(errno)); + } +} + +/** + * Check if we request is a retransmit, retransmit stored response + */ +static bool send_retransmit(private_eap_radius_dae_t *this, + radius_message_t *request, host_t *client) +{ + enumerator_t *enumerator; + entry_t *entry; + bool found = FALSE; + + enumerator = this->responses->create_enumerator(this->responses); + while (enumerator->enumerate(enumerator, &entry)) + { + if (client->equals(client, entry->client) && + request->get_identifier(request) == + entry->response->get_identifier(entry->response)) + { + DBG1(DBG_CFG, "received retransmit of RADIUS %N, retransmitting %N " + "to %H", radius_message_code_names, request->get_code(request), + radius_message_code_names, + entry->response->get_code(entry->response), client); + send_message(this, entry->response, client); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + return found; +} + +/** + * Send an ACK/NAK response for a request + */ +static void send_response(private_eap_radius_dae_t *this, + radius_message_t *request, radius_message_code_t code, + host_t *client) +{ + radius_message_t *response; + + response = radius_message_create(code); + response->set_identifier(response, request->get_identifier(request)); + response->sign(response, request->get_authenticator(request), + this->secret, this->hasher, this->signer, NULL, FALSE); + + send_message(this, response, client); + save_retransmit(this, response, client); +} + +/** + * Add all IKE_SAs matching to user to a list + */ +static void add_matching_ike_sas(linked_list_t *list, identification_t *user) +{ + enumerator_t *enumerator; + ike_sa_t *ike_sa; + ike_sa_id_t *id; + + enumerator = charon->ike_sa_manager->create_enumerator( + charon->ike_sa_manager, FALSE); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + if (user->matches(user, ike_sa->get_other_eap_id(ike_sa))) + { + id = ike_sa->get_id(ike_sa); + list->insert_last(list, id->clone(id)); + } + } + enumerator->destroy(enumerator); +} + +/** + * Get list of IKE_SAs matching a Disconnect/CoA request + */ +static linked_list_t *get_matching_ike_sas(private_eap_radius_dae_t *this, + radius_message_t *request, host_t *client) +{ + enumerator_t *enumerator; + identification_t *user; + linked_list_t *ids; + chunk_t data; + int type; + + ids = linked_list_create(); + + enumerator = request->create_enumerator(request); + while (enumerator->enumerate(enumerator, &type, &data)) + { + if (type == RAT_USER_NAME && data.len) + { + user = identification_create_from_data(data); + DBG1(DBG_CFG, "received RADIUS DAE %N for %Y from %H", + radius_message_code_names, request->get_code(request), + user, client); + add_matching_ike_sas(ids, user); + user->destroy(user); + } + } + enumerator->destroy(enumerator); + + return ids; +} + +/** + * Process a DAE disconnect request, send response + */ +static void process_disconnect(private_eap_radius_dae_t *this, + radius_message_t *request, host_t *client) +{ + enumerator_t *enumerator; + linked_list_t *ids; + ike_sa_id_t *id; + + ids = get_matching_ike_sas(this, request, client); + + if (ids->get_count(ids)) + { + DBG1(DBG_CFG, "closing %d IKE_SA%s matching %N, sending %N", + ids->get_count(ids), ids->get_count(ids) > 1 ? "s" : "", + radius_message_code_names, RMC_DISCONNECT_REQUEST, + radius_message_code_names, RMC_DISCONNECT_ACK); + + enumerator = ids->create_enumerator(ids); + while (enumerator->enumerate(enumerator, &id)) + { + lib->processor->queue_job(lib->processor, (job_t*) + delete_ike_sa_job_create(id, TRUE)); + } + enumerator->destroy(enumerator); + + send_response(this, request, RMC_DISCONNECT_ACK, client); + } + else + { + DBG1(DBG_CFG, "no IKE_SA matches %N, sending %N", + radius_message_code_names, RMC_DISCONNECT_REQUEST, + radius_message_code_names, RMC_DISCONNECT_NAK); + send_response(this, request, RMC_DISCONNECT_NAK, client); + } + ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy)); +} + +/** + * Apply a new lifetime to an IKE_SA + */ +static void apply_lifetime(private_eap_radius_dae_t *this, ike_sa_id_t *id, + u_int32_t lifetime) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id); + if (ike_sa) + { + if (ike_sa->set_auth_lifetime(ike_sa, lifetime) == DESTROY_ME) + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, + ike_sa); + } + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + } +} + +/** + * Process a DAE CoA request, send response + */ +static void process_coa(private_eap_radius_dae_t *this, + radius_message_t *request, host_t *client) +{ + enumerator_t *enumerator; + linked_list_t *ids; + ike_sa_id_t *id; + chunk_t data; + int type; + u_int32_t lifetime = 0; + bool lifetime_seen = FALSE; + + ids = get_matching_ike_sas(this, request, client); + + if (ids->get_count(ids)) + { + enumerator = request->create_enumerator(request); + while (enumerator->enumerate(enumerator, &type, &data)) + { + if (type == RAT_SESSION_TIMEOUT && data.len == 4) + { + lifetime = untoh32(data.ptr); + lifetime_seen = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (lifetime_seen) + { + DBG1(DBG_CFG, "applying %us lifetime to %d IKE_SA%s matching %N, " + "sending %N", lifetime, ids->get_count(ids), + ids->get_count(ids) > 1 ? "s" : "", + radius_message_code_names, RMC_COA_REQUEST, + radius_message_code_names, RMC_COA_ACK); + + enumerator = ids->create_enumerator(ids); + while (enumerator->enumerate(enumerator, &id)) + { + apply_lifetime(this, id, lifetime); + } + enumerator->destroy(enumerator); + send_response(this, request, RMC_COA_ACK, client); + } + else + { + DBG1(DBG_CFG, "no Session-Timeout attribute found in %N, sending %N", + radius_message_code_names, RMC_COA_REQUEST, + radius_message_code_names, RMC_COA_NAK); + send_response(this, request, RMC_COA_NAK, client); + } + } + else + { + DBG1(DBG_CFG, "no IKE_SA matches %N, sending %N", + radius_message_code_names, RMC_COA_REQUEST, + radius_message_code_names, RMC_COA_NAK); + send_response(this, request, RMC_COA_NAK, client); + } + ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy)); +} + +/** + * Receive RADIUS DAE requests + */ +static job_requeue_t receive(private_eap_radius_dae_t *this) +{ + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + radius_message_t *request; + char buf[2048]; + ssize_t len; + bool oldstate; + host_t *client; + + oldstate = thread_cancelability(TRUE); + len = recvfrom(this->fd, buf, sizeof(buf), 0, + (struct sockaddr*)&addr, &addr_len); + thread_cancelability(oldstate); + + if (len > 0) + { + request = radius_message_parse(chunk_create(buf, len)); + if (request) + { + client = host_create_from_sockaddr((struct sockaddr*)&addr); + if (client) + { + if (!send_retransmit(this, request, client)) + { + if (request->verify(request, NULL, this->secret, + this->hasher, this->signer)) + { + switch (request->get_code(request)) + { + case RMC_DISCONNECT_REQUEST: + process_disconnect(this, request, client); + break; + case RMC_COA_REQUEST: + process_coa(this, request, client); + break; + default: + DBG1(DBG_CFG, "ignoring unsupported RADIUS DAE " + "%N message from %H", + radius_message_code_names, + request->get_code(request), client); + break; + } + } + } + client->destroy(client); + } + request->destroy(request); + } + else + { + DBG1(DBG_NET, "ignoring invalid RADIUS DAE request"); + } + } + else + { + DBG1(DBG_NET, "receving RADIUS DAE request failed: %s", strerror(errno)); + } + return JOB_REQUEUE_DIRECT; +} + +/** + * Open DAE socket + */ +static bool open_socket(private_eap_radius_dae_t *this) +{ + host_t *host; + + this->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (this->fd == -1) + { + DBG1(DBG_CFG, "unable to open RADIUS DAE socket: %s", strerror(errno)); + return FALSE; + } + + host = host_create_from_string( + lib->settings->get_str(lib->settings, + "charon.plugins.eap-radius.dae.listen", "0.0.0.0"), + lib->settings->get_int(lib->settings, + "charon.plugins.eap-radius.dae.port", RADIUS_DAE_PORT)); + if (!host) + { + DBG1(DBG_CFG, "invalid RADIUS DAE listen address"); + return FALSE; + } + + if (bind(this->fd, host->get_sockaddr(host), + *host->get_sockaddr_len(host)) == -1) + { + DBG1(DBG_CFG, "unable to bind RADIUS DAE socket: %s", strerror(errno)); + host->destroy(host); + return FALSE; + } + host->destroy(host); + return TRUE; +} + +METHOD(eap_radius_dae_t, destroy, void, + private_eap_radius_dae_t *this) +{ + if (this->job) + { + this->job->cancel(this->job); + } + if (this->fd != -1) + { + close(this->fd); + } + DESTROY_IF(this->signer); + DESTROY_IF(this->hasher); + this->responses->destroy_function(this->responses, (void*)entry_destroy); + free(this); +} + +/** + * See header + */ +eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting) +{ + private_eap_radius_dae_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .accounting = accounting, + .fd = -1, + .secret = { + .ptr = lib->settings->get_str(lib->settings, + "charon.plugins.eap-radius.dae.secret", NULL), + }, + .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5), + .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128), + .responses = linked_list_create(), + ); + + if (!this->hasher || !this->signer) + { + destroy(this); + return NULL; + } + if (!this->secret.ptr) + { + DBG1(DBG_CFG, "missing RADIUS DAE secret, disabled"); + destroy(this); + return NULL; + } + this->secret.len = strlen(this->secret.ptr); + this->signer->set_key(this->signer, this->secret); + + if (!open_socket(this)) + { + destroy(this); + return NULL; + } + + this->job = callback_job_create_with_prio((callback_job_cb_t)receive, + this, NULL, NULL, JOB_PRIO_CRITICAL); + lib->processor->queue_job(lib->processor, (job_t*)this->job); + + return &this->public; +} diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.h b/src/libcharon/plugins/eap_radius/eap_radius_dae.h new file mode 100644 index 000000000..759eadb49 --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_dae.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_radius_dae eap_radius_dae + * @{ @ingroup eap_radius + */ + +#ifndef EAP_RADIUS_DAE_H_ +#define EAP_RADIUS_DAE_H_ + +#include "eap_radius_accounting.h" + +typedef struct eap_radius_dae_t eap_radius_dae_t; + +/** + * Dynamic Authorization Extensions (RFC 5176) for EAP-RADIUS. + */ +struct eap_radius_dae_t { + + /** + * Destroy a eap_radius_dae_t. + */ + void (*destroy)(eap_radius_dae_t *this); +}; + +/** + * Create a eap_radius_dae instance. + */ +eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting); + +#endif /** EAP_RADIUS_DAE_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.c b/src/libcharon/plugins/eap_radius/eap_radius_forward.c new file mode 100644 index 000000000..16701bb57 --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_radius_forward.h" + +#include <daemon.h> +#include <utils/linked_list.h> +#include <utils/hashtable.h> +#include <threading/mutex.h> + +typedef struct private_eap_radius_forward_t private_eap_radius_forward_t; + +/** + * Private data of an eap_radius_forward_t object. + */ +struct private_eap_radius_forward_t { + + /** + * Public eap_radius_forward_t interface. + */ + eap_radius_forward_t public; + + /** + * List of attribute types to copy from IKE, as attr_t + */ + linked_list_t *from_attr; + + /** + * List of attribute types to copy to IKE, as attr_t + */ + linked_list_t *to_attr; + + /** + * Queued to forward from IKE, unique_id => linked_list_t of chunk_t + */ + hashtable_t *from; + + /** + * Queued to forward to IKE, unique_id => linked_list_t of chunk_t + */ + hashtable_t *to; + + /** + * Mutex to lock concurrent access to hashtables + */ + mutex_t *mutex; +}; + +/** + * RADIUS attribute selector + */ +typedef struct { + /** vendor ID, 0 for standard attributes */ + u_int32_t vendor; + /** attribute type */ + u_int8_t type; +} attr_t; + +/** + * Single instance of this + */ +static private_eap_radius_forward_t *singleton = NULL; + +/** + * Hashtable hash function + */ +static u_int hash(uintptr_t key) +{ + return key; +} + +/** + * Hashtable equals function + */ +static bool equals(uintptr_t a, uintptr_t b) +{ + return a == b; +} + +/** + * Free a queue entry + */ +static void free_attribute(chunk_t *chunk) +{ + free(chunk->ptr); + free(chunk); +} + +/** + * Lookup/create an attribute queue from a table + */ +static linked_list_t *lookup_queue(private_eap_radius_forward_t *this, + hashtable_t *table) +{ + linked_list_t *queue = NULL; + ike_sa_t *ike_sa; + uintptr_t id; + + ike_sa = charon->bus->get_sa(charon->bus); + if (ike_sa && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN)) + { + id = ike_sa->get_unique_id(ike_sa); + this->mutex->lock(this->mutex); + queue = table->get(table, (void*)id); + if (!queue) + { + queue = linked_list_create(); + table->put(table, (void*)id, queue); + } + this->mutex->unlock(this->mutex); + } + return queue; +} + +/** + * Remove attribute queue from table + */ +static void remove_queue(private_eap_radius_forward_t *this, + hashtable_t *table, ike_sa_t *ike_sa) +{ + linked_list_t *queue; + + this->mutex->lock(this->mutex); + queue = table->remove(table, (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa)); + this->mutex->unlock(this->mutex); + if (queue) + { + queue->destroy_function(queue, (void*)free_attribute); + } +} + +/** + * Check if RADIUS attribute is contained in selector + */ +static bool is_attribute_selected(linked_list_t *selector, + radius_attribute_type_t type, chunk_t data) +{ + enumerator_t *enumerator; + u_int32_t vendor = 0; + attr_t *sel; + bool found = FALSE; + + if (type == RAT_VENDOR_SPECIFIC) + { + if (data.len < 4) + { + return FALSE; + } + vendor = untoh32(data.ptr); + } + enumerator = selector->create_enumerator(selector); + while (!found && enumerator->enumerate(enumerator, &sel)) + { + if (sel->vendor == vendor) + { + if (vendor) + { + if (sel->type == 0) + { /* any of that vendor is fine */ + found = TRUE; + } + else if (data.len > 4 && data.ptr[4] == sel->type) + { /* vendor specific type field, as defined in RFC 2865 */ + found = TRUE; + } + } + else + { + if (sel->type == type) + { + found = TRUE; + } + } + } + } + enumerator->destroy(enumerator); + + return found; +} + +/** + * Copy RADIUS attributes from queue to a RADIUS message + */ +static void queue2radius(linked_list_t *queue, radius_message_t *message) +{ + chunk_t *data; + + while (queue->remove_last(queue, (void**)&data) == SUCCESS) + { + if (data->len >= 2) + { + message->add(message, data->ptr[0], chunk_skip(*data, 2)); + } + free_attribute(data); + } +} + +/** + * Copy RADIUS attributes from a RADIUS message to the queue + */ +static void radius2queue(radius_message_t *message, linked_list_t *queue, + linked_list_t *selector) +{ + enumerator_t *enumerator; + int type; + chunk_t data, hdr, *ptr; + + enumerator = message->create_enumerator(message); + while (enumerator->enumerate(enumerator, &type, &data)) + { + if (is_attribute_selected(selector, type, data)) + { + hdr = chunk_alloc(2); + hdr.ptr[0] = type; + hdr.ptr[1] = data.len + 2; + + INIT(ptr); + *ptr = chunk_cat("mc", hdr, data); + queue->insert_last(queue, ptr); + } + } + enumerator->destroy(enumerator); +} + +/** + * Copy RADIUS attribute nofifies from IKE message to queue + */ +static void ike2queue(message_t *message, linked_list_t *queue, + linked_list_t *selector) +{ + enumerator_t *enumerator; + payload_t *payload; + notify_payload_t *notify; + chunk_t data, *ptr; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE) + { + data = notify->get_notification_data(notify); + if (data.len >= 2 && is_attribute_selected(selector, + data.ptr[0], chunk_skip(data, 2))) + { + INIT(ptr); + *ptr = chunk_clone(data); + queue->insert_last(queue, ptr); + } + } + } + } + enumerator->destroy(enumerator); +} + +/** + * Copy RADUIS attributes from queue to IKE message notifies + */ +static void queue2ike(linked_list_t *queue, message_t *message) +{ + chunk_t *data; + + while (queue->remove_last(queue, (void**)&data) == SUCCESS) + { + message->add_notify(message, FALSE, RADIUS_ATTRIBUTE, *data); + free_attribute(data); + } +} + +/** + * See header. + */ +void eap_radius_forward_from_ike(radius_message_t *request) +{ + private_eap_radius_forward_t *this = singleton; + linked_list_t *queue; + + if (this) + { + queue = lookup_queue(this, this->from); + if (queue) + { + queue2radius(queue, request); + } + } +} + +/** + * See header. + */ +void eap_radius_forward_to_ike(radius_message_t *response) +{ + private_eap_radius_forward_t *this = singleton; + linked_list_t *queue; + + if (this) + { + queue = lookup_queue(this, this->to); + if (queue) + { + radius2queue(response, queue, this->to_attr); + } + } +} + +METHOD(listener_t, message, bool, + private_eap_radius_forward_t *this, + ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain) +{ + linked_list_t *queue; + + if (plain && message->get_exchange_type(message) == IKE_AUTH) + { + if (incoming) + { + queue = lookup_queue(this, this->from); + if (queue) + { + ike2queue(message, queue, this->from_attr); + } + } + else + { + queue = lookup_queue(this, this->to); + if (queue) + { + queue2ike(queue, message); + } + } + } + return TRUE; +} + +METHOD(listener_t, ike_updown, bool, + private_eap_radius_forward_t *this, ike_sa_t *ike_sa, bool up) +{ + /* up or down, we don't need the state anymore */ + remove_queue(this, this->from, ike_sa); + remove_queue(this, this->to, ike_sa); + return TRUE; +} + +/** + * Parse a selector string to a list of attr_t selectors + */ +static linked_list_t* parse_selector(char *selector) +{ + enumerator_t *enumerator; + linked_list_t *list; + char *token, *pos; + + list = linked_list_create(); + enumerator = enumerator_create_token(selector, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + int type, vendor = 0; + attr_t *attr; + + pos = strchr(token, ':'); + if (pos) + { + *(pos++) = 0; + vendor = atoi(token); + token = pos; + } + type = enum_from_name(radius_attribute_type_names, token); + if (type == -1) + { + type = atoi(token); + } + if (vendor == 0 && type == 0) + { + DBG1(DBG_CFG, "ignoring unknown RADIUS attribute type '%s'", token); + } + else + { + INIT(attr, + .type = type, + .vendor = vendor, + ); + list->insert_last(list, attr); + if (!vendor) + { + DBG1(DBG_IKE, "forwarding RADIUS attribute %N", + radius_attribute_type_names, type); + } + else + { + DBG1(DBG_IKE, "forwarding RADIUS VSA %d-%d", vendor, type); + } + } + } + enumerator->destroy(enumerator); + return list; +} + +METHOD(eap_radius_forward_t, destroy, void, + private_eap_radius_forward_t *this) +{ + this->from_attr->destroy_function(this->from_attr, free); + this->to_attr->destroy_function(this->to_attr, free); + this->from->destroy(this->from); + this->to->destroy(this->to); + this->mutex->destroy(this->mutex); + free(this); + singleton = NULL; +} + +/** + * See header + */ +eap_radius_forward_t *eap_radius_forward_create() +{ + private_eap_radius_forward_t *this; + + INIT(this, + .public = { + .listener = { + .message = _message, + .ike_updown = _ike_updown, + }, + .destroy = _destroy, + }, + .from_attr = parse_selector(lib->settings->get_str(lib->settings, + "charon.plugins.eap-radius.forward.ike_to_radius", "")), + .to_attr = parse_selector(lib->settings->get_str(lib->settings, + "charon.plugins.eap-radius.forward.radius_to_ike", "")), + .from = hashtable_create((hashtable_hash_t)hash, + (hashtable_equals_t)equals, 8), + .to = hashtable_create((hashtable_hash_t)hash, + (hashtable_equals_t)equals, 8), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + if (this->from_attr->get_count(this->from_attr) == 0 && + this->to_attr->get_count(this->to_attr) == 0) + { + destroy(this); + return NULL; + } + + singleton = this; + return &this->public; +} diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.h b/src/libcharon/plugins/eap_radius/eap_radius_forward.h new file mode 100644 index 000000000..2c1dbf7a8 --- /dev/null +++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_radius_forward eap_radius_forward + * @{ @ingroup eap_radius + */ + +#ifndef EAP_RADIUS_FORWARD_H_ +#define EAP_RADIUS_FORWARD_H_ + +#include <radius_message.h> + +#include <bus/listeners/listener.h> + +typedef struct eap_radius_forward_t eap_radius_forward_t; + +/** + * Forward RADIUS attributes in Notifies between client and AAA backend. + */ +struct eap_radius_forward_t { + + /** + * Implements a listener. + */ + listener_t listener; + + /** + * Destroy a eap_radius_forward_t. + */ + void (*destroy)(eap_radius_forward_t *this); +}; + +/** + * Create a eap_radius_forward instance. + */ +eap_radius_forward_t *eap_radius_forward_create(); + +/** + * Forward RADIUS attributes from IKE notifies to a RADIUS request. + * + * @param request RADIUS request message to add attributes to + */ +void eap_radius_forward_from_ike(radius_message_t *request); + +/** + * Forward RADIUS attributes from a RADIUS response to IKE notifies. + * + * @param response RADIUS respose to read notifies from + */ +void eap_radius_forward_to_ike(radius_message_t *response); + +#endif /** EAP_RADIUS_FORWARD_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c index 4119ec571..8ee0ab81a 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c @@ -16,16 +16,25 @@ #include "eap_radius_plugin.h" #include "eap_radius.h" -#include "radius_client.h" -#include "radius_server.h" +#include "eap_radius_accounting.h" +#include "eap_radius_dae.h" +#include "eap_radius_forward.h" + +#include <radius_client.h> +#include <radius_config.h> #include <daemon.h> #include <threading/rwlock.h> /** - * Default RADIUS server port, when not configured + * Default RADIUS server port for authentication + */ +#define AUTH_PORT 1812 + +/** + * Default RADIUS server port for accounting */ -#define RADIUS_PORT 1812 +#define ACCT_PORT 1813 typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t; @@ -40,14 +49,29 @@ struct private_eap_radius_plugin_t { eap_radius_plugin_t public; /** - * List of RADIUS servers + * List of RADIUS server configurations */ - linked_list_t *servers; + linked_list_t *configs; /** - * Lock for server list + * Lock for configs list */ rwlock_t *lock; + + /** + * RADIUS sessions for accounting + */ + eap_radius_accounting_t *accounting; + + /** + * Dynamic authorization extensions + */ + eap_radius_dae_t *dae; + + /** + * RADIUS <-> IKE attribute forwarding + */ + eap_radius_forward_t *forward; }; /** @@ -58,12 +82,12 @@ static private_eap_radius_plugin_t *instance = NULL; /** * Load RADIUS servers from configuration */ -static void load_servers(private_eap_radius_plugin_t *this) +static void load_configs(private_eap_radius_plugin_t *this) { enumerator_t *enumerator; - radius_server_t *server; + radius_config_t *config; char *nas_identifier, *secret, *address, *section; - int port, sockets, preference; + int auth_port, acct_port, sockets, preference; address = lib->settings->get_str(lib->settings, "charon.plugins.eap-radius.server", NULL); @@ -78,18 +102,18 @@ static void load_servers(private_eap_radius_plugin_t *this) } nas_identifier = lib->settings->get_str(lib->settings, "charon.plugins.eap-radius.nas_identifier", "strongSwan"); - port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.port", RADIUS_PORT); + auth_port = lib->settings->get_int(lib->settings, + "charon.plugins.eap-radius.port", AUTH_PORT); sockets = lib->settings->get_int(lib->settings, "charon.plugins.eap-radius.sockets", 1); - server = radius_server_create(address, address, port, nas_identifier, - secret, sockets, 0); - if (!server) + config = radius_config_create(address, address, auth_port, ACCT_PORT, + nas_identifier, secret, sockets, 0); + if (!config) { DBG1(DBG_CFG, "no RADUIS server defined"); return; } - this->servers->insert_last(this->servers, server); + this->configs->insert_last(this->configs, config); return; } @@ -114,26 +138,32 @@ static void load_servers(private_eap_radius_plugin_t *this) nas_identifier = lib->settings->get_str(lib->settings, "charon.plugins.eap-radius.servers.%s.nas_identifier", "strongSwan", section); - port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.servers.%s.port", RADIUS_PORT, section); + auth_port = lib->settings->get_int(lib->settings, + "charon.plugins.eap-radius.servers.%s.auth_port", + lib->settings->get_int(lib->settings, + "charon.plugins.eap-radius.servers.%s.port", + AUTH_PORT, section), + section); + acct_port = lib->settings->get_int(lib->settings, + "charon.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, section); sockets = lib->settings->get_int(lib->settings, "charon.plugins.eap-radius.servers.%s.sockets", 1, section); preference = lib->settings->get_int(lib->settings, "charon.plugins.eap-radius.servers.%s.preference", 0, section); - server = radius_server_create(section, address, port, nas_identifier, - secret, sockets, preference); - if (!server) + config = radius_config_create(section, address, auth_port, acct_port, + nas_identifier, secret, sockets, preference); + if (!config) { DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section); continue; } - this->servers->insert_last(this->servers, server); + this->configs->insert_last(this->configs, config); } enumerator->destroy(enumerator); DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s", - this->servers->get_count(this->servers), - this->servers->get_count(this->servers) == 1 ? "" : "s"); + this->configs->get_count(this->configs), + this->configs->get_count(this->configs) == 1 ? "" : "s"); } METHOD(plugin_t, get_name, char*, @@ -160,10 +190,10 @@ METHOD(plugin_t, reload, bool, private_eap_radius_plugin_t *this) { this->lock->write_lock(this->lock); - this->servers->destroy_offset(this->servers, - offsetof(radius_server_t, destroy)); - this->servers = linked_list_create(); - load_servers(this); + this->configs->destroy_offset(this->configs, + offsetof(radius_config_t, destroy)); + this->configs = linked_list_create(); + load_configs(this); this->lock->unlock(this->lock); return TRUE; } @@ -171,9 +201,17 @@ METHOD(plugin_t, reload, bool, METHOD(plugin_t, destroy, void, private_eap_radius_plugin_t *this) { - this->servers->destroy_offset(this->servers, - offsetof(radius_server_t, destroy)); + if (this->forward) + { + charon->bus->remove_listener(charon->bus, &this->forward->listener); + this->forward->destroy(this->forward); + } + DESTROY_IF(this->dae); + this->configs->destroy_offset(this->configs, + offsetof(radius_config_t, destroy)); this->lock->destroy(this->lock); + charon->bus->remove_listener(charon->bus, &this->accounting->listener); + this->accounting->destroy(this->accounting); free(this); instance = NULL; } @@ -194,28 +232,73 @@ plugin_t *eap_radius_plugin_create() .destroy = _destroy, }, }, - .servers = linked_list_create(), + .configs = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .accounting = eap_radius_accounting_create(), + .forward = eap_radius_forward_create(), ); - load_servers(this); + load_configs(this); instance = this; + if (lib->settings->get_bool(lib->settings, + "charon.plugins.eap-radius.accounting", FALSE)) + { + charon->bus->add_listener(charon->bus, &this->accounting->listener); + } + if (lib->settings->get_bool(lib->settings, + "charon.plugins.eap-radius.dae.enable", FALSE)) + { + this->dae = eap_radius_dae_create(this->accounting); + } + if (this->forward) + { + charon->bus->add_listener(charon->bus, &this->forward->listener); + } + return &this->public.plugin; } /** * See header */ -enumerator_t *eap_radius_create_server_enumerator() +radius_client_t *eap_radius_create_client() { if (instance) { + enumerator_t *enumerator; + radius_config_t *config, *selected = NULL; + int current, best = -1; + instance->lock->read_lock(instance->lock); - return enumerator_create_cleaner( - instance->servers->create_enumerator(instance->servers), - (void*)instance->lock->unlock, instance->lock); + enumerator = instance->configs->create_enumerator(instance->configs); + while (enumerator->enumerate(enumerator, &config)) + { + current = config->get_preference(config); + if (current > best || + /* for two with equal preference, 50-50 chance */ + (current == best && random() % 2 == 0)) + { + DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d", + config->get_name(config), current); + best = current; + DESTROY_IF(selected); + selected = config->get_ref(config); + } + else + { + DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d", + config->get_name(config), current); + } + } + enumerator->destroy(enumerator); + instance->lock->unlock(instance->lock); + + if (selected) + { + return radius_client_create(selected); + } } - return enumerator_create_empty(); + return NULL; } diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h index cb724364a..1570bd566 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h +++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h @@ -25,7 +25,8 @@ #define EAP_RADIUS_PLUGIN_H_ #include <plugins/plugin.h> -#include <utils/enumerator.h> + +#include <radius_client.h> typedef struct eap_radius_plugin_t eap_radius_plugin_t; @@ -44,10 +45,10 @@ struct eap_radius_plugin_t { }; /** - * Create an enumerator over all loaded RADIUS servers. + * Get a RADIUS client instance to connect to servers. * - * @return enumerator over radius_server_t + * @return RADIUS client */ -enumerator_t *eap_radius_create_server_enumerator(); +radius_client_t *eap_radius_create_client(); #endif /** EAP_RADIUS_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/eap_tls/eap_tls.c b/src/libcharon/plugins/eap_tls/eap_tls.c index 39e1a60d9..dc0289ba2 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.c +++ b/src/libcharon/plugins/eap_tls/eap_tls.c @@ -39,7 +39,7 @@ struct private_eap_tls_t { }; /** Maximum number of EAP-TLS messages/fragments allowed */ -#define MAX_MESSAGE_COUNT 32 +#define MAX_MESSAGE_COUNT 32 /** Default size of a EAP-TLS fragment */ #define MAX_FRAGMENT_LEN 1024 @@ -148,8 +148,8 @@ static eap_tls_t *eap_tls_create(identification_t *server, max_msg_count = lib->settings->get_int(lib->settings, "charon.plugins.eap-tls.max_message_count", MAX_MESSAGE_COUNT); include_length = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-tls.include_length", TRUE); - tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, NULL); + "charon.plugins.eap-tls.include_length", TRUE); + tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, NULL, NULL); this->tls_eap = tls_eap_create(EAP_TLS, tls, frag_size, max_msg_count, include_length); if (!this->tls_eap) diff --git a/src/libcharon/plugins/eap_ttls/Makefile.am b/src/libcharon/plugins/eap_ttls/Makefile.am index 94ce5cc1e..8cc82cc2e 100644 --- a/src/libcharon/plugins/eap_ttls/Makefile.am +++ b/src/libcharon/plugins/eap_ttls/Makefile.am @@ -1,6 +1,7 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libtls + -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libtls \ + -I$(top_srcdir)/src/libradius AM_CFLAGS = -rdynamic diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.c b/src/libcharon/plugins/eap_ttls/eap_ttls.c index 7193bc9f0..ace62f6b9 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.c @@ -156,7 +156,8 @@ static eap_ttls_t *eap_ttls_create(identification_t *server, "charon.plugins.eap-ttls.max_message_count", MAX_MESSAGE_COUNT); include_length = lib->settings->get_bool(lib->settings, "charon.plugins.eap-ttls.include_length", TRUE); - tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TTLS, application); + tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TTLS, + application, NULL); this->tls_eap = tls_eap_create(EAP_TTLS, tls, frag_size, max_msg_count, include_length); if (!this->tls_eap) diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index e75bd2976..767111b3e 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -18,7 +18,7 @@ #include <debug.h> #include <daemon.h> - +#include <radius_message.h> #include <sa/eap/eap_method.h> typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t; @@ -64,8 +64,6 @@ struct private_eap_ttls_peer_t { eap_ttls_avp_t *avp; }; -#define MAX_RADIUS_ATTRIBUTE_SIZE 253 - METHOD(tls_application_t, process, status_t, private_eap_ttls_peer_t *this, bio_reader_t *reader) { diff --git a/src/libcharon/plugins/farp/farp_listener.c b/src/libcharon/plugins/farp/farp_listener.c index 30709c9eb..d1df4cc27 100644 --- a/src/libcharon/plugins/farp/farp_listener.c +++ b/src/libcharon/plugins/farp/farp_listener.c @@ -15,7 +15,7 @@ #include "farp_listener.h" -#include <utils/hashtable.h> +#include <utils/linked_list.h> #include <threading/rwlock.h> typedef struct private_farp_listener_t private_farp_listener_t; @@ -31,9 +31,9 @@ struct private_farp_listener_t { farp_listener_t public; /** - * Hashtable with active virtual IPs + * List with entry_t */ - hashtable_t *ips; + linked_list_t *entries; /** * RWlock for IP list @@ -42,88 +42,99 @@ struct private_farp_listener_t { }; /** - * Hashtable hash function + * Traffic selector cache entry */ -static u_int hash(host_t *key) +typedef struct { + /** list of local selectors */ + linked_list_t *local; + /** list of remote selectors */ + linked_list_t *remote; + /** reqid of CHILD_SA */ + u_int32_t reqid; +} entry_t; + +METHOD(listener_t, child_updown, bool, + private_farp_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, + bool up) { - return chunk_hash(key->get_address(key)); -} - -/** - * Hashtable equals function - */ -static bool equals(host_t *a, host_t *b) -{ - return a->ip_equals(a, b); -} + enumerator_t *enumerator; + entry_t *entry; -METHOD(listener_t, ike_updown, bool, - private_farp_listener_t *this, ike_sa_t *ike_sa, bool up) -{ - if (!up) + if (up) { - host_t *ip; - - ip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (ip) - { - this->lock->write_lock(this->lock); - ip = this->ips->remove(this->ips, ip); - this->lock->unlock(this->lock); - DESTROY_IF(ip); - } + INIT(entry, + .local = child_sa->get_traffic_selectors(child_sa, TRUE), + .remote = child_sa->get_traffic_selectors(child_sa, FALSE), + .reqid = child_sa->get_reqid(child_sa), + ); + entry->local = entry->local->clone_offset(entry->local, + offsetof(traffic_selector_t, clone)); + entry->remote = entry->remote->clone_offset(entry->remote, + offsetof(traffic_selector_t, clone)); + + this->lock->write_lock(this->lock); + this->entries->insert_last(this->entries, entry); + this->lock->unlock(this->lock); } - return TRUE; -} - -METHOD(listener_t, message_hook, bool, - private_farp_listener_t *this, ike_sa_t *ike_sa, - message_t *message, bool incoming, bool plain) -{ - if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && - message->get_exchange_type(message) == IKE_AUTH && - !message->get_request(message)) + else { - host_t *ip; - - ip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (ip) + this->lock->write_lock(this->lock); + enumerator = this->entries->create_enumerator(this->entries); + while (enumerator->enumerate(enumerator, &entry)) { - ip = ip->clone(ip); - this->lock->write_lock(this->lock); - ip = this->ips->put(this->ips, ip, ip); - this->lock->unlock(this->lock); - DESTROY_IF(ip); + if (entry->reqid == child_sa->get_reqid(child_sa)) + { + this->entries->remove_at(this->entries, enumerator); + entry->local->destroy_offset(entry->local, + offsetof(traffic_selector_t, destroy)); + entry->remote->destroy_offset(entry->remote, + offsetof(traffic_selector_t, destroy)); + free(entry); + } } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); } return TRUE; } -METHOD(farp_listener_t, is_active, bool, - private_farp_listener_t *this, host_t *ip) +METHOD(farp_listener_t, has_tunnel, bool, + private_farp_listener_t *this, host_t *local, host_t *remote) { - bool active; + enumerator_t *entries, *locals, *remotes; + traffic_selector_t *ts; + bool found = FALSE; + entry_t *entry; this->lock->read_lock(this->lock); - active = this->ips->get(this->ips, ip) != NULL; + entries = this->entries->create_enumerator(this->entries); + while (!found && entries->enumerate(entries, &entry)) + { + remotes = entry->remote->create_enumerator(entry->remote); + while (!found && remotes->enumerate(remotes, &ts)) + { + if (ts->includes(ts, remote)) + { + locals = entry->local->create_enumerator(entry->local); + while (!found && locals->enumerate(locals, &ts)) + { + found = ts->includes(ts, local); + } + locals->destroy(locals); + } + } + remotes->destroy(remotes); + } + entries->destroy(entries); this->lock->unlock(this->lock); - return active; + + return found; } METHOD(farp_listener_t, destroy, void, private_farp_listener_t *this) { - enumerator_t *enumerator; - host_t *key, *value; - - enumerator = this->ips->create_enumerator(this->ips); - while (enumerator->enumerate(enumerator, &key, &value)) - { - value->destroy(value); - } - enumerator->destroy(enumerator); - this->ips->destroy(this->ips); - + this->entries->destroy(this->entries); this->lock->destroy(this->lock); free(this); } @@ -138,14 +149,12 @@ farp_listener_t *farp_listener_create() INIT(this, .public = { .listener = { - .ike_updown = _ike_updown, - .message = _message_hook, + .child_updown = _child_updown, }, - .is_active = _is_active, + .has_tunnel = _has_tunnel, .destroy = _destroy, }, - .ips = hashtable_create((hashtable_hash_t)hash, - (hashtable_equals_t)equals, 8), + .entries = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); diff --git a/src/libcharon/plugins/farp/farp_listener.h b/src/libcharon/plugins/farp/farp_listener.h index bd96d7a1c..3155f60e2 100644 --- a/src/libcharon/plugins/farp/farp_listener.h +++ b/src/libcharon/plugins/farp/farp_listener.h @@ -37,12 +37,13 @@ struct farp_listener_t { listener_t listener; /** - * Check if a given IP is currently used as virtual IP by a peer. + * Check if we have a tunnel between two IP addresses. * - * @param ip IP to check - * @return TRUE if IP is an active virtual IP + * @param local local IP + * @param remote remote IP + * @return TRUE if a tunnel is active */ - bool (*is_active)(farp_listener_t *this, host_t *ip); + bool (*has_tunnel)(farp_listener_t *this, host_t *local, host_t *remote); /** * Destroy a farp_listener_t. diff --git a/src/libcharon/plugins/farp/farp_spoofer.c b/src/libcharon/plugins/farp/farp_spoofer.c index 7a8ca850b..587a3a74e 100644 --- a/src/libcharon/plugins/farp/farp_spoofer.c +++ b/src/libcharon/plugins/farp/farp_spoofer.c @@ -108,7 +108,7 @@ static job_requeue_t receive_arp(private_farp_spoofer_t *this) arp_t arp; int oldstate; ssize_t len; - host_t *ip; + host_t *local, *remote; oldstate = thread_cancelability(TRUE); len = recvfrom(this->skt, &arp, sizeof(arp), 0, @@ -117,16 +117,16 @@ static job_requeue_t receive_arp(private_farp_spoofer_t *this) if (len == sizeof(arp)) { - ip = host_create_from_chunk(AF_INET, + local = host_create_from_chunk(AF_INET, + chunk_create((char*)&arp.sender_ip, 4), 0); + remote = host_create_from_chunk(AF_INET, chunk_create((char*)&arp.target_ip, 4), 0); - if (ip) + if (this->listener->has_tunnel(this->listener, local, remote)) { - if (this->listener->is_active(this->listener, ip)) - { - send_arp(this, &arp, &addr); - } - ip->destroy(ip); + send_arp(this, &arp, &addr); } + local->destroy(local); + remote->destroy(remote); } return JOB_REQUEUE_DIRECT; diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 328b923b0..de5253b37 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -315,7 +315,7 @@ static void process_ike_update(private_ha_dispatcher_t *this, ike_sa_t *ike_sa = NULL; peer_cfg_t *peer_cfg = NULL; auth_cfg_t *auth; - bool received_vip = FALSE; + bool received_vip = FALSE, first_peer_addr = TRUE; enumerator = message->create_attribute_enumerator(message); while (enumerator->enumerate(enumerator, &attribute, &value)) @@ -355,9 +355,13 @@ static void process_ike_update(private_ha_dispatcher_t *this, ike_sa->set_virtual_ip(ike_sa, FALSE, value.host); received_vip = TRUE; break; - case HA_ADDITIONAL_ADDR: - ike_sa->add_additional_address(ike_sa, - value.host->clone(value.host)); + case HA_PEER_ADDR: + if (first_peer_addr) + { + ike_sa->clear_peer_addresses(ike_sa); + first_peer_addr = FALSE; + } + ike_sa->add_peer_address(ike_sa, value.host->clone(value.host)); break; case HA_CONFIG_NAME: peer_cfg = charon->backends->get_peer_cfg_by_name( diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index c8ad0f845..2819b9dd5 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -205,10 +205,10 @@ METHOD(listener_t, ike_updown, bool, m->add_attribute(m, HA_CONDITIONS, condition); m->add_attribute(m, HA_EXTENSIONS, extension); m->add_attribute(m, HA_CONFIG_NAME, peer_cfg->get_name(peer_cfg)); - enumerator = ike_sa->create_additional_address_enumerator(ike_sa); + enumerator = ike_sa->create_peer_address_enumerator(ike_sa); while (enumerator->enumerate(enumerator, (void**)&addr)) { - m->add_attribute(m, HA_ADDITIONAL_ADDR, addr); + m->add_attribute(m, HA_PEER_ADDR, addr); } enumerator->destroy(enumerator); } diff --git a/src/libcharon/plugins/ha/ha_kernel.c b/src/libcharon/plugins/ha/ha_kernel.c index 07a201557..2377a2630 100644 --- a/src/libcharon/plugins/ha/ha_kernel.c +++ b/src/libcharon/plugins/ha/ha_kernel.c @@ -274,11 +274,14 @@ METHOD(ha_kernel_t, activate, void, char *file; enumerator = enumerator_create_directory(CLUSTERIP_DIR); - while (enumerator->enumerate(enumerator, NULL, &file, NULL)) + if (enumerator) { - enable_disable(this, segment, file, TRUE); + while (enumerator->enumerate(enumerator, NULL, &file, NULL)) + { + enable_disable(this, segment, file, TRUE); + } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); } METHOD(ha_kernel_t, deactivate, void, @@ -288,11 +291,14 @@ METHOD(ha_kernel_t, deactivate, void, char *file; enumerator = enumerator_create_directory(CLUSTERIP_DIR); - while (enumerator->enumerate(enumerator, NULL, &file, NULL)) + if (enumerator) { - enable_disable(this, segment, file, FALSE); + while (enumerator->enumerate(enumerator, NULL, &file, NULL)) + { + enable_disable(this, segment, file, FALSE); + } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); } /** @@ -306,23 +312,26 @@ static void disable_all(private_ha_kernel_t *this) int i; enumerator = enumerator_create_directory(CLUSTERIP_DIR); - while (enumerator->enumerate(enumerator, NULL, &file, NULL)) + if (enumerator) { - if (chown(file, charon->uid, charon->gid) != 0) + while (enumerator->enumerate(enumerator, NULL, &file, NULL)) { - DBG1(DBG_CFG, "changing ClusterIP permissions failed: %s", - strerror(errno)); - } - active = get_active(this, file); - for (i = 1; i <= this->count; i++) - { - if (active & SEGMENTS_BIT(i)) + if (chown(file, charon->uid, charon->gid) != 0) + { + DBG1(DBG_CFG, "changing ClusterIP permissions failed: %s", + strerror(errno)); + } + active = get_active(this, file); + for (i = 1; i <= this->count; i++) { - enable_disable(this, i, file, FALSE); + if (active & SEGMENTS_BIT(i)) + { + enable_disable(this, i, file, FALSE); + } } } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); } METHOD(ha_kernel_t, destroy, void, diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c index 52317e532..6b00ed83f 100644 --- a/src/libcharon/plugins/ha/ha_message.c +++ b/src/libcharon/plugins/ha/ha_message.c @@ -187,7 +187,7 @@ METHOD(ha_message_t, add_attribute, void, case HA_REMOTE_ADDR: case HA_LOCAL_VIP: case HA_REMOTE_VIP: - case HA_ADDITIONAL_ADDR: + case HA_PEER_ADDR: { host_encoding_t *enc; host_t *host; @@ -395,7 +395,7 @@ METHOD(enumerator_t, attribute_enumerate, bool, case HA_REMOTE_ADDR: case HA_LOCAL_VIP: case HA_REMOTE_VIP: - case HA_ADDITIONAL_ADDR: + case HA_PEER_ADDR: { host_encoding_t *enc; diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h index 22a5bd46a..8cd30f711 100644 --- a/src/libcharon/plugins/ha/ha_message.h +++ b/src/libcharon/plugins/ha/ha_message.h @@ -100,8 +100,8 @@ enum ha_message_attribute_t { HA_LOCAL_VIP, /** host_t*, remote virtual IP */ HA_REMOTE_VIP, - /** host_t*, additional MOBIKE peer address */ - HA_ADDITIONAL_ADDR, + /** host_t*, known peer addresses (used for MOBIKE) */ + HA_PEER_ADDR, /** u_int8_t, initiator of an exchange, TRUE for local */ HA_INITIATOR, /** chunk_t, initiators nonce */ diff --git a/src/libcharon/plugins/ha/ha_segments.h b/src/libcharon/plugins/ha/ha_segments.h index eb9e5c1d5..76da38082 100644 --- a/src/libcharon/plugins/ha/ha_segments.h +++ b/src/libcharon/plugins/ha/ha_segments.h @@ -55,7 +55,7 @@ struct ha_segments_t { * Activate a set of IKE_SAs identified by a segment. * * @param segment numerical segment to takeover, 0 for all - * @param notify wheter to notify other nodes about activation + * @param notify whether to notify other nodes about activation */ void (*activate)(ha_segments_t *this, u_int segment, bool notify); @@ -63,7 +63,7 @@ struct ha_segments_t { * Deactivate a set of IKE_SAs identified by a segment. * * @param segment numerical segment to takeover, 0 for all - * @param notify wheter to notify other nodes about deactivation + * @param notify whether to notify other nodes about deactivation */ void (*deactivate)(ha_segments_t *this, u_int segment, bool notify); diff --git a/src/libcharon/plugins/radattr/Makefile.am b/src/libcharon/plugins/radattr/Makefile.am new file mode 100644 index 000000000..0ea8df5d1 --- /dev/null +++ b/src/libcharon/plugins/radattr/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libradius + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-radattr.la +else +libstrongswan_radattr_la_LIBADD = $(top_builddir)/src/libradius/libradius.la +plugin_LTLIBRARIES = libstrongswan-radattr.la +endif + +libstrongswan_radattr_la_SOURCES = radattr_plugin.h radattr_plugin.c \ + radattr_listener.h radattr_listener.c + +libstrongswan_radattr_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/radattr/radattr_listener.c b/src/libcharon/plugins/radattr/radattr_listener.c new file mode 100644 index 000000000..88ab60582 --- /dev/null +++ b/src/libcharon/plugins/radattr/radattr_listener.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "radattr_listener.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <errno.h> + +#include <daemon.h> + +#include <radius_message.h> + +/** + * Maximum size of an attribute to add + */ +#define MAX_ATTR_SIZE 1024 + +typedef struct private_radattr_listener_t private_radattr_listener_t; + +/** + * Private data of an radattr_listener_t object. + */ +struct private_radattr_listener_t { + + /** + * Public radattr_listener_t interface. + */ + radattr_listener_t public; + + /** + * Directory to look for attribute files + */ + char *dir; + + /** + * IKE_AUTH message ID to attribute + */ + int mid; +}; + +/** + * Print RADIUS attributes found in IKE message notifies + */ +static void print_radius_attributes(private_radattr_listener_t *this, + message_t *message) +{ + radius_attribute_type_t type; + enumerator_t *enumerator; + notify_payload_t *notify; + payload_t *payload; + chunk_t data; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE) + { + data = notify->get_notification_data(notify); + if (data.len >= 2) + { + type = data.ptr[0]; + data = chunk_skip(data, 2); + if (chunk_printable(data, NULL, 0)) + { + DBG1(DBG_IKE, "received RADIUS %N: %.*s", + radius_attribute_type_names, type, + (int)data.len, data.ptr); + } + else + { + DBG1(DBG_IKE, "received RADIUS %N: %#B", + radius_attribute_type_names, type, &data); + + } + } + } + } + } + enumerator->destroy(enumerator); +} + +/** + * Add a RADIUS attribute from a client-ID specific file to an IKE message + */ +static void add_radius_attribute(private_radattr_listener_t *this, + ike_sa_t *ike_sa, message_t *message) +{ + if (this->dir && + (this->mid == -1 || message->get_message_id(message) == this->mid)) + { + identification_t *id; + auth_cfg_t *auth; + char path[PATH_MAX]; + chunk_t data; + struct stat sb; + void *addr; + int fd; + + auth = ike_sa->get_auth_cfg(ike_sa, TRUE); + id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); + if (!id) + { + id = ike_sa->get_my_id(ike_sa); + } + + snprintf(path, sizeof(path), "%s/%Y", this->dir, id); + fd = open(path, O_RDONLY); + if (fd != -1) + { + if (fstat(fd, &sb) != -1) + { + if (sb.st_size <= MAX_ATTR_SIZE) + { + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr != MAP_FAILED) + { + data = chunk_create(addr, sb.st_size); + if (data.len >= 2) + { + DBG1(DBG_CFG, "adding RADIUS %N attribute", + radius_attribute_type_names, data.ptr[0]); + message->add_notify(message, FALSE, + RADIUS_ATTRIBUTE, data); + } + munmap(addr, sb.st_size); + } + else + { + DBG1(DBG_CFG, "mapping RADIUS attribute '%s' failed: %s", + path, strerror(errno)); + } + } + else + { + DBG1(DBG_CFG, "RADIUS attribute '%s' exceeds size limit", + path); + } + } + else + { + DBG1(DBG_CFG, "fstat RADIUS attribute '%s' failed: %s", + path, strerror(errno)); + } + close(fd); + } + else + { + DBG1(DBG_CFG, "reading RADIUS attribute '%s' failed: %s", + path, strerror(errno)); + } + } +} + +METHOD(listener_t, message, bool, + private_radattr_listener_t *this, + ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain) +{ + if (plain && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN) && + message->get_exchange_type(message) == IKE_AUTH && + message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) + { + if (incoming) + { + print_radius_attributes(this, message); + } + else + { + add_radius_attribute(this, ike_sa, message); + } + } + return TRUE; +} + + +METHOD(radattr_listener_t, destroy, void, + private_radattr_listener_t *this) +{ + free(this); +} + +/** + * See header + */ +radattr_listener_t *radattr_listener_create() +{ + private_radattr_listener_t *this; + + INIT(this, + .public = { + .listener = { + .message = _message, + }, + .destroy = _destroy, + }, + .dir = lib->settings->get_str(lib->settings, + "charon.plugins.radattr.dir", NULL), + .mid = lib->settings->get_int(lib->settings, + "charon.plugins.radattr.message_id", -1), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/radattr/radattr_listener.h b/src/libcharon/plugins/radattr/radattr_listener.h new file mode 100644 index 000000000..9a14827fc --- /dev/null +++ b/src/libcharon/plugins/radattr/radattr_listener.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup radattr_listener radattr_listener + * @{ @ingroup + */ + +#ifndef RADATTR_LISTENER_H_ +#define RADATTR_LISTENER_H_ + +#include <bus/listeners/listener.h> + +typedef struct radattr_listener_t radattr_listener_t; + +/** + * Output received RADIUS attributes, inject custom attributes. + */ +struct radattr_listener_t { + + /** + * Implements a listener. + */ + listener_t listener; + + /** + * Destroy a radattr_listener_t. + */ + void (*destroy)(radattr_listener_t *this); +}; + +/** + * Create a radattr_listener instance. + */ +radattr_listener_t *radattr_listener_create(); + +#endif /** RADATTR_LISTENER_H_ @}*/ diff --git a/src/libcharon/plugins/radattr/radattr_plugin.c b/src/libcharon/plugins/radattr/radattr_plugin.c new file mode 100644 index 000000000..85ea326ac --- /dev/null +++ b/src/libcharon/plugins/radattr/radattr_plugin.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "radattr_plugin.h" + +#include "radattr_listener.h" + +#include <daemon.h> + +typedef struct private_radattr_plugin_t private_radattr_plugin_t; + +/** + * private data of radattr plugin + */ +struct private_radattr_plugin_t { + + /** + * implements plugin interface + */ + radattr_plugin_t public; + + /** + * Listener acting on messages + */ + radattr_listener_t *listener; +}; + +METHOD(plugin_t, get_name, char*, + private_radattr_plugin_t *this) +{ + return "radattr"; +} + +METHOD(plugin_t, destroy, void, + private_radattr_plugin_t *this) +{ + charon->bus->remove_listener(charon->bus, &this->listener->listener); + this->listener->destroy(this->listener); + free(this); +} + +/** + * Plugin constructor + */ +plugin_t *radattr_plugin_create() +{ + private_radattr_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .reload = (void*)return_false, + .destroy = _destroy, + }, + }, + .listener = radattr_listener_create(), + ); + + charon->bus->add_listener(charon->bus, &this->listener->listener); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/radattr/radattr_plugin.h b/src/libcharon/plugins/radattr/radattr_plugin.h new file mode 100644 index 000000000..c3bad5a3a --- /dev/null +++ b/src/libcharon/plugins/radattr/radattr_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup radattr radattr + * @ingroup cplugins + * + * @defgroup radattr_plugin radattr_plugin + * @{ @ingroup radattr + */ + +#ifndef RADATTR_PLUGIN_H_ +#define RADATTR_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct radattr_plugin_t radattr_plugin_t; + +/** + * Plugin to inject/process custom RADIUS attributes. + */ +struct radattr_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** RADATTR_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index 3264cb802..a58d904c5 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -609,8 +609,7 @@ METHOD(stroke_control_t, unroute, void, { child_sa_t *child_sa; enumerator_t *enumerator; - u_int32_t id; - bool found = FALSE; + u_int32_t id = 0; if (charon->shunts->uninstall(charon->shunts, msg->unroute.name)) { @@ -624,15 +623,17 @@ METHOD(stroke_control_t, unroute, void, if (streq(msg->unroute.name, child_sa->get_name(child_sa))) { id = child_sa->get_reqid(child_sa); - enumerator->destroy(enumerator); - charon->traps->uninstall(charon->traps, id); - fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name); - found = TRUE; + break; } } enumerator->destroy(enumerator); - if (!found) + if (id) + { + charon->traps->uninstall(charon->traps, id); + fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name); + } + else { fprintf(out, "configuration '%s' not found\n", msg->unroute.name); } diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c index aff0e66b1..cdf69135a 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.c +++ b/src/libcharon/plugins/stroke/stroke_cred.c @@ -71,6 +71,12 @@ struct private_stroke_cred_t { mem_cred_t *creds; /** + * ignore missing CA basic constraint (i.e. treat all certificates in + * ipsec.conf ca sections and ipsec.d/cacert as CA certificates) + */ + bool force_ca_cert; + + /** * cache CRLs to disk? */ bool cachecrl; @@ -91,10 +97,21 @@ METHOD(stroke_cred_t, load_ca, certificate_t*, snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename); } - cert = lib->creds->create(lib->creds, + if (this->force_ca_cert) + { /* we treat this certificate as a CA certificate even if it has no + * CA basic constraint */ + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA, + BUILD_END); + } + else + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, path, BUILD_END); + } if (cert) { x509_t *x509 = (x509_t*)cert; @@ -171,11 +188,21 @@ static void load_certdir(private_stroke_cred_t *this, char *path, { case CERT_X509: if (flag & X509_CA) - { /* for CA certificates, we strictly require - * the CA basic constraint to be set */ - cert = lib->creds->create(lib->creds, + { + if (this->force_ca_cert) + { /* treat this certificate as CA cert even it has no + * CA basic constraint */ + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, file, BUILD_X509_FLAG, + X509_CA, BUILD_END); + } + else + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, file, BUILD_END); + } if (cert) { x509_t *x509 = (x509_t*)cert; @@ -1073,6 +1100,9 @@ stroke_cred_t *stroke_cred_create() lib->credmgr->add_set(lib->credmgr, &this->creds->set); + this->force_ca_cert = lib->settings->get_bool(lib->settings, + "charon.plugins.stroke.ignore_missing_ca_basic_constraint", FALSE); + load_certs(this); load_secrets(this, SECRETS_FILE, 0, NULL); diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 8bb1a98ef..6b256f29b 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -426,7 +426,6 @@ METHOD(stroke_list_t, status, void, if (all) { peer_cfg_t *peer_cfg; - plugin_t *plugin; char *pool; host_t *host; u_int32_t dpd; @@ -461,14 +460,8 @@ METHOD(stroke_list_t, status, void, } fprintf(out, ", scheduled: %d\n", lib->scheduler->get_job_load(lib->scheduler)); - fprintf(out, " loaded plugins: "); - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (enumerator->enumerate(enumerator, &plugin, NULL)) - { - fprintf(out, "%s ", plugin->get_name(plugin)); - } - enumerator->destroy(enumerator); - fprintf(out, "\n"); + fprintf(out, " loaded plugins: %s\n", + lib->plugins->loaded_plugins(lib->plugins)); first = TRUE; enumerator = this->attribute->create_pool_enumerator(this->attribute); diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 21d15afe6..4956b011f 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -25,7 +26,10 @@ #include <hydra.h> #include <daemon.h> +#include <threading/mutex.h> #include <threading/thread.h> +#include <threading/condvar.h> +#include <utils/linked_list.h> #include <processing/jobs/callback_job.h> #include "stroke_config.h" @@ -35,6 +39,12 @@ #include "stroke_attribute.h" #include "stroke_list.h" +/** + * To avoid clogging the thread pool with (blocking) jobs, we limit the number + * of concurrently handled stroke commands. + */ +#define MAX_CONCURRENT_DEFAULT 4 + typedef struct stroke_job_context_t stroke_job_context_t; typedef struct private_stroke_socket_t private_stroke_socket_t; @@ -56,7 +66,37 @@ struct private_stroke_socket_t { /** * job accepting stroke messages */ - callback_job_t *job; + callback_job_t *receiver; + + /** + * job handling stroke messages + */ + callback_job_t *handler; + + /** + * queued stroke commands + */ + linked_list_t *commands; + + /** + * lock for command list + */ + mutex_t *mutex; + + /** + * condvar to signal the arrival or completion of commands + */ + condvar_t *condvar; + + /** + * the number of currently handled commands + */ + u_int handling; + + /** + * the maximum number of concurrently handled commands + */ + u_int max_concurrent; /** * configuration backend @@ -84,7 +124,7 @@ struct private_stroke_socket_t { stroke_ca_t *ca; /** - * Status information logging + * status information logging */ stroke_list_t *list; }; @@ -450,7 +490,7 @@ static void stroke_loglevel(private_stroke_socket_t *this, msg->loglevel.level, msg->loglevel.type); group = enum_from_name(debug_names, msg->loglevel.type); - if (group < 0) + if ((int)group < 0) { fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); return; @@ -492,6 +532,18 @@ static void stroke_job_context_destroy(stroke_job_context_t *this) } /** + * called to signal the completion of a command + */ +static inline job_requeue_t job_processed(private_stroke_socket_t *this) +{ + this->mutex->lock(this->mutex); + this->handling--; + this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); + return JOB_REQUEUE_NONE; +} + +/** * process a stroke request from the socket pointed by "fd" */ static job_requeue_t process(stroke_job_context_t *ctx) @@ -509,7 +561,7 @@ static job_requeue_t process(stroke_job_context_t *ctx) { DBG1(DBG_CFG, "reading length of stroke message failed: %s", strerror(errno)); - return JOB_REQUEUE_NONE; + return job_processed(this); } /* read message */ @@ -518,14 +570,14 @@ static job_requeue_t process(stroke_job_context_t *ctx) if (bytes_read != msg_length) { DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); - return JOB_REQUEUE_NONE; + return job_processed(this); } out = fdopen(strokefd, "w+"); if (out == NULL) { DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno)); - return JOB_REQUEUE_NONE; + return job_processed(this); } DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length); @@ -602,11 +654,38 @@ static job_requeue_t process(stroke_job_context_t *ctx) fclose(out); /* fclose() closes underlying FD */ ctx->fd = 0; - return JOB_REQUEUE_NONE; + return job_processed(this); } /** - * Implementation of private_stroke_socket_t.stroke_receive. + * Handle queued stroke commands + */ +static job_requeue_t handle(private_stroke_socket_t *this) +{ + stroke_job_context_t *ctx; + callback_job_t *job; + bool oldstate; + + this->mutex->lock(this->mutex); + thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); + oldstate = thread_cancelability(TRUE); + while (this->commands->get_count(this->commands) == 0 || + this->handling >= this->max_concurrent) + { + this->condvar->wait(this->condvar, this->mutex); + } + thread_cancelability(oldstate); + this->commands->remove_first(this->commands, (void**)&ctx); + this->handling++; + thread_cleanup_pop(TRUE); + job = callback_job_create_with_prio((callback_job_cb_t)process, ctx, + (void*)stroke_job_context_destroy, this->handler, JOB_PRIO_HIGH); + lib->processor->queue_job(lib->processor, (job_t*)job); + return JOB_REQUEUE_DIRECT; +} + +/** + * Accept stroke commands and queue them to be handled */ static job_requeue_t receive(private_stroke_socket_t *this) { @@ -614,7 +693,6 @@ static job_requeue_t receive(private_stroke_socket_t *this) int strokeaddrlen = sizeof(strokeaddr); int strokefd; bool oldstate; - callback_job_t *job; stroke_job_context_t *ctx; oldstate = thread_cancelability(TRUE); @@ -627,17 +705,18 @@ static job_requeue_t receive(private_stroke_socket_t *this) return JOB_REQUEUE_FAIR; } - ctx = malloc_thing(stroke_job_context_t); - ctx->fd = strokefd; - ctx->this = this; - job = callback_job_create_with_prio((callback_job_cb_t)process, - ctx, (void*)stroke_job_context_destroy, this->job, JOB_PRIO_HIGH); - lib->processor->queue_job(lib->processor, (job_t*)job); + INIT(ctx, + .fd = strokefd, + .this = this, + ); + this->mutex->lock(this->mutex); + this->commands->insert_last(this->commands, ctx); + this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); return JOB_REQUEUE_FAIR; } - /** * initialize and open stroke socket */ @@ -685,7 +764,11 @@ static bool open_socket(private_stroke_socket_t *this) METHOD(stroke_socket_t, destroy, void, private_stroke_socket_t *this) { - this->job->cancel(this->job); + this->handler->cancel(this->handler); + this->receiver->cancel(this->receiver); + this->commands->destroy_function(this->commands, (void*)stroke_job_context_destroy); + this->condvar->destroy(this->condvar); + this->mutex->destroy(this->mutex); lib->credmgr->remove_set(lib->credmgr, &this->ca->set); lib->credmgr->remove_set(lib->credmgr, &this->cred->set); charon->backends->remove_backend(charon->backends, &this->config->backend); @@ -725,14 +808,24 @@ stroke_socket_t *stroke_socket_create() this->control = stroke_control_create(); this->list = stroke_list_create(this->attribute); + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); + this->commands = linked_list_create(); + this->max_concurrent = lib->settings->get_int(lib->settings, + "charon.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT); + lib->credmgr->add_set(lib->credmgr, &this->ca->set); lib->credmgr->add_set(lib->credmgr, &this->cred->set); charon->backends->add_backend(charon->backends, &this->config->backend); hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider); - this->job = callback_job_create_with_prio((callback_job_cb_t)receive, + this->receiver = callback_job_create_with_prio((callback_job_cb_t)receive, + this, NULL, NULL, JOB_PRIO_CRITICAL); + lib->processor->queue_job(lib->processor, (job_t*)this->receiver); + + this->handler = callback_job_create_with_prio((callback_job_cb_t)handle, this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, (job_t*)this->handler); return &this->public; } diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc.c b/src/libcharon/plugins/tnc_imc/tnc_imc.c index 52e526604..a1f2d770f 100644 --- a/src/libcharon/plugins/tnc_imc/tnc_imc.c +++ b/src/libcharon/plugins/tnc_imc/tnc_imc.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Mike McCauley - * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2011 Andreas Steffen, + * HSR 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 @@ -17,8 +18,11 @@ #include <dlfcn.h> +#include <tncif_pa_subtypes.h> + #include <debug.h> #include <library.h> +#include <utils/linked_list.h> #include <threading/mutex.h> typedef struct private_tnc_imc_t private_tnc_imc_t; @@ -54,9 +58,19 @@ struct private_tnc_imc_t { TNC_IMCID id; /** - * List of message types supported by IMC + * list of additional IMC IDs */ - TNC_MessageTypeList supported_types; + linked_list_t *additional_ids; + + /** + * List of message types supported by IMC - Vendor ID part + */ + TNC_VendorIDList supported_vids; + + /** + * List of message types supported by IMC - Subtype part + */ + TNC_MessageSubtypeList supported_subtypes; /** * Number of supported message types @@ -81,6 +95,54 @@ METHOD(imc_t, get_id, TNC_IMCID, return this->id; } +METHOD(imc_t, add_id, void, + private_tnc_imc_t *this, TNC_IMCID id) +{ + void *pointer; + + /* store the scalar value in the pointer */ + pointer = (void*)id; + this->additional_ids->insert_last(this->additional_ids, pointer); +} + +METHOD(imc_t, has_id, bool, + private_tnc_imc_t *this, TNC_IMCID id) +{ + enumerator_t *enumerator; + TNC_IMCID additional_id; + void *pointer; + bool found = FALSE; + + /* check primary IMC ID */ + if (id == this->id) + { + return TRUE; + } + + /* return if there are no additional IMC IDs */ + if (this->additional_ids->get_count(this->additional_ids) == 0) + { + return FALSE; + } + + /* check additional IMC IDs */ + enumerator = this->additional_ids->create_enumerator(this->additional_ids); + while (enumerator->enumerate(enumerator, &pointer)) + { + /* interpret pointer as scalar value */ + additional_id = (TNC_UInt32)pointer; + + if (id == additional_id) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + return found; +} + METHOD(imc_t, get_name, char*, private_tnc_imc_t *this) { @@ -91,66 +153,150 @@ METHOD(imc_t, set_message_types, void, private_tnc_imc_t *this, TNC_MessageTypeList supported_types, TNC_UInt32 type_count) { - char buf[512]; + char buf[BUF_LEN]; char *pos = buf; int len = sizeof(buf); - int written; + int i, written; + size_t size; + TNC_VendorID vid; + TNC_MessageSubtype subtype; + enum_name_t *pa_subtype_names; /* lock the imc_t instance */ this->mutex->lock(this->mutex); - /* Free an existing MessageType list */ - free(this->supported_types); - this->supported_types = NULL; + /* Free existing VendorID and MessageSubtype lists */ + free(this->supported_vids); + this->supported_vids = NULL; + free(this->supported_subtypes); + this->supported_subtypes = NULL; /* Store the new MessageType list */ this->type_count = type_count; if (type_count && supported_types) { - size_t size = type_count * sizeof(TNC_MessageType); - int i; + size = type_count * sizeof(TNC_VendorID); + this->supported_vids = malloc(size); + size = type_count * sizeof(TNC_MessageSubtype); + this->supported_subtypes = malloc(size); for (i = 0; i < type_count; i++) { - written = snprintf(pos, len, " 0x%08x", supported_types[i]); + vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY; + subtype = supported_types[i] & TNC_SUBTYPE_ANY; + + pa_subtype_names = get_pa_subtype_names(vid); + if (pa_subtype_names) + { + written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x", + pen_names, vid, pa_subtype_names, subtype, + vid, subtype); + } + else + { + written = snprintf(pos, len," '%N' 0x%06x/0x%02x", + pen_names, vid, vid, subtype); + } if (written >= len) { break; } pos += written; len -= written; + + this->supported_vids[i] = vid; + this->supported_subtypes[i] = subtype; } - this->supported_types = malloc(size); - memcpy(this->supported_types, supported_types, size); } *pos = '\0'; DBG2(DBG_TNC, "IMC %u supports %u message type%s:%s", this->id, type_count, (type_count == 1) ? "":"s", buf); + /* unlock the imc_t instance */ + this->mutex->unlock(this->mutex); +} + +METHOD(imc_t, set_message_types_long, void, + private_tnc_imc_t *this, TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count) +{ + char buf[BUF_LEN]; + char *pos = buf; + int len = sizeof(buf); + int i, written; + size_t size; + TNC_VendorID vid; + TNC_MessageSubtype subtype; + enum_name_t *pa_subtype_names; + /* lock the imc_t instance */ + this->mutex->lock(this->mutex); + + /* Free existing VendorID and MessageSubtype lists */ + free(this->supported_vids); + this->supported_vids = NULL; + free(this->supported_subtypes); + this->supported_subtypes = NULL; + + /* Store the new MessageType list */ + this->type_count = type_count; + if (type_count && supported_vids && supported_subtypes) + { + size = type_count * sizeof(TNC_VendorID); + this->supported_vids = malloc(size); + memcpy(this->supported_vids, supported_vids, size); + size = type_count * sizeof(TNC_MessageSubtype); + this->supported_subtypes = malloc(size); + memcpy(this->supported_subtypes, supported_subtypes, size); + + for (i = 0; i < type_count; i++) + { + vid = supported_vids[i]; + subtype = supported_subtypes[i]; + + pa_subtype_names = get_pa_subtype_names(vid); + if (pa_subtype_names) + { + written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x", + pen_names, vid, pa_subtype_names, subtype, + vid, subtype); + } + else + { + written = snprintf(pos, len," '%N' 0x%06x/0x%08x", + pen_names, vid, vid, subtype); + } + if (written >= len) + { + break; + } + pos += written; + len -= written; + } + } + *pos = '\0'; + DBG2(DBG_TNC, "IMC %u supports %u message type%s:%s", + this->id, type_count, (type_count == 1) ? "":"s", buf); + + /* unlock the imc_t instance */ this->mutex->unlock(this->mutex); } METHOD(imc_t, type_supported, bool, - private_tnc_imc_t *this, TNC_MessageType message_type) + private_tnc_imc_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype) { - TNC_VendorID msg_vid, vid; - TNC_MessageSubtype msg_subtype, subtype; + TNC_VendorID vid; + TNC_MessageSubtype subtype; int i; - msg_vid = (message_type >> 8) & TNC_VENDORID_ANY; - msg_subtype = message_type & TNC_SUBTYPE_ANY; - for (i = 0; i < this->type_count; i++) { - vid = (this->supported_types[i] >> 8) & TNC_VENDORID_ANY; - subtype = this->supported_types[i] & TNC_SUBTYPE_ANY; - - if (this->supported_types[i] == message_type - || (subtype == TNC_SUBTYPE_ANY - && (msg_vid == vid || vid == TNC_VENDORID_ANY)) - || (vid == TNC_VENDORID_ANY - && (msg_subtype == subtype || subtype == TNC_SUBTYPE_ANY))) + vid = this->supported_vids[i]; + subtype = this->supported_subtypes[i]; + + if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) || + (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY || + subtype == msg_subtype))) { return TRUE; } @@ -163,7 +309,9 @@ METHOD(imc_t, destroy, void, { dlclose(this->handle); this->mutex->destroy(this->mutex); - free(this->supported_types); + this->additional_ids->destroy(this->additional_ids); + free(this->supported_vids); + free(this->supported_subtypes); free(this->name); free(this->path); free(this); @@ -180,13 +328,17 @@ imc_t* tnc_imc_create(char *name, char *path) .public = { .set_id = _set_id, .get_id = _get_id, + .add_id = _add_id, + .has_id = _has_id, .get_name = _get_name, .set_message_types = _set_message_types, + .set_message_types_long = _set_message_types_long, .type_supported = _type_supported, .destroy = _destroy, }, .name = name, .path = path, + .additional_ids = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); @@ -220,6 +372,8 @@ imc_t* tnc_imc_create(char *name, char *path) } this->public.receive_message = dlsym(this->handle, "TNC_IMC_ReceiveMessage"); + this->public.receive_message_long = + dlsym(this->handle, "TNC_IMC_ReceiveMessageLong"); this->public.batch_ending = dlsym(this->handle, "TNC_IMC_BatchEnding"); this->public.terminate = diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c b/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c index 46c131b44..90a607ccc 100644 --- a/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c +++ b/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c @@ -19,8 +19,6 @@ #include <debug.h> -#define TNC_IMVID_ANY 0xffff - /** * Called by the IMC to inform a TNCC about the set of message types the IMC * is able to receive @@ -40,6 +38,25 @@ TNC_Result TNC_TNCC_ReportMessageTypes(TNC_IMCID imc_id, } /** + * Called by the IMC to inform a TNCC about the set of message types the IMC + * is able to receive. This function supports long message types. + */ +TNC_Result TNC_TNCC_ReportMessageTypesLong(TNC_IMCID imc_id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count) +{ + if (!tnc->imcs->is_registered(tnc->imcs, imc_id)) + { + DBG1(DBG_TNC, "ignoring ReportMessageTypesLong() from unregistered IMC %u", + imc_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return tnc->imcs->set_message_types_long(tnc->imcs, imc_id, supported_vids, + supported_subtypes, type_count); +} + +/** * Called by the IMC to ask a TNCC to retry an Integrity Check Handshake */ TNC_Result TNC_TNCC_RequestHandshakeRetry(TNC_IMCID imc_id, @@ -65,14 +82,97 @@ TNC_Result TNC_TNCC_SendMessage(TNC_IMCID imc_id, TNC_UInt32 msg_len, TNC_MessageType msg_type) { + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + if (!tnc->imcs->is_registered(tnc->imcs, imc_id)) { DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMC %u", imc_id); return TNC_RESULT_INVALID_PARAMETER; } + msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + return tnc->tnccs->send_message(tnc->tnccs, imc_id, TNC_IMVID_ANY, - connection_id, msg, msg_len, msg_type); + connection_id, 0, msg, msg_len, msg_vid, msg_subtype); +} + +/** + * Called by the IMC when an IMC-IMV message is to be sent over IF-TNCCS 2.0 + */ +TNC_Result TNC_TNCC_SendMessageLong(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 imv_id) +{ + if (!tnc->imcs->is_registered(tnc->imcs, imc_id)) + { + DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMC %u", + imc_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return tnc->tnccs->send_message(tnc->tnccs, imc_id, imv_id, connection_id, + msg_flags, msg, msg_len, msg_vid, msg_subtype); +} + +/** + * Called by the IMC to get the value of an attribute associated with a + * connection or with the TNCC as a whole. + */ +TNC_Result TNC_TNCC_GetAttribute(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_AttributeID attribute_id, + TNC_UInt32 buffer_len, + TNC_BufferReference buffer, + TNC_UInt32 *out_value_len) +{ + if (!tnc->imcs->is_registered(tnc->imcs, imc_id)) + { + DBG1(DBG_TNC, "ignoring GetAttribute() from unregistered IMC %u", + imc_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return tnc->tnccs->get_attribute(tnc->tnccs, TRUE, imc_id, connection_id, + attribute_id, buffer_len, buffer, out_value_len); +} + +/** + * Called by the IMC to set the value of an attribute associated with a + * connection or with the TNCC as a whole. + */ +TNC_Result TNC_TNCC_SetAttribute(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_AttributeID attribute_id, + TNC_UInt32 buffer_len, + TNC_BufferReference buffer) +{ + if (!tnc->imcs->is_registered(tnc->imcs, imc_id)) + { + DBG1(DBG_TNC, "ignoring SetAttribute() from unregistered IMC %u", + imc_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return tnc->tnccs->set_attribute(tnc->tnccs, TRUE, imc_id, connection_id, + attribute_id, buffer_len, buffer); +} + +/** + * Called by the IMC when it wants to reserve an additional IMC ID for itself + */ +TNC_Result TNC_TNCC_ReserveAdditionalIMCID(TNC_IMCID imc_id, TNC_UInt32 *new_id) +{ + if (tnc->imcs->reserve_id(tnc->imcs, imc_id, new_id)) + { + return TNC_RESULT_SUCCESS; + } + DBG1(DBG_TNC, "ignoring ReserveAdditionalIMCID() from unregistered IMC %u", + imc_id); + return TNC_RESULT_INVALID_PARAMETER; } /** @@ -86,6 +186,10 @@ TNC_Result TNC_TNCC_BindFunction(TNC_IMCID id, { *function_pointer = (void*)TNC_TNCC_ReportMessageTypes; } + else if (streq(function_name, "TNC_TNCC_ReportMessageTypesLong")) + { + *function_pointer = (void*)TNC_TNCC_ReportMessageTypesLong; + } else if (streq(function_name, "TNC_TNCC_RequestHandshakeRetry")) { *function_pointer = (void*)TNC_TNCC_RequestHandshakeRetry; @@ -94,6 +198,22 @@ TNC_Result TNC_TNCC_BindFunction(TNC_IMCID id, { *function_pointer = (void*)TNC_TNCC_SendMessage; } + else if (streq(function_name, "TNC_TNCC_SendMessageLong")) + { + *function_pointer = (void*)TNC_TNCC_SendMessageLong; + } + else if (streq(function_name, "TNC_TNCC_GetAttribute")) + { + *function_pointer = (void*)TNC_TNCC_GetAttribute; + } + else if (streq(function_name, "TNC_TNCC_SetAttribute")) + { + *function_pointer = (void*)TNC_TNCC_SetAttribute; + } + else if (streq(function_name, "TNC_TNCC_ReserveAdditionalIMCID")) + { + *function_pointer = (void*)TNC_TNCC_ReserveAdditionalIMCID; + } else { return TNC_RESULT_INVALID_PARAMETER; diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c b/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c index 202df5f5c..e101cf974 100644 --- a/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c +++ b/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Mike McCauley - * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2011 Andreas Steffen + * HSR 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 @@ -130,9 +131,34 @@ METHOD(imc_manager_t, is_registered, bool, enumerator = this->imcs->create_enumerator(this->imcs); while (enumerator->enumerate(enumerator, &imc)) { - if (id == imc->get_id(imc)) + if (imc->has_id(imc, id)) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + return found; +} + +METHOD(imc_manager_t, reserve_id, bool, + private_tnc_imc_manager_t *this, TNC_IMCID id, TNC_UInt32 *new_id) +{ + enumerator_t *enumerator; + imc_t *imc; + bool found = FALSE; + + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (imc->get_id(imc)) { found = TRUE; + *new_id = this->next_imc_id++; + imc->add_id(imc, *new_id); + DBG2(DBG_TNC, "additional ID %u reserved for IMC with primary ID %u", + *new_id, id); break; } } @@ -203,30 +229,77 @@ METHOD(imc_manager_t, set_message_types, TNC_Result, return result; } +METHOD(imc_manager_t, set_message_types_long, TNC_Result, + private_tnc_imc_manager_t *this, TNC_IMCID id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count) +{ + enumerator_t *enumerator; + imc_t *imc; + TNC_Result result = TNC_RESULT_FATAL; + + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (id == imc->get_id(imc)) + { + imc->set_message_types_long(imc, supported_vids, supported_subtypes, + type_count); + result = TNC_RESULT_SUCCESS; + break; + } + } + enumerator->destroy(enumerator); + return result; +} + METHOD(imc_manager_t, receive_message, void, private_tnc_imc_manager_t *this, TNC_ConnectionID connection_id, - TNC_BufferReference message, - TNC_UInt32 message_len, - TNC_MessageType message_type) + bool excl, + 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) { bool type_supported = FALSE; + TNC_MessageType msg_type; + TNC_UInt32 msg_flags; enumerator_t *enumerator; imc_t *imc; enumerator = this->imcs->create_enumerator(this->imcs); while (enumerator->enumerate(enumerator, &imc)) { - if (imc->receive_message && imc->type_supported(imc, message_type)) + if (imc->type_supported(imc, msg_vid, msg_subtype) && + (!excl || (excl && imc->has_id(imc, dst_imc_id)) )) { - type_supported = TRUE; - imc->receive_message(imc->get_id(imc), connection_id, - message, message_len, message_type); + if (imc->receive_message_long && src_imv_id) + { + type_supported = TRUE; + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + imc->receive_message_long(imc->get_id(imc), connection_id, + msg_flags, msg, msg_len, msg_vid, msg_subtype, + src_imv_id, dst_imc_id); + + } + else if (imc->receive_message && msg_vid <= TNC_VENDORID_ANY && + msg_subtype <= TNC_SUBTYPE_ANY) + { + type_supported = TRUE; + msg_type = (msg_vid << 8) | msg_subtype; + imc->receive_message(imc->get_id(imc), connection_id, + msg, msg_len, msg_type); + } } } enumerator->destroy(enumerator); if (!type_supported) { - DBG2(DBG_TNC, "message type 0x%08x not supported by any IMC", message_type); + DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMC", + msg_vid, msg_subtype); } } @@ -279,10 +352,12 @@ imc_manager_t* tnc_imc_manager_create(void) .remove = _remove_, /* avoid name conflict with stdio.h */ .load = _load, .is_registered = _is_registered, + .reserve_id = _reserve_id, .get_preferred_language = _get_preferred_language, .notify_connection_change = _notify_connection_change, .begin_handshake = _begin_handshake, .set_message_types = _set_message_types, + .set_message_types_long = _set_message_types_long, .receive_message = _receive_message, .batch_ending = _batch_ending, .destroy = _destroy, diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv.c b/src/libcharon/plugins/tnc_imv/tnc_imv.c index f9cfc3417..f0b150743 100644 --- a/src/libcharon/plugins/tnc_imv/tnc_imv.c +++ b/src/libcharon/plugins/tnc_imv/tnc_imv.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Mike McCauley - * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2011 Andreas Steffen, + * HSR 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 @@ -17,8 +18,11 @@ #include <dlfcn.h> +#include <tncif_pa_subtypes.h> + #include <debug.h> #include <library.h> +#include <utils/linked_list.h> #include <threading/mutex.h> typedef struct private_tnc_imv_t private_tnc_imv_t; @@ -54,9 +58,19 @@ struct private_tnc_imv_t { TNC_IMVID id; /** - * List of message types supported by IMC + * List of additional IMV IDs */ - TNC_MessageTypeList supported_types; + linked_list_t *additional_ids; + + /** + * List of message types supported by IMV - Vendor ID part + */ + TNC_VendorIDList supported_vids; + + /** + * List of message types supported by IMV - Subtype part + */ + TNC_MessageSubtypeList supported_subtypes; /** * Number of supported message types @@ -81,6 +95,50 @@ METHOD(imv_t, get_id, TNC_IMVID, return this->id; } +METHOD(imv_t, add_id, void, + private_tnc_imv_t *this, TNC_IMVID id) +{ + TNC_IMVID *new_id; + + new_id = malloc_thing(TNC_IMVID); + *new_id = id; + this->additional_ids->insert_last(this->additional_ids, new_id); +} + +METHOD(imv_t, has_id, bool, + private_tnc_imv_t *this, TNC_IMVID id) +{ + enumerator_t *enumerator; + TNC_IMVID *additional_id; + bool found = FALSE; + + /* check primary IMV ID */ + if (id == this->id) + { + return TRUE; + } + + /* return if there are no additional IMV IDs */ + if (this->additional_ids->get_count(this->additional_ids) == 0) + { + return FALSE; + } + + /* check additional IMV IDs */ + enumerator = this->additional_ids->create_enumerator(this->additional_ids); + while (enumerator->enumerate(enumerator, &additional_id)) + { + if (id == *additional_id) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + return found; +} + METHOD(imv_t, get_name, char*, private_tnc_imv_t *this) { @@ -91,67 +149,150 @@ METHOD(imv_t, set_message_types, void, private_tnc_imv_t *this, TNC_MessageTypeList supported_types, TNC_UInt32 type_count) { - char buf[512]; + char buf[BUF_LEN]; char *pos = buf; int len = sizeof(buf); - int written; + int i, written; + size_t size; + TNC_VendorID vid; + TNC_MessageSubtype subtype; + enum_name_t *pa_subtype_names; /* lock the imv_t instance */ this->mutex->lock(this->mutex); - /* Free an existing MessageType list */ - free(this->supported_types); - this->supported_types = NULL; + /* Free existing VendorID and MessageSubtype lists */ + free(this->supported_vids); + this->supported_vids = NULL; + free(this->supported_subtypes); + this->supported_subtypes = NULL; /* Store the new MessageType list */ this->type_count = type_count; if (type_count && supported_types) { - size_t size = type_count * sizeof(TNC_MessageType); - - int i; + size = type_count * sizeof(TNC_VendorID); + this->supported_vids = malloc(size); + size = type_count * sizeof(TNC_MessageSubtype); + this->supported_subtypes = malloc(size); for (i = 0; i < type_count; i++) { - written = snprintf(pos, len, " 0x%08x", supported_types[i]); + vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY; + subtype = supported_types[i] & TNC_SUBTYPE_ANY; + + pa_subtype_names = get_pa_subtype_names(vid); + if (pa_subtype_names) + { + written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x", + pen_names, vid, pa_subtype_names, subtype, + vid, subtype); + } + else + { + written = snprintf(pos, len," '%N' 0x%06x/0x%02x", + pen_names, vid, vid, subtype); + } if (written >= len) { break; } pos += written; len -= written; + + this->supported_vids[i] = vid; + this->supported_subtypes[i] = subtype; } - this->supported_types = malloc(size); - memcpy(this->supported_types, supported_types, size); } *pos = '\0'; DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s", this->id, type_count, (type_count == 1) ? "":"s", buf); + /* unlock the imv_t instance */ + this->mutex->unlock(this->mutex); +} + +METHOD(imv_t, set_message_types_long, void, + private_tnc_imv_t *this, TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count) +{ + char buf[BUF_LEN]; + char *pos = buf; + int len = sizeof(buf); + int i, written; + size_t size; + TNC_VendorID vid; + TNC_MessageSubtype subtype; + enum_name_t *pa_subtype_names; + /* lock the imv_t instance */ + this->mutex->lock(this->mutex); + + /* Free existing VendorID and MessageSubtype lists */ + free(this->supported_vids); + this->supported_vids = NULL; + free(this->supported_subtypes); + this->supported_subtypes = NULL; + + /* Store the new MessageType list */ + this->type_count = type_count; + if (type_count && supported_vids && supported_subtypes) + { + size = type_count * sizeof(TNC_VendorID); + this->supported_vids = malloc(size); + memcpy(this->supported_vids, supported_vids, size); + size = type_count * sizeof(TNC_MessageSubtype); + this->supported_subtypes = malloc(size); + memcpy(this->supported_subtypes, supported_subtypes, size); + + for (i = 0; i < type_count; i++) + { + vid = supported_vids[i]; + subtype = supported_subtypes[i]; + + pa_subtype_names = get_pa_subtype_names(vid); + if (pa_subtype_names) + { + written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x", + pen_names, vid, pa_subtype_names, subtype, + vid, subtype); + } + else + { + written = snprintf(pos, len," '%N' 0x%06x/0x%08x", + pen_names, vid, vid, subtype); + } + if (written >= len) + { + break; + } + pos += written; + len -= written; + } + } + *pos = '\0'; + DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s", + this->id, type_count, (type_count == 1) ? "":"s", buf); + + /* unlock the imv_t instance */ this->mutex->unlock(this->mutex); } METHOD(imv_t, type_supported, bool, - private_tnc_imv_t *this, TNC_MessageType message_type) + private_tnc_imv_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype) { - TNC_VendorID msg_vid, vid; - TNC_MessageSubtype msg_subtype, subtype; + TNC_VendorID vid; + TNC_MessageSubtype subtype; int i; - msg_vid = (message_type >> 8) & TNC_VENDORID_ANY; - msg_subtype = message_type & TNC_SUBTYPE_ANY; - for (i = 0; i < this->type_count; i++) { - vid = (this->supported_types[i] >> 8) & TNC_VENDORID_ANY; - subtype = this->supported_types[i] & TNC_SUBTYPE_ANY; - - if (this->supported_types[i] == message_type - || (subtype == TNC_SUBTYPE_ANY - && (msg_vid == vid || vid == TNC_VENDORID_ANY)) - || (vid == TNC_VENDORID_ANY - && (msg_subtype == subtype || subtype == TNC_SUBTYPE_ANY))) + vid = this->supported_vids[i]; + subtype = this->supported_subtypes[i]; + + if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) || + (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY || + subtype == msg_subtype))) { return TRUE; } @@ -164,7 +305,9 @@ METHOD(imv_t, destroy, void, { dlclose(this->handle); this->mutex->destroy(this->mutex); - free(this->supported_types); + this->additional_ids->destroy_function(this->additional_ids, free); + free(this->supported_vids); + free(this->supported_subtypes); free(this->name); free(this->path); free(this); @@ -181,13 +324,17 @@ imv_t* tnc_imv_create(char *name, char *path) .public = { .set_id = _set_id, .get_id = _get_id, + .add_id = _add_id, + .has_id = _has_id, .get_name = _get_name, .set_message_types = _set_message_types, + .set_message_types_long = _set_message_types_long, .type_supported = _type_supported, .destroy = _destroy, }, .name = name, .path = path, + .additional_ids = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); @@ -222,6 +369,8 @@ imv_t* tnc_imv_create(char *name, char *path) } this->public.receive_message = dlsym(this->handle, "TNC_IMV_ReceiveMessage"); + this->public.receive_message_long = + dlsym(this->handle, "TNC_IMV_ReceiveMessageLong"); this->public.batch_ending = dlsym(this->handle, "TNC_IMV_BatchEnding"); this->public.terminate = diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c b/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c index cde1e4fe1..dd11c5009 100644 --- a/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c +++ b/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Mike McCauley - * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2011 Andreas Steffen + * HSR 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 @@ -19,8 +20,6 @@ #include <debug.h> -#define TNC_IMCID_ANY 0xffff - /** * Called by the IMV to inform a TNCS about the set of message types the IMV * is able to receive @@ -40,6 +39,25 @@ TNC_Result TNC_TNCS_ReportMessageTypes(TNC_IMVID imv_id, } /** + * Called by the IMV to inform a TNCS about the set of message types the IMV + * is able to receive. This function supports long message types. + */ +TNC_Result TNC_TNCS_ReportMessageTypesLong(TNC_IMVID imv_id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count) +{ + if (!tnc->imvs->is_registered(tnc->imvs, imv_id)) + { + DBG1(DBG_TNC, "ignoring ReportMessageTypesLong() from unregistered IMV %u", + imv_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return tnc->imvs->set_message_types_long(tnc->imvs, imv_id, supported_vids, + supported_subtypes, type_count); +} + +/** * Called by the IMV to ask a TNCS to retry an Integrity Check Handshake */ TNC_Result TNC_TNCS_RequestHandshakeRetry(TNC_IMVID imv_id, @@ -65,14 +83,42 @@ TNC_Result TNC_TNCS_SendMessage(TNC_IMVID imv_id, TNC_UInt32 msg_len, TNC_MessageType msg_type) { + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + if (!tnc->imvs->is_registered(tnc->imvs, imv_id)) { DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMV %u", imv_id); return TNC_RESULT_INVALID_PARAMETER; } + msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + return tnc->tnccs->send_message(tnc->tnccs, TNC_IMCID_ANY, imv_id, - connection_id, msg, msg_len, msg_type); + connection_id, 0, msg, msg_len, msg_vid, msg_subtype); +} + +/** + * Called by the IMV when an IMV-IMC message is to be sent over IF-TNCCS 2.0 + */ +TNC_Result TNC_TNCS_SendMessageLong(TNC_IMVID imv_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 imc_id) +{ + if (!tnc->imvs->is_registered(tnc->imvs, imv_id)) + { + DBG1(DBG_TNC, "ignoring SendMessageLong() from unregistered IMV %u", + imv_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return tnc->tnccs->send_message(tnc->tnccs, imc_id, imv_id, connection_id, + msg_flags, msg, msg_len, msg_vid, msg_subtype); } /** @@ -111,7 +157,7 @@ TNC_Result TNC_TNCS_GetAttribute(TNC_IMVID imv_id, imv_id); return TNC_RESULT_INVALID_PARAMETER; } - return tnc->tnccs->get_attribute(tnc->tnccs, imv_id, connection_id, + return tnc->tnccs->get_attribute(tnc->tnccs, FALSE, imv_id, connection_id, attribute_id, buffer_len, buffer, out_value_len); } @@ -131,11 +177,25 @@ TNC_Result TNC_TNCS_SetAttribute(TNC_IMVID imv_id, imv_id); return TNC_RESULT_INVALID_PARAMETER; } - return tnc->tnccs->set_attribute(tnc->tnccs, imv_id, connection_id, + return tnc->tnccs->set_attribute(tnc->tnccs, FALSE, imv_id, connection_id, attribute_id, buffer_len, buffer); } /** + * Called by the IMV when it wants to reserve an additional IMV ID for itself + */ +TNC_Result TNC_TNCS_ReserveAdditionalIMVID(TNC_IMVID imv_id, TNC_UInt32 *new_id) +{ + if (tnc->imvs->reserve_id(tnc->imvs, imv_id, new_id)) + { + return TNC_RESULT_SUCCESS; + } + DBG1(DBG_TNC, "ignoring ReserveAdditionalIMVID() from unregistered IMV %u", + imv_id); + return TNC_RESULT_INVALID_PARAMETER; +} + +/** * Called by the IMV when it needs a function pointer */ TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id, @@ -146,6 +206,10 @@ TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id, { *function_pointer = (void*)TNC_TNCS_ReportMessageTypes; } + else if (streq(function_name, "TNC_TNCS_ReportMessageTypesLong")) + { + *function_pointer = (void*)TNC_TNCS_ReportMessageTypesLong; + } else if (streq(function_name, "TNC_TNCS_RequestHandshakeRetry")) { *function_pointer = (void*)TNC_TNCS_RequestHandshakeRetry; @@ -154,6 +218,10 @@ TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id, { *function_pointer = (void*)TNC_TNCS_SendMessage; } + else if (streq(function_name, "TNC_TNCS_SendMessageLong")) + { + *function_pointer = (void*)TNC_TNCS_SendMessageLong; + } else if (streq(function_name, "TNC_TNCS_ProvideRecommendation")) { *function_pointer = (void*)TNC_TNCS_ProvideRecommendation; @@ -166,6 +234,10 @@ TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id, { *function_pointer = (void*)TNC_TNCS_SetAttribute; } + else if (streq(function_name, "TNC_TNCS_ReserveAdditionalIMVID")) + { + *function_pointer = (void*)TNC_TNCS_ReserveAdditionalIMVID; + } else { return TNC_RESULT_INVALID_PARAMETER; diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c b/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c index 4eee69e4d..b1da73156 100644 --- a/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c +++ b/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Mike McCauley - * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2011 Andreas Steffen + * HSR 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 @@ -147,9 +148,34 @@ METHOD(imv_manager_t, is_registered, bool, enumerator = this->imvs->create_enumerator(this->imvs); while (enumerator->enumerate(enumerator, &imv)) { - if (id == imv->get_id(imv)) + if (imv->has_id(imv, id)) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + return found; +} + +METHOD(imv_manager_t, reserve_id, bool, + private_tnc_imv_manager_t *this, TNC_IMVID id, TNC_UInt32 *new_id) +{ + enumerator_t *enumerator; + imv_t *imv; + bool found = FALSE; + + enumerator = this->imvs->create_enumerator(this->imvs); + while (enumerator->enumerate(enumerator, &imv)) + { + if (imv->get_id(imv)) { found = TRUE; + *new_id = this->next_imv_id++; + imv->add_id(imv, *new_id); + DBG2(DBG_TNC, "additional ID %u reserved for IMV with primary ID %u", + *new_id, id); break; } } @@ -267,6 +293,31 @@ METHOD(imv_manager_t, set_message_types, TNC_Result, return result; } +METHOD(imv_manager_t, set_message_types_long, TNC_Result, + private_tnc_imv_manager_t *this, TNC_IMVID id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count) +{ + enumerator_t *enumerator; + imv_t *imv; + TNC_Result result = TNC_RESULT_FATAL; + + enumerator = this->imvs->create_enumerator(this->imvs); + while (enumerator->enumerate(enumerator, &imv)) + { + if (id == imv->get_id(imv)) + { + imv->set_message_types_long(imv, supported_vids, supported_subtypes, + type_count); + result = TNC_RESULT_SUCCESS; + break; + } + } + enumerator->destroy(enumerator); + return result; +} + METHOD(imv_manager_t, solicit_recommendation, void, private_tnc_imv_manager_t *this, TNC_ConnectionID id) { @@ -283,28 +334,52 @@ METHOD(imv_manager_t, solicit_recommendation, void, METHOD(imv_manager_t, receive_message, void, private_tnc_imv_manager_t *this, TNC_ConnectionID connection_id, - TNC_BufferReference message, - TNC_UInt32 message_len, - TNC_MessageType message_type) + bool excl, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id) { bool type_supported = FALSE; + TNC_MessageType msg_type; + TNC_UInt32 msg_flags; enumerator_t *enumerator; imv_t *imv; + msg_type = (msg_vid << 8) | msg_subtype; + enumerator = this->imvs->create_enumerator(this->imvs); while (enumerator->enumerate(enumerator, &imv)) { - if (imv->receive_message && imv->type_supported(imv, message_type)) + if (imv->type_supported(imv, msg_vid, msg_subtype) && + (!excl || (excl && imv->has_id(imv, dst_imv_id)) )) { - type_supported = TRUE; - imv->receive_message(imv->get_id(imv), connection_id, - message, message_len, message_type); + if (imv->receive_message_long && src_imc_id) + { + type_supported = TRUE; + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + imv->receive_message_long(imv->get_id(imv), connection_id, + msg_flags, msg, msg_len, msg_vid, msg_subtype, + src_imc_id, dst_imv_id); + + } + else if (imv->receive_message && msg_vid <= TNC_VENDORID_ANY && + msg_subtype <= TNC_SUBTYPE_ANY) + { + type_supported = TRUE; + msg_type = (msg_vid << 8) | msg_subtype; + imv->receive_message(imv->get_id(imv), connection_id, + msg, msg_len, msg_type); + } } } enumerator->destroy(enumerator); if (!type_supported) { - DBG2(DBG_TNC, "message type 0x%08x not supported by any IMV", message_type); + DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMV", + msg_vid, msg_subtype); } } @@ -359,11 +434,13 @@ imv_manager_t* tnc_imv_manager_create(void) .remove = _remove_, /* avoid name conflict with stdio.h */ .load = _load, .is_registered = _is_registered, + .reserve_id = _reserve_id, .get_recommendation_policy = _get_recommendation_policy, .create_recommendations = _create_recommendations, .enforce_recommendation = _enforce_recommendation, .notify_connection_change = _notify_connection_change, .set_message_types = _set_message_types, + .set_message_types_long = _set_message_types_long, .solicit_recommendation = _solicit_recommendation, .receive_message = _receive_message, .batch_ending = _batch_ending, diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.am b/src/libcharon/plugins/tnc_pdp/Makefile.am new file mode 100644 index 000000000..2d4c4d55a --- /dev/null +++ b/src/libcharon/plugins/tnc_pdp/Makefile.am @@ -0,0 +1,24 @@ + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon \ + -I$(top_srcdir)/src/libradius + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-tnc-pdp.la +else +plugin_LTLIBRARIES = libstrongswan-tnc-pdp.la +libstrongswan_tnc_pdp_la_LIBADD = \ + $(top_builddir)/src/libradius/libradius.la \ + $(top_builddir)/src/libtls/libtls.la \ + $(top_builddir)/src/libtnccs/libtnccs.la +endif + +libstrongswan_tnc_pdp_la_SOURCES = \ + tnc_pdp_plugin.h tnc_pdp_plugin.c \ + tnc_pdp.h tnc_pdp.c tnc_pdp_connections.h tnc_pdp_connections.c + +libstrongswan_tnc_pdp_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c new file mode 100644 index 000000000..0625baa90 --- /dev/null +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c @@ -0,0 +1,648 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR 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 "tnc_pdp.h" +#include "tnc_pdp_connections.h" + +#include <errno.h> +#include <unistd.h> + +#include <radius_message.h> +#include <radius_mppe.h> + +#include <daemon.h> +#include <debug.h> +#include <pen/pen.h> +#include <threading/thread.h> +#include <processing/jobs/callback_job.h> +#include <sa/authenticators/eap/eap_method.h> + +typedef struct private_tnc_pdp_t private_tnc_pdp_t; + +/** + * Maximum size of a RADIUS IP packet + */ +#define MAX_PACKET 4096 + +/** + * private data of tnc_pdp_t + */ +struct private_tnc_pdp_t { + + /** + * implements tnc_pdp_t interface + */ + tnc_pdp_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * EAP method type to be used + */ + eap_type_t type; + + /** + * IPv4 RADIUS socket + */ + int ipv4; + + /** + * IPv6 RADIUS socket + */ + int ipv6; + + /** + * Callback job dispatching commands + */ + callback_job_t *job; + + /** + * RADIUS shared secret + */ + chunk_t secret; + + /** + * MD5 hasher + */ + hasher_t *hasher; + + /** + * HMAC MD5 signer, with secret set + */ + signer_t *signer; + + /** + * Random number generator for MS-MPPE salt values + */ + rng_t *rng; + + /** + * List of registered TNC-PDP connections + */ + tnc_pdp_connections_t *connections; +}; + + +/** + * Open IPv4 or IPv6 UDP RADIUS socket + */ +static int open_socket(int family, u_int16_t port) +{ + int on = TRUE; + struct sockaddr_storage addr; + socklen_t addrlen; + int skt; + + memset(&addr, 0, sizeof(addr)); + addr.ss_family = family; + + /* precalculate constants depending on address family */ + switch (family) + { + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + + htoun32(&sin->sin_addr.s_addr, INADDR_ANY); + htoun16(&sin->sin_port, port); + addrlen = sizeof(struct sockaddr_in); + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; + + memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)); + htoun16(&sin6->sin6_port, port); + addrlen = sizeof(struct sockaddr_in6); + break; + } + default: + return 0; + } + + /* open the socket */ + skt = socket(family, SOCK_DGRAM, IPPROTO_UDP); + if (skt < 0) + { + DBG1(DBG_CFG, "opening RADIUS socket failed: %s", strerror(errno)); + return 0; + } + if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) + { + DBG1(DBG_CFG, "unable to set SO_REUSEADDR on socket: %s", strerror(errno)); + close(skt); + return 0; + } + + /* bind the socket */ + if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0) + { + DBG1(DBG_CFG, "unable to bind RADIUS socket: %s", strerror(errno)); + close(skt); + return 0; + } + + return skt; +} + +/** + * Send a RADIUS message to client + */ +static void send_message(private_tnc_pdp_t *this, radius_message_t *message, + host_t *client) +{ + int fd; + chunk_t data; + + fd = (client->get_family(client) == AF_INET) ? this->ipv4 : this->ipv6; + data = message->get_encoding(message); + + DBG2(DBG_CFG, "sending RADIUS packet to %#H", client); + DBG3(DBG_CFG, "%B", &data); + + if (sendto(fd, data.ptr, data.len, 0, client->get_sockaddr(client), + *client->get_sockaddr_len(client)) != data.len) + { + DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno)); + } +} + +/** + * Encrypt a MS-MPPE-Send/Recv-Key + */ +static chunk_t encrypt_mppe_key(private_tnc_pdp_t *this, u_int8_t type, + chunk_t key, u_int16_t *salt, + radius_message_t *request) +{ + chunk_t a, r, seed, data; + u_char b[HASH_SIZE_MD5], *c; + mppe_key_t *mppe_key; + + /** + * From RFC2548 (encryption): + * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1) + * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2) + * . . . + * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i) + */ + + data = chunk_alloc(sizeof(mppe_key_t) + + HASH_SIZE_MD5 * (1 + key.len / HASH_SIZE_MD5)); + memset(data.ptr, 0x00, data.len); + + mppe_key = (mppe_key_t*)data.ptr; + mppe_key->id = htonl(PEN_MICROSOFT); + mppe_key->type = type; + mppe_key->length = data.len - sizeof(mppe_key->id); + mppe_key->key[0] = key.len; + + memcpy(&mppe_key->key[1], key.ptr, key.len); + + /** + * generate a 16 bit unique random salt value for the MPPE stream cipher + * the MSB of the salt MUST be set to 1 + */ + a = chunk_create((u_char*)&(mppe_key->salt), sizeof(mppe_key->salt)); + do + { + this->rng->get_bytes(this->rng, a.len, a.ptr); + *a.ptr |= 0x80; + } + while (mppe_key->salt == *salt); + + /* update the salt value */ + *salt = mppe_key->salt; + + r = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5); + seed = chunk_cata("cc", r, a); + + c = mppe_key->key; + while (c < data.ptr + data.len) + { + /* b(i) = MD5(S + c(i-1)) */ + this->hasher->get_hash(this->hasher, this->secret, NULL); + this->hasher->get_hash(this->hasher, seed, b); + + /* c(i) = b(i) xor p(1) */ + memxor(c, b, HASH_SIZE_MD5); + + /* prepare next round */ + seed = chunk_create(c, HASH_SIZE_MD5); + c += HASH_SIZE_MD5; + } + + return data; +} + +/** + * Send a RADIUS response for a request + */ +static void send_response(private_tnc_pdp_t *this, radius_message_t *request, + radius_message_code_t code, eap_payload_t *eap, + identification_t *group, chunk_t msk, host_t *client) +{ + radius_message_t *response; + chunk_t data, recv, send; + u_int32_t tunnel_type; + u_int16_t salt = 0; + + response = radius_message_create(code); + if (eap) + { + data = eap->get_data(eap); + DBG3(DBG_CFG, "%N payload %B", eap_type_names, this->type, &data); + + /* fragment data suitable for RADIUS */ + while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE) + { + response->add(response, RAT_EAP_MESSAGE, + chunk_create(data.ptr, MAX_RADIUS_ATTRIBUTE_SIZE)); + data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE); + } + response->add(response, RAT_EAP_MESSAGE, data); + } + if (group) + { + tunnel_type = RADIUS_TUNNEL_TYPE_ESP; + htoun32(data.ptr, tunnel_type); + data.len = sizeof(tunnel_type); + response->add(response, RAT_TUNNEL_TYPE, data); + response->add(response, RAT_FILTER_ID, group->get_encoding(group)); + } + if (msk.len) + { + recv = chunk_create(msk.ptr, msk.len / 2); + data = encrypt_mppe_key(this, MS_MPPE_RECV_KEY, recv, &salt, request); + response->add(response, RAT_VENDOR_SPECIFIC, data); + chunk_free(&data); + + send = chunk_create(msk.ptr + recv.len, msk.len - recv.len); + data = encrypt_mppe_key(this, MS_MPPE_SEND_KEY, send, &salt, request); + response->add(response, RAT_VENDOR_SPECIFIC, data); + chunk_free(&data); + } + response->set_identifier(response, request->get_identifier(request)); + response->sign(response, request->get_authenticator(request), + this->secret, this->hasher, this->signer, NULL, TRUE); + + DBG1(DBG_CFG, "sending RADIUS %N to client '%H'", radius_message_code_names, + code, client); + send_message(this, response, client); + response->destroy(response); +} + +/** + * Process EAP message + */ +static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, + host_t *source) +{ + enumerator_t *enumerator; + eap_payload_t *in, *out = NULL; + eap_method_t *method; + eap_type_t eap_type; + u_int32_t eap_vendor; + chunk_t data, message = chunk_empty, msk = chunk_empty; + chunk_t user_name = chunk_empty, nas_id = chunk_empty; + identification_t *group = NULL; + radius_message_code_t code = RMC_ACCESS_CHALLENGE; + int type; + + enumerator = request->create_enumerator(request); + while (enumerator->enumerate(enumerator, &type, &data)) + { + switch (type) + { + case RAT_USER_NAME: + user_name = data; + break; + case RAT_NAS_IDENTIFIER: + nas_id = data; + break; + case RAT_EAP_MESSAGE: + if (data.len) + { + message = chunk_cat("mc", message, data); + } + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (message.len) + { + in = eap_payload_create_data(message); + + /* apply EAP method selected by RADIUS server */ + eap_type = in->get_type(in, &eap_vendor); + + DBG3(DBG_CFG, "%N payload %B", eap_type_names, eap_type, &message); + + if (eap_type == EAP_IDENTITY) + { + identification_t *peer; + chunk_t eap_identity; + + if (message.len < 5) + { + goto end; + } + eap_identity = chunk_create(message.ptr + 5, message.len - 5); + peer = identification_create_from_data(eap_identity); + method = charon->eap->create_instance(charon->eap, this->type, + 0, EAP_SERVER, this->server, peer); + if (!method) + { + peer->destroy(peer); + goto end; + } + this->connections->add(this->connections, nas_id, user_name, peer, + method); + method->initiate(method, &out); + } + else + { + ike_sa_t *ike_sa; + auth_cfg_t *auth; + auth_rule_t type; + identification_t *data; + enumerator_t *e; + + method = this->connections->get_state(this->connections, nas_id, + user_name, &ike_sa); + if (!method) + { + goto end; + } + charon->bus->set_sa(charon->bus, ike_sa); + + switch (method->process(method, in, &out)) + { + case NEED_MORE: + code = RMC_ACCESS_CHALLENGE; + break; + case SUCCESS: + code = RMC_ACCESS_ACCEPT; + method->get_msk(method, &msk); + auth = ike_sa->get_auth_cfg(ike_sa, FALSE); + e = auth->create_enumerator(auth); + while (e->enumerate(e, &type, &data)) + { + /* look for group memberships */ + if (type == AUTH_RULE_GROUP) + { + group = data; + } + } + e->destroy(e); + + DESTROY_IF(out); + out = eap_payload_create_code(EAP_SUCCESS, + in->get_identifier(in)); + break; + case FAILED: + default: + code = RMC_ACCESS_REJECT; + DESTROY_IF(out); + out = eap_payload_create_code(EAP_FAILURE, + in->get_identifier(in)); + } + charon->bus->set_sa(charon->bus, NULL); + } + + send_response(this, request, code, out, group, msk, source); + out->destroy(out); + + if (code == RMC_ACCESS_ACCEPT || code == RMC_ACCESS_REJECT) + { + this->connections->remove(this->connections, nas_id, user_name); + } + +end: + free(message.ptr); + in->destroy(in); + } +} + +/** + * Process packets received on the RADIUS socket + */ +static job_requeue_t receive(private_tnc_pdp_t *this) +{ + while (TRUE) + { + radius_message_t *request; + char buffer[MAX_PACKET]; + int max_fd = 0, selected = 0, bytes_read = 0; + fd_set rfds; + bool oldstate; + host_t *source; + struct msghdr msg; + struct iovec iov; + union { + struct sockaddr_in in4; + struct sockaddr_in6 in6; + } src; + + FD_ZERO(&rfds); + + if (this->ipv4) + { + FD_SET(this->ipv4, &rfds); + } + if (this->ipv6) + { + FD_SET(this->ipv6, &rfds); + } + max_fd = max(this->ipv4, this->ipv6); + + DBG2(DBG_CFG, "waiting for data on RADIUS sockets"); + oldstate = thread_cancelability(TRUE); + if (select(max_fd + 1, &rfds, NULL, NULL, NULL) <= 0) + { + thread_cancelability(oldstate); + continue; + } + thread_cancelability(oldstate); + + if (FD_ISSET(this->ipv4, &rfds)) + { + selected = this->ipv4; + } + else if (FD_ISSET(this->ipv6, &rfds)) + { + selected = this->ipv6; + } + else + { + /* oops, shouldn't happen */ + continue; + } + + /* read received packet */ + msg.msg_name = &src; + msg.msg_namelen = sizeof(src); + iov.iov_base = buffer; + iov.iov_len = MAX_PACKET; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + + bytes_read = recvmsg(selected, &msg, 0); + if (bytes_read < 0) + { + DBG1(DBG_CFG, "error reading RADIUS socket: %s", strerror(errno)); + continue; + } + if (msg.msg_flags & MSG_TRUNC) + { + DBG1(DBG_CFG, "receive buffer too small, RADIUS packet discarded"); + continue; + } + source = host_create_from_sockaddr((sockaddr_t*)&src); + DBG2(DBG_CFG, "received RADIUS packet from %#H", source); + DBG3(DBG_CFG, "%b", buffer, bytes_read); + request = radius_message_parse(chunk_create(buffer, bytes_read)); + if (request) + { + DBG1(DBG_CFG, "received RADIUS %N from client '%H'", + radius_message_code_names, request->get_code(request), source); + + if (request->verify(request, NULL, this->secret, this->hasher, + this->signer)) + { + process_eap(this, request, source); + } + request->destroy(request); + + } + else + { + DBG1(DBG_CFG, "received invalid RADIUS message, ignored"); + } + source->destroy(source); + } + return JOB_REQUEUE_FAIR; +} + +METHOD(tnc_pdp_t, destroy, void, + private_tnc_pdp_t *this) +{ + if (this->job) + { + this->job->cancel(this->job); + } + if (this->ipv4) + { + close(this->ipv4); + } + if (this->ipv6) + { + close(this->ipv6); + } + DESTROY_IF(this->server); + DESTROY_IF(this->signer); + DESTROY_IF(this->hasher); + DESTROY_IF(this->rng); + DESTROY_IF(this->connections); + free(this); +} + +/* + * see header file + */ +tnc_pdp_t *tnc_pdp_create(u_int16_t port) +{ + private_tnc_pdp_t *this; + char *secret, *server, *eap_type_str; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .ipv4 = open_socket(AF_INET, port), + .ipv6 = open_socket(AF_INET6, port), + .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5), + .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128), + .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), + .connections = tnc_pdp_connections_create(), + ); + + if (!this->hasher || !this->signer || !this->rng) + { + DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required"); + destroy(this); + return NULL; + } + if (!this->ipv4 && !this->ipv6) + { + DBG1(DBG_NET, "could not create any RADIUS sockets"); + destroy(this); + return NULL; + } + if (!this->ipv4) + { + DBG1(DBG_NET, "could not open IPv4 RADIUS socket, IPv4 disabled"); + } + if (!this->ipv6) + { + DBG1(DBG_NET, "could not open IPv6 RADIUS socket, IPv6 disabled"); + } + + server = lib->settings->get_str(lib->settings, + "charon.plugins.tnc-pdp.server", NULL); + if (!server) + { + DBG1(DBG_CFG, "missing PDP server name, PDP disabled"); + destroy(this); + return NULL; + } + this->server = identification_create_from_string(server); + + secret = lib->settings->get_str(lib->settings, + "charon.plugins.tnc-pdp.secret", NULL); + if (!secret) + { + DBG1(DBG_CFG, "missing RADIUS secret, PDP disabled"); + destroy(this); + return NULL; + } + this->secret = chunk_create(secret, strlen(secret)); + this->signer->set_key(this->signer, this->secret); + + eap_type_str = lib->settings->get_str(lib->settings, + "charon.plugins.tnc-pdp.method", "ttls"); + this->type = eap_type_from_string(eap_type_str); + if (this->type == 0) + { + DBG1(DBG_CFG, "unrecognized eap method \"%s\"", eap_type_str); + destroy(this); + return NULL; + } + DBG1(DBG_IKE, "eap method %N selected", eap_type_names, this->type); + + this->job = callback_job_create_with_prio((callback_job_cb_t)receive, + this, NULL, NULL, JOB_PRIO_CRITICAL); + lib->processor->queue_job(lib->processor, (job_t*)this->job); + + return &this->public; +} + diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp.h new file mode 100644 index 000000000..e769353b7 --- /dev/null +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 tnc_pdp tnc_pdp + * @{ @ingroup tnc_pdp + */ + +#ifndef TNC_PDP_H_ +#define TNC_PDP_H_ + +typedef struct tnc_pdp_t tnc_pdp_t; + +#include <library.h> + +/** + * Public interface of a TNC Policy Decision Point object + */ +struct tnc_pdp_t { + + /** + * implements plugin interface + */ + void (*destroy)(tnc_pdp_t *this); +}; + +/** + * Create a TNC PDP instance + * + * @param port RADIUS port of TNC PDP + */ +tnc_pdp_t* tnc_pdp_create(u_int16_t port); + +#endif /** TNC_PDP_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c new file mode 100644 index 000000000..175a57aba --- /dev/null +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR 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 "tnc_pdp_connections.h" + +#include <utils/linked_list.h> +#include <debug.h> + +typedef struct private_tnc_pdp_connections_t private_tnc_pdp_connections_t; +typedef struct entry_t entry_t; + +/** + * Private data of tnc_pdp_connections_t + */ +struct private_tnc_pdp_connections_t { + + /** + * Implements tnc_pdp_connections_t interface + */ + tnc_pdp_connections_t public; + + /** + * List of TNC PEP RADIUS Connections + */ + linked_list_t *list; +}; + +/** + * Data entry for a TNC PEP RADIUS connection + */ +struct entry_t { + + /** + * NAS identifier of PEP + */ + chunk_t nas_id; + + /** + * User name of TNC Client + */ + chunk_t user_name; + + /** + * EAP method state + */ + eap_method_t *method; + + /** + * IKE SA used for bus communication + */ + ike_sa_t *ike_sa; +}; + +/** + * Free the memory allocated to a data entry + */ +static void free_entry(entry_t *this) +{ + this->method->destroy(this->method); + this->ike_sa->destroy(this->ike_sa); + free(this->nas_id.ptr); + free(this->user_name.ptr); + free(this); +} + +/** + * Find a matching data entry + */ +static bool equals_entry( entry_t *this, chunk_t nas_id, chunk_t user_name) +{ + bool no_nas_id = !this->nas_id.ptr && !nas_id.ptr; + + return (chunk_equals(this->nas_id, nas_id) || no_nas_id) && + chunk_equals(this->user_name, user_name); +} + +/** + * Find a matching data entry + */ +static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op) +{ + if (nas_id.len) + { + DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s' NAS '%.*s'", + not ? "could not find" : op, user_name.len, user_name.ptr, + nas_id.len, nas_id.ptr); + } + else + { + DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s'", + not ? "could not find" : op, user_name.len, user_name.ptr); + } +} + +METHOD(tnc_pdp_connections_t, add, void, + private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name, + identification_t *peer, eap_method_t *method) +{ + enumerator_t *enumerator; + entry_t *entry; + ike_sa_id_t *ike_sa_id; + ike_sa_t *ike_sa; + bool found = FALSE; + + ike_sa_id = ike_sa_id_create(0, 0, FALSE); + ike_sa = ike_sa_create(ike_sa_id); + ike_sa_id->destroy(ike_sa_id); + ike_sa->set_other_id(ike_sa, peer); + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (equals_entry(entry, nas_id, user_name)) + { + found = TRUE; + entry->method->destroy(entry->method); + entry->ike_sa->destroy(entry->ike_sa); + DBG1(DBG_CFG, "removed stale RADIUS connection"); + entry->method = method; + entry->ike_sa = ike_sa; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + entry = malloc_thing(entry_t); + entry->nas_id = chunk_clone(nas_id); + entry->user_name = chunk_clone(user_name); + entry->method = method; + entry->ike_sa = ike_sa; + this->list->insert_last(this->list, entry); + } + dbg_nas_user(nas_id, user_name, FALSE, "created"); +} + +METHOD(tnc_pdp_connections_t, remove_, void, + private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name) +{ + enumerator_t *enumerator; + entry_t *entry; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (equals_entry(entry, nas_id, user_name)) + { + free_entry(entry); + this->list->remove_at(this->list, enumerator); + dbg_nas_user(nas_id, user_name, FALSE, "removed"); + break; + } + } + enumerator->destroy(enumerator); +} + +METHOD(tnc_pdp_connections_t, get_state, eap_method_t*, + private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name, + ike_sa_t **ike_sa) +{ + enumerator_t *enumerator; + entry_t *entry; + eap_method_t *found = NULL; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (equals_entry(entry, nas_id, user_name)) + { + found = entry->method; + *ike_sa = entry->ike_sa; + break; + } + } + enumerator->destroy(enumerator); + + dbg_nas_user(nas_id, user_name, !found, "found"); + return found; +} + +METHOD(tnc_pdp_connections_t, destroy, void, + private_tnc_pdp_connections_t *this) +{ + this->list->destroy_function(this->list, (void*)free_entry); + free(this); +} + +/* + * see header file + */ +tnc_pdp_connections_t *tnc_pdp_connections_create(void) +{ + private_tnc_pdp_connections_t *this; + + INIT(this, + .public = { + .add = _add, + .remove = _remove_, + .get_state = _get_state, + .destroy = _destroy, + }, + .list = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h new file mode 100644 index 000000000..b9f5d097b --- /dev/null +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR 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 tnc_pdp_connections tnc_pdp_connections + * @{ @ingroup tnc_pdp + */ + +#ifndef TNC_PDP_CONNECTIONS_H_ +#define TNC_PDP_CONNECTIONS_H_ + +typedef struct tnc_pdp_connections_t tnc_pdp_connections_t; + +#include <library.h> +#include <sa/ike_sa.h> +#include <sa/authenticators/eap/eap_method.h> + +/** + * Public interface of a tnc_pdp_connections object + */ +struct tnc_pdp_connections_t { + + /** + * Register a new TNC PEP RADIUS Connection + * + * @param nas_id NAS identifier of Policy Enforcement Point + * @param user_name User name of TNC Client + * @param peer Peer identity + * @param method EAP method state for this TNC PEP Connection + */ + void (*add)(tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name, + identification_t *peer, eap_method_t *method); + + /** + * Remove a TNC PEP RADIUS Connection + * + * @param nas_id NAS identifier of Policy Enforcement Point + * @param user_name User name of TNC Client + */ + void (*remove)(tnc_pdp_connections_t *this, chunk_t nas_id, + chunk_t user_name); + + /** + * Get the EAP method and IKE_SA of a registered TNC PEP RADIUS Connection + * + * @param nas_id NAS identifier of Policy Enforcement Point + * @param user_name User name of TNC Client + * @param ike_sa IKE_SA used for bus communication only + * @return EAP method for this connection or NULL if not found + */ + eap_method_t* (*get_state)(tnc_pdp_connections_t *this, chunk_t nas_id, + chunk_t user_name, ike_sa_t **ike_sa); + + /** + * Destroys a tnc_pdp_connections_t object. + */ + void (*destroy)(tnc_pdp_connections_t *this); +}; + +/** + * Create a tnc_pdp_connections_t instance + */ +tnc_pdp_connections_t* tnc_pdp_connections_create(void); + +#endif /** TNC_PDP_CONNECTIONS_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c new file mode 100644 index 000000000..9abe02aec --- /dev/null +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 Andreas Steffen + * HSR 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 "tnc_pdp_plugin.h" +#include "tnc_pdp.h" + +typedef struct private_tnc_pdp_plugin_t private_tnc_pdp_plugin_t; + +/** + * Default RADIUS port, when not configured + */ +#define RADIUS_PORT 1812 + +/** + * private data of tnc_pdp plugin + */ +struct private_tnc_pdp_plugin_t { + + /** + * implements plugin interface + */ + tnc_pdp_plugin_t public; + + /** + * Policy Decision Point object + */ + tnc_pdp_t *pdp; + +}; + +METHOD(plugin_t, get_name, char*, + private_tnc_pdp_plugin_t *this) +{ + return "tnc-pdp"; +} + +METHOD(plugin_t, get_features, int, + private_tnc_pdp_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_PROVIDE(CUSTOM, "tnc-pdp"), + PLUGIN_DEPENDS(CUSTOM, "imv-manager"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_tnc_pdp_plugin_t *this) +{ + DESTROY_IF(this->pdp); + free(this); +} + +/* + * see header file + */ +plugin_t *tnc_pdp_plugin_create() +{ + private_tnc_pdp_plugin_t *this; + int port; + + port = lib->settings->get_int(lib->settings, + "charon.plugins.tnc_pdp.port", RADIUS_PORT); + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + .pdp = tnc_pdp_create(port), + ); + + return &this->public.plugin; +} + diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h new file mode 100644 index 000000000..9b8b9ff0e --- /dev/null +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 tnc_pdp tnc_pdp + * @ingroup cplugins + * + * @defgroup tnc_pdp_plugin tnc_pdp_plugin + * @{ @ingroup tnc_pdp + */ + +#ifndef TNC_PDP_PLUGIN_H_ +#define TNC_PDP_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct tnc_pdp_plugin_t tnc_pdp_plugin_t; + +/** + * TNC-PDP plugin + */ +struct tnc_pdp_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** TNC_PDP_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c index f007ce19f..64ed160d9 100644 --- a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c +++ b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c @@ -55,6 +55,11 @@ struct tnccs_connection_entry_t { TNC_ConnectionID id; /** + * TNCCS protocol type + */ + tnccs_type_t type; + + /** * TNCCS instance */ tnccs_t *tnccs; @@ -174,13 +179,14 @@ METHOD(tnccs_manager_t, create_instance, tnccs_t*, } METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID, - private_tnc_tnccs_manager_t *this, tnccs_t *tnccs, + private_tnc_tnccs_manager_t *this, tnccs_type_t type, tnccs_t *tnccs, tnccs_send_message_t send_message, bool* request_handshake_retry, recommendations_t **recs) { tnccs_connection_entry_t *entry; entry = malloc_thing(tnccs_connection_entry_t); + entry->type = type; entry->tnccs = tnccs; entry->send_message = send_message; entry->request_handshake_retry = request_handshake_retry; @@ -295,24 +301,22 @@ METHOD(tnccs_manager_t, request_handshake_retry, TNC_Result, METHOD(tnccs_manager_t, send_message, TNC_Result, private_tnc_tnccs_manager_t *this, TNC_IMCID imc_id, TNC_IMVID imv_id, TNC_ConnectionID id, + TNC_UInt32 msg_flags, TNC_BufferReference msg, TNC_UInt32 msg_len, - TNC_MessageType msg_type) + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype) { enumerator_t *enumerator; tnccs_connection_entry_t *entry; tnccs_send_message_t send_message = NULL; tnccs_t *tnccs = NULL; - TNC_VendorID msg_vid; - TNC_MessageSubtype msg_subtype; - - msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY; - msg_subtype = msg_type & TNC_SUBTYPE_ANY; if (msg_vid == TNC_VENDORID_ANY || msg_subtype == TNC_SUBTYPE_ANY) { - DBG1(DBG_TNC, "not sending message of invalid type 0x%08x", msg_type); + DBG1(DBG_TNC, "not sending message of invalid type 0x%02x/0x%08x", + msg_vid, msg_subtype); return TNC_RESULT_INVALID_PARAMETER; } @@ -332,7 +336,8 @@ METHOD(tnccs_manager_t, send_message, TNC_Result, if (tnccs && send_message) { - return send_message(tnccs, imc_id, imv_id, msg, msg_len, msg_type); + return send_message(tnccs, imc_id, imv_id, msg_flags, msg, msg_len, + msg_vid, msg_subtype); } return TNC_RESULT_FATAL; } @@ -368,20 +373,150 @@ METHOD(tnccs_manager_t, provide_recommendation, TNC_Result, return TNC_RESULT_FATAL; } +/** + * Write the value of a boolean attribute into the buffer + */ +static TNC_Result bool_attribute(TNC_UInt32 buffer_len, + TNC_BufferReference buffer, + TNC_UInt32 *value_len, + bool value) +{ + *value_len = 1; + + if (buffer && buffer_len > 0) + { + *buffer = value ? 0x01 : 0x00; + return TNC_RESULT_SUCCESS; + } + else + { + return TNC_RESULT_INVALID_PARAMETER; + } +} + +/** + * Write the value of an u_int32_t attribute into the buffer + */ +static TNC_Result uint_attribute(TNC_UInt32 buffer_len, + TNC_BufferReference buffer, + TNC_UInt32 *value_len, + u_int32_t value) +{ + *value_len = sizeof(u_int32_t); + + if (buffer && buffer_len >= *value_len) + { + htoun32(buffer, value); + return TNC_RESULT_SUCCESS; + } + else + { + return TNC_RESULT_INVALID_PARAMETER; + } +} + +/** + * Write the value of string attribute into the buffer + */ +static TNC_Result str_attribute(TNC_UInt32 buffer_len, + TNC_BufferReference buffer, + TNC_UInt32 *value_len, + char *value) +{ + *value_len = 1 + strlen(value); + + if (buffer && buffer_len >= *value_len) + { + snprintf(buffer, buffer_len, "%s", value); + return TNC_RESULT_SUCCESS; + } + else + { + return TNC_RESULT_INVALID_PARAMETER; + } +} + METHOD(tnccs_manager_t, get_attribute, TNC_Result, - private_tnc_tnccs_manager_t *this, TNC_IMVID imv_id, + private_tnc_tnccs_manager_t *this, bool is_imc, + TNC_UInt32 imcv_id, TNC_ConnectionID id, TNC_AttributeID attribute_id, TNC_UInt32 buffer_len, TNC_BufferReference buffer, - TNC_UInt32 *out_value_len) + TNC_UInt32 *value_len) { enumerator_t *enumerator; tnccs_connection_entry_t *entry; - recommendations_t *recs = NULL; + bool attribute_match = FALSE, entry_found = FALSE; + + if (is_imc) + { + switch (attribute_id) + { + /* these attributes are unsupported */ + case TNC_ATTRIBUTEID_SOHR: + case TNC_ATTRIBUTEID_SSOHR: + return TNC_RESULT_INVALID_PARAMETER; + + /* these attributes are supported */ + case TNC_ATTRIBUTEID_PRIMARY_IMC_ID: + attribute_match = TRUE; + break; + + /* these attributes are yet to be matched */ + default: + break; + } + } + else + { + switch (attribute_id) + { + /* these attributes are unsupported or invalid */ + case TNC_ATTRIBUTEID_REASON_STRING: + case TNC_ATTRIBUTEID_REASON_LANGUAGE: + case TNC_ATTRIBUTEID_SOH: + case TNC_ATTRIBUTEID_SSOH: + return TNC_RESULT_INVALID_PARAMETER; + + /* these attributes are supported */ + case TNC_ATTRIBUTEID_PRIMARY_IMV_ID: + attribute_match = TRUE; + break; + + /* these attributes are yet to be matched */ + default: + break; + } + } + + if (!attribute_match) + { + switch (attribute_id) + { + /* these attributes are supported */ + case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE: + case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS: + case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE: + case TNC_ATTRIBUTEID_HAS_LONG_TYPES: + case TNC_ATTRIBUTEID_HAS_EXCLUSIVE: + case TNC_ATTRIBUTEID_HAS_SOH: + case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL: + case TNC_ATTRIBUTEID_IFTNCCS_VERSION: + case TNC_ATTRIBUTEID_IFT_PROTOCOL: + case TNC_ATTRIBUTEID_IFT_VERSION: + break; - if (id == TNC_CONNECTIONID_ANY || - attribute_id != TNC_ATTRIBUTEID_PREFERRED_LANGUAGE) + /* these attributes are unsupported or unknown */ + case TNC_ATTRIBUTEID_DHPN: + case TNC_ATTRIBUTEID_TLS_UNIQUE: + default: + return TNC_RESULT_INVALID_PARAMETER; + } + } + + /* attributes specific to the TNCC or TNCS are unsupported */ + if (id == TNC_CONNECTIONID_ANY) { return TNC_RESULT_INVALID_PARAMETER; } @@ -392,34 +527,104 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, { if (id == entry->id) { - recs = entry->recs; + entry_found = TRUE; break; } } enumerator->destroy(enumerator); this->connection_lock->unlock(this->connection_lock); - if (recs) + if (!entry_found) { - chunk_t pref_lang; + return TNC_RESULT_INVALID_PARAMETER; + } - pref_lang = recs->get_preferred_language(recs); - if (pref_lang.len == 0) + switch (attribute_id) + { + case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE: { - return TNC_RESULT_INVALID_PARAMETER; + recommendations_t *recs; + chunk_t pref_lang; + + recs = entry->recs; + if (!recs) + { + return TNC_RESULT_INVALID_PARAMETER; + } + pref_lang = recs->get_preferred_language(recs); + if (pref_lang.len == 0) + { + return TNC_RESULT_INVALID_PARAMETER; + } + *value_len = pref_lang.len; + if (buffer && buffer_len >= pref_lang.len) + { + memcpy(buffer, pref_lang.ptr, pref_lang.len); + } + return TNC_RESULT_SUCCESS; } - *out_value_len = pref_lang.len; - if (buffer && buffer_len >= pref_lang.len) + case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS: + return uint_attribute(buffer_len, buffer, value_len, 0xffffffff); + case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE: + return uint_attribute(buffer_len, buffer, value_len, 0x00000000); + case TNC_ATTRIBUTEID_HAS_LONG_TYPES: + case TNC_ATTRIBUTEID_HAS_EXCLUSIVE: + return bool_attribute(buffer_len, buffer, value_len, + entry->type == TNCCS_2_0); + case TNC_ATTRIBUTEID_HAS_SOH: + return bool_attribute(buffer_len, buffer, value_len, + entry->type == TNCCS_SOH); + case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL: { - memcpy(buffer, pref_lang.ptr, pref_lang.len); + char *protocol; + + switch (entry->type) + { + case TNCCS_1_1: + case TNCCS_2_0: + protocol = "IF-TNCCS"; + break; + case TNCCS_SOH: + protocol = "IF-TNCCS-SOH"; + break; + default: + return TNC_RESULT_INVALID_PARAMETER; + } + return str_attribute(buffer_len, buffer, value_len, protocol); } - return TNC_RESULT_SUCCESS; + case TNC_ATTRIBUTEID_IFTNCCS_VERSION: + { + char *version; + + switch (entry->type) + { + case TNCCS_1_1: + version = "1.1"; + break; + case TNCCS_2_0: + version = "2.0"; + break; + case TNCCS_SOH: + version = "1.0"; + break; + default: + return TNC_RESULT_INVALID_PARAMETER; + } + return str_attribute(buffer_len, buffer, value_len, version); + } + case TNC_ATTRIBUTEID_IFT_PROTOCOL: + return str_attribute(buffer_len, buffer, value_len, + "IF-T for Tunneled EAP"); + case TNC_ATTRIBUTEID_IFT_VERSION: + return str_attribute(buffer_len, buffer, value_len, "1.1"); + default: + return TNC_RESULT_INVALID_PARAMETER; } - return TNC_RESULT_INVALID_PARAMETER; } METHOD(tnccs_manager_t, set_attribute, TNC_Result, - private_tnc_tnccs_manager_t *this, TNC_IMVID imv_id, + private_tnc_tnccs_manager_t *this, bool is_imc, + TNC_UInt32 imcv_id, TNC_ConnectionID id, TNC_AttributeID attribute_id, TNC_UInt32 buffer_len, @@ -429,7 +634,7 @@ METHOD(tnccs_manager_t, set_attribute, TNC_Result, tnccs_connection_entry_t *entry; recommendations_t *recs = NULL; - if (id == TNC_CONNECTIONID_ANY || + if (is_imc || id == TNC_CONNECTIONID_ANY || (attribute_id != TNC_ATTRIBUTEID_REASON_STRING && attribute_id != TNC_ATTRIBUTEID_REASON_LANGUAGE)) { @@ -455,11 +660,11 @@ METHOD(tnccs_manager_t, set_attribute, TNC_Result, if (attribute_id == TNC_ATTRIBUTEID_REASON_STRING) { - return recs->set_reason_string(recs, imv_id, attribute); + return recs->set_reason_string(recs, imcv_id, attribute); } else { - return recs->set_reason_language(recs, imv_id, attribute); + return recs->set_reason_language(recs, imcv_id, attribute); } } return TNC_RESULT_INVALID_PARAMETER; diff --git a/src/libcharon/plugins/tnccs_11/tnccs_11.c b/src/libcharon/plugins/tnccs_11/tnccs_11.c index 88a2c8474..3673221e5 100644 --- a/src/libcharon/plugins/tnccs_11/tnccs_11.c +++ b/src/libcharon/plugins/tnccs_11/tnccs_11.c @@ -100,12 +100,14 @@ struct private_tnccs_11_t { METHOD(tnccs_t, send_msg, TNC_Result, private_tnccs_11_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id, + TNC_UInt32 msg_flags, TNC_BufferReference msg, TNC_UInt32 msg_len, - TNC_MessageType msg_type) + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype) { tnccs_msg_t *tnccs_msg; - u_int32_t vendor_id, subtype; + TNC_MessageType msg_type; enum_name_t *pa_subtype_names; if (!this->send_msg) @@ -115,18 +117,23 @@ METHOD(tnccs_t, send_msg, TNC_Result, this->is_server ? imv_id : imc_id); return TNC_RESULT_ILLEGAL_OPERATION; } - vendor_id = msg_type >> 8; - subtype = msg_type & 0xff; - pa_subtype_names = get_pa_subtype_names(vendor_id); + if (msg_vid > TNC_VENDORID_ANY || msg_subtype > TNC_SUBTYPE_ANY) + { + return TNC_RESULT_NO_LONG_MESSAGE_TYPES; + } + msg_type = (msg_vid << 8) | msg_subtype; + + pa_subtype_names = get_pa_subtype_names(msg_vid); if (pa_subtype_names) { DBG2(DBG_TNC, "creating IMC-IMV message type '%N/%N' 0x%06x/0x%02x", - pen_names, vendor_id, pa_subtype_names, subtype, vendor_id, subtype); + pen_names, msg_vid, pa_subtype_names, msg_subtype, + msg_vid, msg_subtype); } else { DBG2(DBG_TNC, "creating IMC-IMV message type '%N' 0x%06x/0x%02x", - pen_names, vendor_id, vendor_id, subtype); + pen_names, msg_vid, msg_vid, msg_subtype); } tnccs_msg = imc_imv_msg_create(msg_type, chunk_create(msg, msg_len)); @@ -153,38 +160,40 @@ static void handle_message(private_tnccs_11_t *this, tnccs_msg_t *msg) imc_imv_msg_t *imc_imv_msg; TNC_MessageType msg_type; chunk_t msg_body; - u_int32_t vendor_id, subtype; + u_int32_t msg_vid, msg_subtype; enum_name_t *pa_subtype_names; imc_imv_msg = (imc_imv_msg_t*)msg; msg_type = imc_imv_msg->get_msg_type(imc_imv_msg); msg_body = imc_imv_msg->get_msg_body(imc_imv_msg); - vendor_id = msg_type >> 8; - subtype = msg_type & 0xff; + msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; - pa_subtype_names = get_pa_subtype_names(vendor_id); + pa_subtype_names = get_pa_subtype_names(msg_vid); if (pa_subtype_names) { DBG2(DBG_TNC, "handling IMC-IMV message type '%N/%N' 0x%06x/0x%02x", - pen_names, vendor_id, pa_subtype_names, subtype, - vendor_id, subtype); + pen_names, msg_vid, pa_subtype_names, msg_subtype, + msg_vid, msg_subtype); } else { DBG2(DBG_TNC, "handling IMC-IMV message type '%N' 0x%06x/0x%02x", - pen_names, vendor_id, vendor_id, subtype); + pen_names, msg_vid, msg_vid, msg_subtype); } this->send_msg = TRUE; if (this->is_server) { - tnc->imvs->receive_message(tnc->imvs, - this->connection_id, msg_body.ptr, msg_body.len, msg_type); + tnc->imvs->receive_message(tnc->imvs, this->connection_id, + FALSE, msg_body.ptr, msg_body.len, + msg_vid, msg_subtype, 0, TNC_IMVID_ANY); } else { - tnc->imcs->receive_message(tnc->imcs, - this->connection_id, msg_body.ptr, msg_body.len,msg_type); + tnc->imcs->receive_message(tnc->imcs, this->connection_id, + FALSE, msg_body.ptr, msg_body.len, + msg_vid, msg_subtype, 0, TNC_IMCID_ANY); } this->send_msg = FALSE; break; @@ -280,7 +289,7 @@ METHOD(tls_t, process, status_t, if (this->is_server && !this->connection_id) { this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - (tnccs_t*)this, _send_msg, + TNCCS_1_1, (tnccs_t*)this, _send_msg, &this->request_handshake_retry, &this->recs); if (!this->connection_id) { @@ -406,7 +415,7 @@ METHOD(tls_t, build, status_t, char *pref_lang; this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - (tnccs_t*)this, _send_msg, + TNCCS_1_1, (tnccs_t*)this, _send_msg, &this->request_handshake_retry, NULL); if (!this->connection_id) { diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c index b9bbf6bd1..1c4913e5e 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c @@ -211,12 +211,6 @@ METHOD(pb_pa_msg_t, get_exclusive_flag, bool, return this->excl; } -METHOD(pb_pa_msg_t, set_exclusive_flag, void, - private_pb_pa_msg_t *this, bool excl) -{ - this->excl = excl; -} - /** * See header */ @@ -237,7 +231,6 @@ pb_tnc_msg_t *pb_pa_msg_create_from_data(chunk_t data) .get_validator_id = _get_validator_id, .get_body = _get_body, .get_exclusive_flag = _get_exclusive_flag, - .set_exclusive_flag = _set_exclusive_flag, }, .type = PB_MSG_PA, .encoding = chunk_clone(data), @@ -251,7 +244,7 @@ pb_tnc_msg_t *pb_pa_msg_create_from_data(chunk_t data) */ pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype, u_int16_t collector_id, u_int16_t validator_id, - chunk_t msg_body) + bool excl, chunk_t msg_body) { private_pb_pa_msg_t *this; @@ -269,13 +262,13 @@ pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype, .get_validator_id = _get_validator_id, .get_body = _get_body, .get_exclusive_flag = _get_exclusive_flag, - .set_exclusive_flag = _set_exclusive_flag, }, .type = PB_MSG_PA, .vendor_id = vendor_id, .subtype = subtype, .collector_id = collector_id, .validator_id = validator_id, + .excl = excl, .msg_body = chunk_clone(msg_body), ); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h index eb087e9e7..d9db9a1ce 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h +++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h @@ -71,12 +71,6 @@ struct pb_pa_msg_t { */ bool (*get_exclusive_flag)(pb_pa_msg_t *this); - /** - * Set the exclusive flag - * - * @param excl vexclusive flag - */ - void (*set_exclusive_flag)(pb_pa_msg_t *this, bool excl); }; /** @@ -86,11 +80,12 @@ struct pb_pa_msg_t { * @param subtype PA Subtype * @param collector_id Posture Collector ID * @param validator_id Posture Validator ID + * @param excl Exclusive Flag * @param msg_body PA Message Body */ pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype, u_int16_t collector_id, u_int16_t validator_id, - chunk_t msg_body); + bool excl, chunk_t msg_body); /** * Create an unprocessed PB-PA message from raw data diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20.c b/src/libcharon/plugins/tnccs_20/tnccs_20.c index d37510880..606fc529b 100644 --- a/src/libcharon/plugins/tnccs_20/tnccs_20.c +++ b/src/libcharon/plugins/tnccs_20/tnccs_20.c @@ -99,15 +99,16 @@ struct private_tnccs_20_t { METHOD(tnccs_t, send_msg, TNC_Result, private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id, + TNC_UInt32 msg_flags, TNC_BufferReference msg, TNC_UInt32 msg_len, - TNC_MessageType msg_type) + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype) { - TNC_MessageSubtype msg_sub_type; - TNC_VendorID msg_vendor_id; pb_tnc_msg_t *pb_tnc_msg; pb_tnc_batch_type_t batch_type; enum_name_t *pa_subtype_names; + bool excl; if (!this->send_msg) { @@ -116,24 +117,22 @@ METHOD(tnccs_t, send_msg, TNC_Result, this->is_server ? imv_id : imc_id); return TNC_RESULT_ILLEGAL_OPERATION; } + excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0; - msg_sub_type = msg_type & TNC_SUBTYPE_ANY; - msg_vendor_id = (msg_type >> 8) & TNC_VENDORID_ANY; + pb_tnc_msg = pb_pa_msg_create(msg_vid, msg_subtype, imc_id, imv_id, + excl, chunk_create(msg, msg_len)); - pb_tnc_msg = pb_pa_msg_create(msg_vendor_id, msg_sub_type, imc_id, imv_id, - chunk_create(msg, msg_len)); - - pa_subtype_names = get_pa_subtype_names(msg_vendor_id); + pa_subtype_names = get_pa_subtype_names(msg_vid); if (pa_subtype_names) { - DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%02x", - pen_names, msg_vendor_id, pa_subtype_names, msg_sub_type, - msg_vendor_id, msg_sub_type); + DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x", + pen_names, msg_vid, pa_subtype_names, msg_subtype, + msg_vid, msg_subtype); } else { - DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%02x", - pen_names, msg_vendor_id, msg_vendor_id, msg_sub_type); + DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x", + pen_names, msg_vid, msg_vid, msg_subtype); } /* adding PA message to SDATA or CDATA batch only */ @@ -168,39 +167,44 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) case PB_MSG_PA: { pb_pa_msg_t *pa_msg; - TNC_MessageType msg_type; - u_int32_t vendor_id, subtype; + u_int32_t msg_vid, msg_subtype; + u_int16_t imc_id, imv_id; chunk_t msg_body; + bool excl; enum_name_t *pa_subtype_names; pa_msg = (pb_pa_msg_t*)msg; - vendor_id = pa_msg->get_vendor_id(pa_msg, &subtype); - msg_type = (vendor_id << 8) | (subtype & 0xff); + msg_vid = pa_msg->get_vendor_id(pa_msg, &msg_subtype); msg_body = pa_msg->get_body(pa_msg); + imc_id = pa_msg->get_collector_id(pa_msg); + imv_id = pa_msg->get_validator_id(pa_msg); + excl = pa_msg->get_exclusive_flag(pa_msg); - pa_subtype_names = get_pa_subtype_names(vendor_id); + pa_subtype_names = get_pa_subtype_names(msg_vid); if (pa_subtype_names) { - DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%02x", - pen_names, vendor_id, pa_subtype_names, subtype, - vendor_id, subtype); + DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x", + pen_names, msg_vid, pa_subtype_names, msg_subtype, + msg_vid, msg_subtype); } else { - DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%02x", - pen_names, vendor_id, vendor_id, subtype); + DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x", + pen_names, msg_vid, msg_vid, msg_subtype); } this->send_msg = TRUE; if (this->is_server) { - tnc->imvs->receive_message(tnc->imvs, - this->connection_id, msg_body.ptr, msg_body.len, msg_type); + tnc->imvs->receive_message(tnc->imvs, this->connection_id, + excl, msg_body.ptr, msg_body.len, + msg_vid, msg_subtype, imc_id, imv_id); } else { - tnc->imcs->receive_message(tnc->imcs, - this->connection_id, msg_body.ptr, msg_body.len,msg_type); + tnc->imcs->receive_message(tnc->imcs, this->connection_id, + excl, msg_body.ptr, msg_body.len, + msg_vid, msg_subtype, imv_id, imc_id); } this->send_msg = FALSE; break; @@ -371,7 +375,7 @@ METHOD(tls_t, process, status_t, if (this->is_server && !this->connection_id) { this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - (tnccs_t*)this, _send_msg, + TNCCS_2_0, (tnccs_t*)this, _send_msg, &this->request_handshake_retry, &this->recs); if (!this->connection_id) { @@ -552,7 +556,7 @@ METHOD(tls_t, build, status_t, char *pref_lang; this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - (tnccs_t*)this, _send_msg, + TNCCS_2_0, (tnccs_t*)this, _send_msg, &this->request_handshake_retry, NULL); if (!this->connection_id) { diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index bcc98709c..5d0a5aea8 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -33,6 +33,7 @@ #include <processing/jobs/send_dpd_job.h> #include <processing/jobs/send_keepalive_job.h> #include <processing/jobs/rekey_ike_sa_job.h> +#include <sa/ikev2/tasks/ike_auth_lifetime.h> #ifdef ME #include <sa/ikev2/tasks/ike_me.h> @@ -195,9 +196,9 @@ struct private_ike_sa_t { linked_list_t *attributes; /** - * list of peers additional addresses, transmitted via MOBIKE + * list of peer's addresses, additional ones transmitted via MOBIKE */ - linked_list_t *additional_addresses; + linked_list_t *peer_addresses; /** * previously value of received DESTINATION_IP hash @@ -668,7 +669,6 @@ METHOD(ike_sa_t, set_state, void, lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); } - trigger_dpd = this->peer_cfg->get_dpd(this->peer_cfg); } break; @@ -770,28 +770,28 @@ METHOD(ike_sa_t, get_virtual_ip, host_t*, } } -METHOD(ike_sa_t, add_additional_address, void, +METHOD(ike_sa_t, add_peer_address, void, private_ike_sa_t *this, host_t *host) { - this->additional_addresses->insert_last(this->additional_addresses, host); + this->peer_addresses->insert_last(this->peer_addresses, host); } -METHOD(ike_sa_t, create_additional_address_enumerator, enumerator_t*, +METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*, private_ike_sa_t *this) { - return this->additional_addresses->create_enumerator( - this->additional_addresses); + return this->peer_addresses->create_enumerator(this->peer_addresses); } -METHOD(ike_sa_t, remove_additional_addresses, void, +METHOD(ike_sa_t, clear_peer_addresses, void, private_ike_sa_t *this) { - enumerator_t *enumerator = create_additional_address_enumerator(this); + enumerator_t *enumerator = create_peer_address_enumerator(this); host_t *host; + while (enumerator->enumerate(enumerator, (void**)&host)) { - this->additional_addresses->remove_at(this->additional_addresses, - enumerator); + this->peer_addresses->remove_at(this->peer_addresses, + enumerator); host->destroy(host); } enumerator->destroy(enumerator); @@ -1386,17 +1386,25 @@ METHOD(ike_sa_t, reauth, status_t, #endif /* ME */ ) { - time_t now = time_monotonic(NULL); + time_t del, now; - DBG1(DBG_IKE, "IKE_SA will timeout in %V", - &now, &this->stats[STAT_DELETE]); + del = this->stats[STAT_DELETE]; + now = time_monotonic(NULL); + DBG1(DBG_IKE, "IKE_SA %s[%d] will timeout in %V", + get_name(this), this->unique_id, &now, &del); return FAILED; } else { - DBG1(DBG_IKE, "reauthenticating actively"); + DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d] actively", + get_name(this), this->unique_id); } } + else + { + DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d]", + get_name(this), this->unique_id); + } this->task_manager->queue_ike_reauth(this->task_manager); return this->task_manager->initiate(this->task_manager); } @@ -1558,6 +1566,7 @@ METHOD(ike_sa_t, retransmit, status_t, DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)", this->keyingtry + 1, tries); reset(this); + resolve_hosts(this); this->task_manager->queue_ike(this->task_manager); return this->task_manager->initiate(this->task_manager); } @@ -1579,35 +1588,67 @@ METHOD(ike_sa_t, retransmit, status_t, return SUCCESS; } -METHOD(ike_sa_t, set_auth_lifetime, void, +METHOD(ike_sa_t, set_auth_lifetime, status_t, private_ike_sa_t *this, u_int32_t lifetime) { - u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg); - u_int32_t reauth_time = time_monotonic(NULL) + lifetime - reduction; + u_int32_t diff, hard, soft, now; + ike_auth_lifetime_t *task; + bool send_update; + + diff = this->peer_cfg->get_over_time(this->peer_cfg); + now = time_monotonic(NULL); + hard = now + lifetime; + soft = hard - diff; - if (lifetime < reduction) + /* check if we have to send an AUTH_LIFETIME to enforce the new lifetime. + * We send the notify in IKE_AUTH if not yet ESTABLISHED. */ + send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 && + !has_condition(this, COND_ORIGINAL_INITIATOR) && + (this->other_virtual_ip != NULL || + has_condition(this, COND_EAP_AUTHENTICATED)); + + if (lifetime < diff) { - DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", - lifetime); - lib->processor->queue_job(lib->processor, + this->stats[STAT_REAUTH] = now; + + if (!send_update) + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, " + "starting reauthentication", lifetime); + lib->processor->queue_job(lib->processor, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE)); + } } else if (this->stats[STAT_REAUTH] == 0 || - this->stats[STAT_REAUTH] > reauth_time) + this->stats[STAT_REAUTH] > soft) { - this->stats[STAT_REAUTH] = reauth_time; - DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" - " in %ds", lifetime, lifetime - reduction); - lib->scheduler->schedule_job(lib->scheduler, + this->stats[STAT_REAUTH] = soft; + if (!send_update) + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling " + "reauthentication in %ds", lifetime, lifetime - diff); + lib->scheduler->schedule_job(lib->scheduler, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), - lifetime - reduction); + lifetime - diff); + } } else { DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, " "reauthentication already scheduled in %ds", lifetime, this->stats[STAT_REAUTH] - time_monotonic(NULL)); + send_update = FALSE; } + /* give at least some seconds to reauthenticate */ + this->stats[STAT_DELETE] = max(hard, now + 10); + + if (send_update) + { + task = ike_auth_lifetime_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, &task->task); + return this->task_manager->initiate(this->task_manager); + } + return SUCCESS; } /** @@ -1639,25 +1680,20 @@ static bool is_any_path_valid(private_ike_sa_t *this) bool valid = FALSE; enumerator_t *enumerator; host_t *src, *addr; + DBG1(DBG_IKE, "old path is not available anymore, try to find another"); - src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, - this->other_host, NULL); - if (!src) + enumerator = this->peer_addresses->create_enumerator(this->peer_addresses); + while (enumerator->enumerate(enumerator, &addr)) { - enumerator = this->additional_addresses->create_enumerator( - this->additional_addresses); - while (enumerator->enumerate(enumerator, &addr)) + DBG1(DBG_IKE, "looking for a route to %H ...", addr); + src = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, addr, NULL); + if (src) { - DBG1(DBG_IKE, "looking for a route to %H ...", addr); - src = hydra->kernel_interface->get_source_addr( - hydra->kernel_interface, addr, NULL); - if (src) - { - break; - } + break; } - enumerator->destroy(enumerator); } + enumerator->destroy(enumerator); if (src) { valid = TRUE; @@ -1900,8 +1936,8 @@ METHOD(ike_sa_t, destroy, void, } this->other_virtual_ip->destroy(this->other_virtual_ip); } - this->additional_addresses->destroy_offset(this->additional_addresses, - offsetof(host_t, destroy)); + this->peer_addresses->destroy_offset(this->peer_addresses, + offsetof(host_t, destroy)); #ifdef ME if (this->is_mediation_server) { @@ -1990,9 +2026,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .has_condition = _has_condition, .set_pending_updates = _set_pending_updates, .get_pending_updates = _get_pending_updates, - .create_additional_address_enumerator = _create_additional_address_enumerator, - .add_additional_address = _add_additional_address, - .remove_additional_addresses = _remove_additional_addresses, + .create_peer_address_enumerator = _create_peer_address_enumerator, + .add_peer_address = _add_peer_address, + .clear_peer_addresses = _clear_peer_addresses, .has_mapping_changed = _has_mapping_changed, .retransmit = _retransmit, .delete = _delete_, @@ -2051,7 +2087,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .my_auths = linked_list_create(), .other_auths = linked_list_create(), .unique_id = ++unique_id, - .additional_addresses = linked_list_create(), + .peer_addresses = linked_list_create(), .attributes = linked_list_create(), .keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL), diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 3fc0a7be2..0644bab78 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -508,19 +508,19 @@ struct ike_sa_t { * * @param host host to add to list */ - void (*add_additional_address)(ike_sa_t *this, host_t *host); + void (*add_peer_address)(ike_sa_t *this, host_t *host); /** - * Create an enumerator over all additional addresses of the peer. + * Create an enumerator over all known addresses of the peer. * * @return enumerator over addresses */ - enumerator_t* (*create_additional_address_enumerator)(ike_sa_t *this); + enumerator_t* (*create_peer_address_enumerator)(ike_sa_t *this); /** - * Remove all additional addresses of the peer. + * Remove all known addresses of the peer. */ - void (*remove_additional_addresses)(ike_sa_t *this); + void (*clear_peer_addresses)(ike_sa_t *this); /** * Check if mappings have changed on a NAT for our source address. @@ -905,11 +905,15 @@ struct ike_sa_t { status_t (*reestablish) (ike_sa_t *this); /** - * Set the lifetime limit received from a AUTH_LIFETIME notify. + * Set the lifetime limit received/to send in a AUTH_LIFETIME notify. + * + * If the IKE_SA is already ESTABLISHED, an INFORMATIONAL is sent with + * an AUTH_LIFETIME notify. The call never fails on unestablished SAs. * * @param lifetime lifetime in seconds + * @return DESTROY_ME to destroy the IKE_SA */ - void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); + status_t (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); /** * Set the virtual IP to use for this IKE_SA and its children. diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index d12f5c977..ba7fdd2da 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -162,15 +162,15 @@ struct private_task_manager_t { */ static void flush(private_task_manager_t *this) { - this->queued_tasks->destroy_offset(this->queued_tasks, - offsetof(task_t, destroy)); - this->queued_tasks = linked_list_create(); this->passive_tasks->destroy_offset(this->passive_tasks, offsetof(task_t, destroy)); this->passive_tasks = linked_list_create(); this->active_tasks->destroy_offset(this->active_tasks, offsetof(task_t, destroy)); this->active_tasks = linked_list_create(); + this->queued_tasks->destroy_offset(this->queued_tasks, + offsetof(task_t, destroy)); + this->queued_tasks = linked_list_create(); } /** @@ -369,6 +369,11 @@ METHOD(task_manager_t, initiate, status_t, exchange = INFORMATIONAL; break; } + if (activate_task(this, TASK_IKE_AUTH_LIFETIME)) + { + exchange = INFORMATIONAL; + break; + } #ifdef ME if (activate_task(this, TASK_IKE_ME)) { @@ -640,11 +645,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request) enumerator); } break; + case DESTROY_ME: case FAILED: default: - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - /* FALL */ - case DESTROY_ME: /* destroy IKE_SA, but SEND response first */ delete = TRUE; break; @@ -679,6 +682,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) this->responding.packet->clone(this->responding.packet)); if (delete) { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); return DESTROY_ME; } return SUCCESS; diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c index 0de2efd38..7583710bf 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c @@ -51,7 +51,7 @@ struct private_ike_cert_pre_t { bool do_http_lookup; /** - * wheter this is the final authentication round + * whether this is the final authentication round */ bool final; }; diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c index c533506bb..377714023 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010-2012 Tobias Brunner * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -134,13 +135,17 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) { if (first) { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */ - this->ike_sa->remove_additional_addresses(this->ike_sa); + this->ike_sa->clear_peer_addresses(this->ike_sa); first = FALSE; + /* add the peer's current address to the list */ + host = this->ike_sa->get_other_host(this->ike_sa); + this->ike_sa->add_peer_address(this->ike_sa, + host->clone(host)); } data = notify->get_notification_data(notify); host = host_create_from_chunk(family, data, 0); DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host); - this->ike_sa->add_additional_address(this->ike_sa, host); + this->ike_sa->add_peer_address(this->ike_sa, host); this->addresses_updated = TRUE; break; } @@ -151,7 +156,10 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) } case NO_ADDITIONAL_ADDRESSES: { - this->ike_sa->remove_additional_addresses(this->ike_sa); + this->ike_sa->clear_peer_addresses(this->ike_sa); + /* add the peer's current address to the list */ + host = this->ike_sa->get_other_host(this->ike_sa); + this->ike_sa->add_peer_address(this->ike_sa, host->clone(host)); this->addresses_updated = TRUE; break; } @@ -291,18 +299,7 @@ METHOD(ike_mobike_t, transmit, void, other_old = this->ike_sa->get_other_host(this->ike_sa); ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - me = hydra->kernel_interface->get_source_addr( - hydra->kernel_interface, other_old, NULL); - if (me) - { - apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg)); - DBG1(DBG_IKE, "checking original path %#H - %#H", me, other_old); - copy = packet->clone(packet); - copy->set_source(copy, me); - charon->sender->send(charon->sender, copy); - } - - enumerator = this->ike_sa->create_additional_address_enumerator(this->ike_sa); + enumerator = this->ike_sa->create_peer_address_enumerator(this->ike_sa); while (enumerator->enumerate(enumerator, (void**)&other)) { me = hydra->kernel_interface->get_source_addr( diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index d04d966ad..7ef0b9f5d 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -79,7 +79,9 @@ int keymat_get_keylen_integ(integrity_algorithm_t alg) { keylen_entry_t map[] = { {AUTH_HMAC_MD5_96, 128}, + {AUTH_HMAC_MD5_128, 128}, {AUTH_HMAC_SHA1_96, 160}, + {AUTH_HMAC_SHA1_160, 160}, {AUTH_HMAC_SHA2_256_96, 256}, {AUTH_HMAC_SHA2_256_128, 256}, {AUTH_HMAC_SHA2_384_192, 384}, diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index 3f434dae1..9a6d4ebcf 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -74,8 +75,10 @@ typedef struct { peer_cfg_t *peer_cfg; /** ref to instanciated CHILD_SA */ child_sa_t *child_sa; + /** TRUE if an acquire is pending */ + bool pending; /** pending IKE_SA connecting upon acquire */ - ike_sa_t *pending; + ike_sa_t *ike_sa; } entry_t; /** @@ -170,10 +173,10 @@ METHOD(trap_manager_t, install, u_int32_t, } reqid = child_sa->get_reqid(child_sa); - entry = malloc_thing(entry_t); - entry->child_sa = child_sa; - entry->peer_cfg = peer->get_ref(peer); - entry->pending = NULL; + INIT(entry, + .child_sa = child_sa, + .peer_cfg = peer->get_ref(peer), + ); this->lock->write_lock(this->lock); this->traps->insert_last(this->traps, entry); @@ -263,38 +266,49 @@ METHOD(trap_manager_t, acquire, void, if (!found) { DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid); + this->lock->unlock(this->lock); + return; } - else if (found->pending) + if (!cas_bool(&found->pending, FALSE, TRUE)) { DBG1(DBG_CFG, "ignoring acquire, connection attempt pending"); + this->lock->unlock(this->lock); + return; } - else + peer = found->peer_cfg->get_ref(found->peer_cfg); + child = found->child_sa->get_config(found->child_sa); + child = child->get_ref(child); + reqid = found->child_sa->get_reqid(found->child_sa); + /* don't hold the lock while checking out the IKE_SA */ + this->lock->unlock(this->lock); + + ike_sa = charon->ike_sa_manager->checkout_by_config( + charon->ike_sa_manager, peer); + if (ike_sa) { - child = found->child_sa->get_config(found->child_sa); - peer = found->peer_cfg; - ike_sa = charon->ike_sa_manager->checkout_by_config( - charon->ike_sa_manager, peer); - if (ike_sa) + if (ike_sa->get_peer_cfg(ike_sa) == NULL) { - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - ike_sa->set_peer_cfg(ike_sa, peer); - } - child->get_ref(child); - reqid = found->child_sa->get_reqid(found->child_sa); - if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + ike_sa->set_peer_cfg(ike_sa, peer); + } + if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + { + /* make sure the entry is still there */ + this->lock->read_lock(this->lock); + if (this->traps->find_first(this->traps, NULL, + (void**)&found) == SUCCESS) { - found->pending = ike_sa; - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + found->ike_sa = ike_sa; } - else - { - charon->ike_sa_manager->checkin_and_destroy( + this->lock->unlock(this->lock); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, ike_sa); - } } } - this->lock->unlock(this->lock); + peer->destroy(peer); } /** @@ -310,7 +324,7 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa, enumerator = this->traps->create_enumerator(this->traps); while (enumerator->enumerate(enumerator, &entry)) { - if (entry->pending != ike_sa) + if (entry->ike_sa != ike_sa) { continue; } @@ -319,7 +333,8 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa, { continue; } - entry->pending = NULL; + entry->ike_sa = NULL; + entry->pending = FALSE; } enumerator->destroy(enumerator); this->lock->unlock(this->lock); @@ -356,15 +371,21 @@ METHOD(listener_t, child_state_change, bool, METHOD(trap_manager_t, flush, void, private_trap_manager_t *this) { - this->traps->invoke_function(this->traps, (void*)destroy_entry); + linked_list_t *traps; + /* since destroying the CHILD_SA results in events which require a read + * lock we cannot destroy the list while holding the write lock */ + this->lock->write_lock(this->lock); + traps = this->traps; + this->traps = linked_list_create(); + this->lock->unlock(this->lock); + traps->destroy_function(traps, (void*)destroy_entry); } METHOD(trap_manager_t, destroy, void, private_trap_manager_t *this) { charon->bus->remove_listener(charon->bus, &this->listener.listener); - this->traps->invoke_function(this->traps, (void*)destroy_entry); - this->traps->destroy(this->traps); + this->traps->destroy_function(this->traps, (void*)destroy_entry); this->lock->destroy(this->lock); free(this); } diff --git a/src/libfast/dispatcher.c b/src/libfast/dispatcher.c index 8cfad0fd3..e5fca7074 100644 --- a/src/libfast/dispatcher.c +++ b/src/libfast/dispatcher.c @@ -183,8 +183,8 @@ static session_entry_t *session_entry_create(private_dispatcher_t *this, INIT(entry, .cond = condvar_create(CONDVAR_TYPE_DEFAULT), .session = load_session(this), - .used = time_monotonic(NULL), .host = strdup(host), + .used = time_monotonic(NULL), ); return entry; } diff --git a/src/libfast/smtp.h b/src/libfast/smtp.h index 910f18127..9589ea2a6 100644 --- a/src/libfast/smtp.h +++ b/src/libfast/smtp.h @@ -34,7 +34,7 @@ struct smtp_t { * Send an e-mail message. * * @param from sender address - * @param to receipient address + * @param to recipient address * @param subject mail subject * @param fmt mail body format string * @param ... arguments for body format string diff --git a/src/libfreeswan/Android.mk b/src/libfreeswan/Android.mk index e9805f0a3..a834d4846 100644 --- a/src/libfreeswan/Android.mk +++ b/src/libfreeswan/Android.mk @@ -26,6 +26,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := libfreeswan +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/libfreeswan/Makefile.am b/src/libfreeswan/Makefile.am index bc12fe386..b38343d34 100644 --- a/src/libfreeswan/Makefile.am +++ b/src/libfreeswan/Makefile.am @@ -19,3 +19,4 @@ dist_man3_MANS = anyaddr.3 atoaddr.3 atoasr.3 atoul.3 goodmask.3 initaddr.3 init portof.3 rangetosubnet.3 sameaddr.3 subnetof.3 \ ttoaddr.3 ttodata.3 ttosa.3 ttoul.3 +EXTRA_DIST = Android.mk diff --git a/src/libfreeswan/pfkey_v2_parse.c b/src/libfreeswan/pfkey_v2_parse.c index 7c0934c25..8fec9d119 100644 --- a/src/libfreeswan/pfkey_v2_parse.c +++ b/src/libfreeswan/pfkey_v2_parse.c @@ -40,12 +40,11 @@ char pfkey_v2_parse_c_version[] = ""; #define SENDERR(_x) do { error = -(_x); goto errlab; } while (0) -struct satype_tbl { +static struct { uint8_t proto; uint8_t satype; char* name; -} -static satype_tbl[] = { +} satype_tbl[] = { { SA_ESP, SADB_SATYPE_ESP, "ESP" }, { SA_AH, SADB_SATYPE_AH, "AH" }, { SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" }, diff --git a/src/libhydra/Android.mk b/src/libhydra/Android.mk index ccc527f94..075f8dbcb 100644 --- a/src/libhydra/Android.mk +++ b/src/libhydra/Android.mk @@ -32,6 +32,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := libhydra +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c index 922f27094..573557506 100644 --- a/src/libhydra/kernel/kernel_interface.c +++ b/src/libhydra/kernel/kernel_interface.c @@ -340,7 +340,7 @@ METHOD(kernel_interface_t, get_address_by_ts, status_t, if (!found) { - DBG1(DBG_KNL, "no local address found in traffic selector %R", ts); + DBG2(DBG_KNL, "no local address found in traffic selector %R", ts); return FAILED; } diff --git a/src/libhydra/plugins/attr_sql/sql_attribute.c b/src/libhydra/plugins/attr_sql/sql_attribute.c index fe7811b36..714bbcd72 100644 --- a/src/libhydra/plugins/attr_sql/sql_attribute.c +++ b/src/libhydra/plugins/attr_sql/sql_attribute.c @@ -38,7 +38,7 @@ struct private_sql_attribute_t { database_t *db; /** - * wheter to record lease history in lease table + * whether to record lease history in lease table */ bool history; }; diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index 49f5c3378..3451b673f 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -202,7 +202,9 @@ static kernel_algorithm_t encryption_algs[] = { */ static kernel_algorithm_t integrity_algs[] = { {AUTH_HMAC_MD5_96, "md5" }, + {AUTH_HMAC_MD5_128, "hmac(md5)" }, {AUTH_HMAC_SHA1_96, "sha1" }, + {AUTH_HMAC_SHA1_160, "hmac(sha1)" }, {AUTH_HMAC_SHA2_256_96, "sha256" }, {AUTH_HMAC_SHA2_256_128, "hmac(sha256)" }, {AUTH_HMAC_SHA2_384_192, "hmac(sha384)" }, @@ -1279,6 +1281,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, if (int_alg != AUTH_UNDEFINED) { + u_int trunc_len = 0; + alg_name = lookup_algorithm(integrity_algs, int_alg); if (alg_name == NULL) { @@ -1289,12 +1293,26 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", integrity_algorithm_names, int_alg, int_key.len * 8); - if (int_alg == AUTH_HMAC_SHA2_256_128) + switch (int_alg) + { + case AUTH_HMAC_MD5_128: + case AUTH_HMAC_SHA2_256_128: + trunc_len = 128; + break; + case AUTH_HMAC_SHA1_160: + trunc_len = 160; + break; + default: + break; + } + + if (trunc_len) { struct xfrm_algo_auth* algo; /* the kernel uses SHA256 with 96 bit truncation by default, - * use specified truncation size supported by newer kernels */ + * use specified truncation size supported by newer kernels. + * also use this for untruncated MD5 and SHA1. */ rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) + int_key.len); @@ -1307,7 +1325,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr); algo->alg_key_len = int_key.len * 8; - algo->alg_trunc_len = 128; + algo->alg_trunc_len = trunc_len; strcpy(algo->alg_name, alg_name); memcpy(algo->alg_key, int_key.ptr, int_key.len); } @@ -1990,7 +2008,8 @@ METHOD(kernel_ipsec_t, flush_sas, status_t, /** * Add or update a policy in the kernel. * - * Note: The mutex has to be locked when entering this function. + * Note: The mutex has to be locked when entering this function + * and is unlocked here in any case. */ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, policy_entry_t *policy, policy_sa_t *mapping, bool update) @@ -2060,6 +2079,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, hdr->nlmsg_len += RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl))); if (hdr->nlmsg_len > sizeof(request)) { + this->mutex->unlock(this->mutex); return FAILED; } @@ -2096,6 +2116,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { + this->mutex->unlock(this->mutex); return FAILED; } @@ -2544,6 +2565,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len); if (hdr->nlmsg_len > sizeof(request)) { + this->mutex->unlock(this->mutex); return FAILED; } diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c index 219657541..cce0ff402 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c @@ -375,9 +375,13 @@ static void process_link(private_kernel_netlink_net_t *this, { if (current->ifindex == msg->ifi_index) { - /* we do not remove it, as an address may be added to a - * "down" interface and we wan't to know that. */ - current->flags = msg->ifi_flags; + if (event) + { + update = TRUE; + DBG1(DBG_KNL, "interface %s deleted", current->ifname); + } + this->ifaces->remove_at(this->ifaces, enumerator); + iface_entry_destroy(current); break; } } @@ -1538,7 +1542,7 @@ kernel_netlink_net_t *kernel_netlink_net_create() return NULL; } addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | - RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_LINK; + RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK; if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr))) { DBG1(DBG_KNL, "unable to bind RT event socket"); diff --git a/src/libhydra/plugins/resolve/resolve_plugin.c b/src/libhydra/plugins/resolve/resolve_plugin.c index d23d36127..f95827ed9 100644 --- a/src/libhydra/plugins/resolve/resolve_plugin.c +++ b/src/libhydra/plugins/resolve/resolve_plugin.c @@ -31,7 +31,7 @@ struct private_resolve_plugin_t { resolve_plugin_t public; /** - * The registerd DNS attribute handler + * The registered DNS attribute handler */ resolve_handler_t *handler; }; diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index 1b240a1d9..fae9fd662 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -36,11 +36,3 @@ endif if USE_IMV_SCANNER SUBDIRS += plugins/imv_scanner endif - -if USE_IMC_ATTESTATION - SUBDIRS += plugins/imc_attestation -endif - -if USE_IMV_ATTESTATION - SUBDIRS += plugins/imv_attestation -endif diff --git a/src/libimcv/ietf/ietf_attr_port_filter.c b/src/libimcv/ietf/ietf_attr_port_filter.c index c9b76dde5..b53019657 100644 --- a/src/libimcv/ietf/ietf_attr_port_filter.c +++ b/src/libimcv/ietf/ietf_attr_port_filter.c @@ -81,6 +81,11 @@ struct private_ietf_attr_port_filter_t { * List of Port Filter entries */ linked_list_t *ports; + + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -166,12 +171,22 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_ietf_attr_port_filter_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_ietf_attr_port_filter_t *this) { - this->ports->destroy_function(this->ports, free); - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + this->ports->destroy_function(this->ports, free); + free(this->value.ptr); + free(this); + } } METHOD(ietf_attr_port_filter_t, add_port, void, @@ -224,6 +239,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .add_port = _add_port, @@ -232,6 +248,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void) .vendor_id = PEN_IETF, .type = IETF_ATTR_PORT_FILTER, .ports = linked_list_create(), + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -252,6 +269,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(chunk_t data) .get_value = _get_value, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .add_port = _add_port, @@ -261,6 +279,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(chunk_t data) .type = IETF_ATTR_PORT_FILTER, .value = chunk_clone(data), .ports = linked_list_create(), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libimcv/ietf/ietf_attr_product_info.c b/src/libimcv/ietf/ietf_attr_product_info.c index 222fef0bf..548793547 100644 --- a/src/libimcv/ietf/ietf_attr_product_info.c +++ b/src/libimcv/ietf/ietf_attr_product_info.c @@ -80,6 +80,10 @@ struct private_ietf_attr_product_info_t { */ char *product_name; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -154,12 +158,22 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_ietf_attr_product_info_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_ietf_attr_product_info_t *this) { - free(this->product_name); - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->product_name); + free(this->value.ptr); + free(this); + } } METHOD(ietf_attr_product_info_t, get_info, char*, @@ -194,6 +208,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create(pen_t vendor_id, u_int16_t id, .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_info = _get_info, @@ -203,6 +218,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create(pen_t vendor_id, u_int16_t id, .product_vendor_id = vendor_id, .product_id = id, .product_name = strdup(name), + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -223,6 +239,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create_from_data(chunk_t data) .get_value = _get_value, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_info = _get_info, @@ -230,6 +247,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create_from_data(chunk_t data) .vendor_id = PEN_IETF, .type = IETF_ATTR_PRODUCT_INFORMATION, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libimcv/imc/imc_agent.c b/src/libimcv/imc/imc_agent.c index 82778a5b6..6bba69733 100644 --- a/src/libimcv/imc/imc_agent.c +++ b/src/libimcv/imc/imc_agent.c @@ -39,9 +39,14 @@ struct private_imc_agent_t { const char *name; /** - * message type of IMC + * message vendor ID of IMC */ - TNC_MessageType type; + TNC_VendorID vendor_id; + + /** + * message subtype of IMC + */ + TNC_MessageSubtype subtype; /** * ID of IMC as assigned by TNCC @@ -49,17 +54,22 @@ struct private_imc_agent_t { TNC_IMCID id; /** + * List of additional IMC IDs assigned by TNCC + */ + linked_list_t *additional_ids; + + /** * list of TNCC connection entries */ linked_list_t *connections; /** - * rwlock to lock TNCS connection entries + * rwlock to lock TNCC connection entries */ rwlock_t *connection_lock; /** - * Inform a TNCS about the set of message types the IMC is able to receive + * Inform a TNCC about the set of message types the IMC is able to receive * * @param imc_id IMC ID assigned by TNCC * @param supported_types list of supported message types @@ -71,6 +81,20 @@ struct private_imc_agent_t { TNC_UInt32 type_count); /** + * Inform a TNCC about the set of message types the IMC is able to receive + * + * @param imc_id IMC ID assigned by TNCC + * @param supported_vids list of supported message vendor IDs + * @param supported_subtypes list of supported message subtypes + * @param type_count number of list elements + * @return TNC result code + */ + TNC_Result (*report_message_types_long)(TNC_IMCID imc_id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count); + + /** * Call when an IMC-IMC message is to be sent * * @param imc_id IMC ID assigned by TNCC @@ -85,6 +109,76 @@ struct private_imc_agent_t { TNC_BufferReference msg, TNC_UInt32 msg_len, TNC_MessageType msg_type); + + + /** + * Call when an IMC-IMC message is to be sent with long message types + * + * @param imc_id IMC ID assigned by TNCC + * @param connection_id network connection ID assigned by TNCC + * @param msg_flags message flags + * @param msg message to send + * @param msg_len message length in bytes + * @param msg_vid message vendor ID + * @param msg_subtype message subtype + * @param dst_imc_id destination IMV ID + * @return TNC result code + */ + TNC_Result (*send_message_long)(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 dst_imv_id); + + /** + * Get the value of an attribute associated with a connection + * or with the TNCC as a whole. + * + * @param imc_id IMC ID assigned by TNCC + * @param connection_id network connection ID assigned by TNCC + * @param attribute_id attribute ID + * @param buffer_len length of buffer in bytes + * @param buffer buffer + * @param out_value_len size in bytes of attribute stored in buffer + * @return TNC result code + */ + TNC_Result (*get_attribute)(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_AttributeID attribute_id, + TNC_UInt32 buffer_len, + TNC_BufferReference buffer, + TNC_UInt32 *out_value_len); + + /** + * Set the value of an attribute associated with a connection + * or with the TNCC as a whole. + * + * @param imc_id IMV ID assigned by TNCC + * @param connection_id network connection ID assigned by TNCC + * @param attribute_id attribute ID + * @param buffer_len length of buffer in bytes + * @param buffer buffer + * @return TNC result code + */ + TNC_Result (*set_attribute)(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_AttributeID attribute_id, + TNC_UInt32 buffer_len, + TNC_BufferReference buffer); + + /** + * Reserve an additional IMC ID + * + * @param imc_id primary IMC ID assigned by TNCC + * @param out_imc_id additional IMC ID assigned by TNCC + * @return TNC result code + */ + TNC_Result (*reserve_additional_id)(TNC_IMCID imc_id, + TNC_UInt32 *out_imc_id); + }; METHOD(imc_agent_t, bind_functions, TNC_Result, @@ -100,6 +194,11 @@ METHOD(imc_agent_t, bind_functions, TNC_Result, { this->report_message_types = NULL; } + if (bind_function(this->id, "TNC_TNCC_ReportMessageTypesLong", + (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS) + { + this->report_message_types_long = NULL; + } if (bind_function(this->id, "TNC_TNCC_RequestHandshakeRetry", (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS) { @@ -110,12 +209,42 @@ METHOD(imc_agent_t, bind_functions, TNC_Result, { this->send_message = NULL; } + if (bind_function(this->id, "TNC_TNCC_SendMessageLong", + (void**)&this->send_message_long) != TNC_RESULT_SUCCESS) + { + this->send_message_long = NULL; + } + if (bind_function(this->id, "TNC_TNCC_GetAttribute", + (void**)&this->get_attribute) != TNC_RESULT_SUCCESS) + { + this->get_attribute = NULL; + } + if (bind_function(this->id, "TNC_TNCC_SetAttribute", + (void**)&this->set_attribute) != TNC_RESULT_SUCCESS) + { + this->set_attribute = NULL; + } + if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMCID", + (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS) + { + this->reserve_additional_id = NULL; + } DBG2(DBG_IMC, "IMC %u \"%s\" provided with bind function", this->id, this->name); - if (this->report_message_types) + if (this->report_message_types_long) + { + this->report_message_types_long(this->id, &this->vendor_id, + &this->subtype, 1); + } + else if (this->report_message_types && + this->vendor_id <= TNC_VENDORID_ANY && + this->subtype <= TNC_SUBTYPE_ANY) { - this->report_message_types(this->id, &this->type, 1); + TNC_MessageType type; + + type = (this->vendor_id << 8) | this->subtype; + this->report_message_types(this->id, &type, 1); } return TNC_RESULT_SUCCESS; } @@ -172,24 +301,78 @@ static bool delete_connection(private_imc_agent_t *this, TNC_ConnectionID id) return found; } +/** + * Read a boolean attribute + */ +static bool get_bool_attribute(private_imc_agent_t *this, TNC_ConnectionID id, + TNC_AttributeID attribute_id) +{ + TNC_UInt32 len; + char buf[4]; + + return this->get_attribute && + this->get_attribute(this->id, id, attribute_id, 4, buf, &len) == + TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01; + } + +/** + * Read a string attribute + */ +static char* get_str_attribute(private_imc_agent_t *this, TNC_ConnectionID id, + TNC_AttributeID attribute_id) +{ + TNC_UInt32 len; + char buf[BUF_LEN]; + + if (this->get_attribute && + this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) == + TNC_RESULT_SUCCESS && len <= BUF_LEN) + { + return strdup(buf); + } + return NULL; + } + METHOD(imc_agent_t, create_state, TNC_Result, private_imc_agent_t *this, imc_state_t *state) { - TNC_ConnectionID connection_id; + TNC_ConnectionID conn_id; + char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL; + bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE; - connection_id = state->get_connection_id(state); - if (find_connection(this, connection_id)) + conn_id = state->get_connection_id(state); + if (find_connection(this, conn_id)) { DBG1(DBG_IMC, "IMC %u \"%s\" already created a state for Connection ID %u", - this->id, this->name, connection_id); + this->id, this->name, conn_id); state->destroy(state); return TNC_RESULT_OTHER; } + + /* Get and display attributes from TNCC via IF-IMC */ + has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES); + has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE); + has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH); + tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL); + tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION); + t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL); + t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION); + + state->set_flags(state, has_long, has_excl); + + DBG2(DBG_IMC, "IMC %u \"%s\" created a state for Connection ID %u: " + "%s %s with %slong %sexcl %ssoh over %s %s", + this->id, this->name, conn_id, tnccs_p ? tnccs_p:"?", + tnccs_v ? tnccs_v:"?", has_long ? "+":"-", has_excl ? "+":"-", + has_soh ? "+":"-", t_p ? t_p:"?", t_v ? t_v :"?"); + free(tnccs_p); + free(tnccs_v); + free(t_p); + free(t_v); + this->connection_lock->write_lock(this->connection_lock); this->connections->insert_last(this->connections, state); this->connection_lock->unlock(this->connection_lock); - DBG2(DBG_IMC, "IMC %u \"%s\" created a state for Connection ID %u", - this->id, this->name, connection_id); return TNC_RESULT_SUCCESS; } @@ -269,27 +452,78 @@ METHOD(imc_agent_t, get_state, bool, } METHOD(imc_agent_t, send_message, TNC_Result, - private_imc_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg) + private_imc_agent_t *this, TNC_ConnectionID connection_id, bool excl, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, chunk_t msg) { - if (!this->send_message) + TNC_MessageType type; + TNC_UInt32 msg_flags; + imc_state_t *state; + + state = find_connection(this, connection_id); + if (!state) { + DBG1(DBG_IMV, "IMC %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); return TNC_RESULT_FATAL; } - return this->send_message(this->id, connection_id, msg.ptr, msg.len, - this->type); + + if (state->has_long(state) && this->send_message_long) + { + if (!src_imc_id) + { + src_imc_id = this->id; + } + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + + return this->send_message_long(src_imc_id, connection_id, msg_flags, + msg.ptr, msg.len, this->vendor_id, + this->subtype, dst_imv_id); + } + if (this->send_message) + { + type = (this->vendor_id << 8) | this->subtype; + + return this->send_message(this->id, connection_id, msg.ptr, msg.len, + type); + } + return TNC_RESULT_FATAL; } METHOD(imc_agent_t, receive_message, TNC_Result, - private_imc_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg, - TNC_MessageType msg_type, pa_tnc_msg_t **pa_tnc_msg) + private_imc_agent_t *this, imc_state_t *state, chunk_t msg, + TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, pa_tnc_msg_t **pa_tnc_msg) { pa_tnc_msg_t *pa_msg, *error_msg; pa_tnc_attr_t *error_attr; enumerator_t *enumerator; + TNC_MessageType msg_type; + TNC_UInt32 msg_flags, src_imc_id, dst_imv_id; + TNC_ConnectionID connection_id; TNC_Result result; - DBG2(DBG_IMV, "IMC %u \"%s\" received message type 0x%08x for Connection ID %u", - this->id, this->name, msg_type, connection_id); + connection_id = state->get_connection_id(state); + + if (state->has_long(state)) + { + if (dst_imc_id != TNC_IMCID_ANY) + { + DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u " + "from IMV %u to IMC %u", this->id, this->name, + connection_id, src_imv_id, dst_imc_id); + } + else + { + DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u " + "from IMV %u", this->id, this->name, connection_id, + src_imv_id); + } + } + else + { + DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u", + this->id, this->name, connection_id); + } *pa_tnc_msg = NULL; pa_msg = pa_tnc_msg_create_from_data(msg); @@ -300,12 +534,6 @@ METHOD(imc_agent_t, receive_message, TNC_Result, *pa_tnc_msg = pa_msg; break; case VERIFY_ERROR: - if (!this->send_message) - { - /* TNCC doen't have a SendMessage() function */ - return TNC_RESULT_FATAL; - } - /* build error message */ error_msg = pa_tnc_msg_create(); enumerator = pa_msg->create_error_enumerator(pa_msg); @@ -318,9 +546,36 @@ METHOD(imc_agent_t, receive_message, TNC_Result, error_msg->build(error_msg); /* send error message */ - msg = error_msg->get_encoding(error_msg); - result = this->send_message(this->id, connection_id, + if (state->has_long(state) && this->send_message_long) + { + if (state->has_excl(state)) + { + msg_flags = TNC_MESSAGE_FLAGS_EXCLUSIVE; + dst_imv_id = src_imv_id; + } + else + { + msg_flags = 0; + dst_imv_id = TNC_IMVID_ANY; + } + src_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? this->id + : dst_imc_id; + + result = this->send_message_long(src_imc_id, connection_id, + msg_flags, msg.ptr, msg.len, msg_vid, + msg_subtype, dst_imv_id); + } + else if (this->send_message) + { + msg_type = (msg_vid << 8) | msg_subtype; + + result = this->send_message(this->id, connection_id, msg.ptr, msg.len, msg_type); + } + else + { + result = TNC_RESULT_FATAL; + } /* clean up */ error_msg->destroy(error_msg); @@ -334,10 +589,56 @@ METHOD(imc_agent_t, receive_message, TNC_Result, return TNC_RESULT_SUCCESS; } +METHOD(imc_agent_t, reserve_additional_ids, TNC_Result, + private_imc_agent_t *this, int count) +{ + TNC_Result result; + TNC_UInt32 id; + void *pointer; + + if (!this->reserve_additional_id) + { + DBG1(DBG_IMC, "IMC %u \"%s\" did not detect the capability to reserve " + "additional IMC IDs from the TNCC", this->id, this->name); + return TNC_RESULT_ILLEGAL_OPERATION; + } + while (count > 0) + { + result = this->reserve_additional_id(this->id, &id); + if (result != TNC_RESULT_SUCCESS) + { + DBG1(DBG_IMC, "IMC %u \"%s\" failed to reserve %d additional IMC IDs", + this->id, this->name, count); + return result; + } + count--; + + /* store the scalar value in the pointer */ + pointer = (void*)id; + this->additional_ids->insert_last(this->additional_ids, pointer); + DBG2(DBG_IMC, "IMC %u \"%s\" reserved additional ID %u", + this->id, this->name, id); + } + return TNC_RESULT_SUCCESS; +} + +METHOD(imc_agent_t, count_additional_ids, int, + private_imc_agent_t *this) +{ + return this->additional_ids->get_count(this->additional_ids); +} + +METHOD(imc_agent_t, create_id_enumerator, enumerator_t*, + private_imc_agent_t *this) +{ + return this->additional_ids->create_enumerator(this->additional_ids); +} + METHOD(imc_agent_t, destroy, void, private_imc_agent_t *this) { DBG1(DBG_IMC, "IMC %u \"%s\" terminated", this->id, this->name); + this->additional_ids->destroy(this->additional_ids); this->connections->destroy_function(this->connections, free); this->connection_lock->destroy(this->connection_lock); free(this); @@ -370,11 +671,16 @@ imc_agent_t *imc_agent_create(const char *name, .get_state = _get_state, .send_message = _send_message, .receive_message = _receive_message, + .reserve_additional_ids = _reserve_additional_ids, + .count_additional_ids = _count_additional_ids, + .create_id_enumerator = _create_id_enumerator, .destroy = _destroy, }, .name = name, - .type = (vendor_id << 8) | (subtype & 0xff), + .vendor_id = vendor_id, + .subtype = subtype, .id = id, + .additional_ids = linked_list_create(), .connections = linked_list_create(), .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); diff --git a/src/libimcv/imc/imc_agent.h b/src/libimcv/imc/imc_agent.h index 1912a39c1..d1fef4d8d 100644 --- a/src/libimcv/imc/imc_agent.h +++ b/src/libimcv/imc/imc_agent.h @@ -101,28 +101,58 @@ struct imc_agent_t { * Call when an PA-TNC message is to be sent * * @param connection_id network connection ID assigned by TNCC + * @param excl exclusive flag + * @param src_imc_id IMC ID to be set as source + * @param dst_imv_id IMV ID to be set as destination * @param msg message to send * @return TNC result code */ TNC_Result (*send_message)(imc_agent_t *this, - TNC_ConnectionID connection_id, + TNC_ConnectionID connection_id, bool excl, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, chunk_t msg); /** * Call when a PA-TNC message was received * - * @param connection_id network connection ID assigned by TNCC + * @param state state for current connection * @param msg received unparsed message - * @param msg_type message type of the received message + * @param msg_vid message vendorID of the received message + * @param msg_subtype message subtype of the received message + * @param src_imv_id source IMV ID + * @param dst_imc_id destination IMC ID * @param pa_tnc_message parsed PA-TNC message or NULL if an error occurred * @return TNC result code */ TNC_Result (*receive_message)(imc_agent_t *this, - TNC_ConnectionID connection_id, chunk_t msg, - TNC_MessageType msg_type, + imc_state_t *state, chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, + TNC_UInt32 dst_imc_id, pa_tnc_msg_t **pa_tnc_msg); /** + * Reserve additional IMC IDs from TNCC + * + * @param count number of additional IMC IDs to be assigned + * @return TNC result code + */ + TNC_Result (*reserve_additional_ids)(imc_agent_t *this, int count); + + /** + * Return the number of additional IMC IDs assigned by the TNCC + * + * @return number of additional IMC IDs + */ + int (*count_additional_ids)(imc_agent_t *this); + + /** + * Create an enumerator for the additional IMC IDs + */ + enumerator_t* (*create_id_enumerator)(imc_agent_t *this); + + /** * Destroys an imc_agent_t object */ void (*destroy)(imc_agent_t *this); diff --git a/src/libimcv/imc/imc_state.h b/src/libimcv/imc/imc_state.h index 73013f8ce..f1b0358c9 100644 --- a/src/libimcv/imc/imc_state.h +++ b/src/libimcv/imc/imc_state.h @@ -33,13 +33,37 @@ typedef struct imc_state_t imc_state_t; struct imc_state_t { /** - * Get the TNCS connection ID attached to the state + * Get the TNCS connection I +D attached to the state * * @return TNCS connection ID of the state */ TNC_ConnectionID (*get_connection_id)(imc_state_t *this); /** + * Checks if long message types are supported for this TNCCS connection + * + * @return TRUE if set, FALSE otherwise + */ + bool (*has_long)(imc_state_t *this); + + /** + * Checks if the exclusive delivery is supported for this TNCCS connection + * + * @return TRUE if set, FALSE otherwise + */ + bool (*has_excl)(imc_state_t *this); + + /** + * Sets the long message types and exclusive flags for this TNCCS connection + * + * @param has_long TNCCS connection supports long message types + * @param has_excl TNCCS connection supports exclusive delivery + * @return TRUE if set, FALSE otherwise + */ + void (*set_flags)(imc_state_t *this, bool has_long, bool has_excl); + + /** * Change the connection state * * @param new_state new connection state diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c index 290bb1147..56131c547 100644 --- a/src/libimcv/imv/imv_agent.c +++ b/src/libimcv/imv/imv_agent.c @@ -39,9 +39,14 @@ struct private_imv_agent_t { const char *name; /** - * message type of IMV + * message vendor ID of IMV */ - TNC_MessageType type; + TNC_VendorID vendor_id; + + /** + * message subtype of IMV + */ + TNC_MessageSubtype subtype; /** * ID of IMV as assigned by TNCS @@ -49,6 +54,11 @@ struct private_imv_agent_t { TNC_IMVID id; /** + * List of additional IMV IDs assigned by TNCS + */ + linked_list_t *additional_ids; + + /** * list of TNCS connection entries */ linked_list_t *connections; @@ -59,7 +69,7 @@ struct private_imv_agent_t { rwlock_t *connection_lock; /** - * Inform a TNCS about the set of message types the IMV is able to receive + * Inform a TNCS about the set of message types the IMV is able to receive * * @param imv_id IMV ID assigned by TNCS * @param supported_types list of supported message types @@ -71,6 +81,20 @@ struct private_imv_agent_t { TNC_UInt32 type_count); /** + * Inform a TNCS about the set of message types the IMV is able to receive + * + * @param imv_id IMV ID assigned by TNCS + * @param supported_vids list of supported message vendor IDs + * @param supported_subtypes list of supported message subtypes + * @param type_count number of list elements + * @return TNC result code + */ + TNC_Result (*report_message_types_long)(TNC_IMVID imv_id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count); + + /** * Call when an IMV-IMC message is to be sent * * @param imv_id IMV ID assigned by TNCS @@ -87,6 +111,28 @@ struct private_imv_agent_t { TNC_MessageType msg_type); /** + * Call when an IMV-IMC message is to be sent with long message types + * + * @param imv_id IMV ID assigned by TNCS + * @param connection_id network connection ID assigned by TNCS + * @param msg_flags message flags + * @param msg message to send + * @param msg_len message length in bytes + * @param msg_vid message vendor ID + * @param msg_subtype message subtype + * @param dst_imc_id destination IMC ID + * @return TNC result code + */ + TNC_Result (*send_message_long)(TNC_IMVID imv_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 dst_imc_id); + + /** * Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS * * @param imv_id IMV ID assigned by TNCS @@ -135,6 +181,17 @@ struct private_imv_agent_t { TNC_AttributeID attribute_id, TNC_UInt32 buffer_len, TNC_BufferReference buffer); + + /** + * Reserve an additional IMV ID + * + * @param imv_id primary IMV ID assigned by TNCS + * @param out_imv_id additional IMV ID assigned by TNCS + * @return TNC result code + */ + TNC_Result (*reserve_additional_id)(TNC_IMVID imv_id, + TNC_UInt32 *out_imv_id); + }; METHOD(imv_agent_t, bind_functions, TNC_Result, @@ -150,6 +207,11 @@ METHOD(imv_agent_t, bind_functions, TNC_Result, { this->report_message_types = NULL; } + if (bind_function(this->id, "TNC_TNCS_ReportMessageTypesLong", + (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS) + { + this->report_message_types_long = NULL; + } if (bind_function(this->id, "TNC_TNCS_RequestHandshakeRetry", (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS) { @@ -160,6 +222,11 @@ METHOD(imv_agent_t, bind_functions, TNC_Result, { this->send_message = NULL; } + if (bind_function(this->id, "TNC_TNCS_SendMessageLong", + (void**)&this->send_message_long) != TNC_RESULT_SUCCESS) + { + this->send_message_long = NULL; + } if (bind_function(this->id, "TNC_TNCS_ProvideRecommendation", (void**)&this->provide_recommendation) != TNC_RESULT_SUCCESS) { @@ -175,12 +242,27 @@ METHOD(imv_agent_t, bind_functions, TNC_Result, { this->set_attribute = NULL; } + if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMVID", + (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS) + { + this->reserve_additional_id = NULL; + } DBG2(DBG_IMV, "IMV %u \"%s\" provided with bind function", this->id, this->name); - if (this->report_message_types) + if (this->report_message_types_long) + { + this->report_message_types_long(this->id, &this->vendor_id, + &this->subtype, 1); + } + else if (this->report_message_types && + this->vendor_id <= TNC_VENDORID_ANY && + this->subtype <= TNC_SUBTYPE_ANY) { - this->report_message_types(this->id, &this->type, 1); + TNC_MessageType type; + + type = (this->vendor_id << 8) | this->subtype; + this->report_message_types(this->id, &type, 1); } return TNC_RESULT_SUCCESS; } @@ -237,24 +319,78 @@ static bool delete_connection(private_imv_agent_t *this, TNC_ConnectionID id) return found; } +/** + * Read a boolean attribute + */ +static bool get_bool_attribute(private_imv_agent_t *this, TNC_ConnectionID id, + TNC_AttributeID attribute_id) +{ + TNC_UInt32 len; + char buf[4]; + + return this->get_attribute && + this->get_attribute(this->id, id, attribute_id, 4, buf, &len) == + TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01; + } + +/** + * Read a string attribute + */ +static char* get_str_attribute(private_imv_agent_t *this, TNC_ConnectionID id, + TNC_AttributeID attribute_id) +{ + TNC_UInt32 len; + char buf[BUF_LEN]; + + if (this->get_attribute && + this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) == + TNC_RESULT_SUCCESS && len <= BUF_LEN) + { + return strdup(buf); + } + return NULL; + } + METHOD(imv_agent_t, create_state, TNC_Result, private_imv_agent_t *this, imv_state_t *state) { - TNC_ConnectionID connection_id; + TNC_ConnectionID conn_id; + char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL; + bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE; - connection_id = state->get_connection_id(state); - if (find_connection(this, connection_id)) + conn_id = state->get_connection_id(state); + if (find_connection(this, conn_id)) { DBG1(DBG_IMV, "IMV %u \"%s\" already created a state for Connection ID %u", - this->id, this->name, connection_id); + this->id, this->name, conn_id); state->destroy(state); return TNC_RESULT_OTHER; } + + /* Get and display attributes from TNCS via IF-IMV */ + has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES); + has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE); + has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH); + tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL); + tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION); + t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL); + t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION); + + state->set_flags(state, has_long, has_excl); + + DBG2(DBG_IMV, "IMV %u \"%s\" created a state for Connection ID %u: " + "%s %s with %slong %sexcl %ssoh over %s %s", + this->id, this->name, conn_id, tnccs_p ? tnccs_p:"?", + tnccs_v ? tnccs_v:"?", has_long ? "+":"-", has_excl ? "+":"-", + has_soh ? "+":"-", t_p ? t_p:"?", t_v ? t_v :"?"); + free(tnccs_p); + free(tnccs_v); + free(t_p); + free(t_v); + this->connection_lock->write_lock(this->connection_lock); this->connections->insert_last(this->connections, state); this->connection_lock->unlock(this->connection_lock); - DBG2(DBG_IMV, "IMV %u \"%s\" created a state for Connection ID %u", - this->id, this->name, connection_id); return TNC_RESULT_SUCCESS; } @@ -333,14 +469,41 @@ METHOD(imv_agent_t, get_state, bool, } METHOD(imv_agent_t, send_message, TNC_Result, - private_imv_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg) + private_imv_agent_t *this, TNC_ConnectionID connection_id, bool excl, + TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, chunk_t msg) { - if (!this->send_message) + TNC_MessageType type; + TNC_UInt32 msg_flags; + imv_state_t *state; + + state = find_connection(this, connection_id); + if (!state) { + DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); return TNC_RESULT_FATAL; } - return this->send_message(this->id, connection_id, msg.ptr, msg.len, - this->type); + + if (state->has_long(state) && this->send_message_long) + { + if (!src_imv_id) + { + src_imv_id = this->id; + } + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + + return this->send_message_long(src_imv_id, connection_id, msg_flags, + msg.ptr, msg.len, this->vendor_id, + this->subtype, dst_imc_id); + } + if (this->send_message) + { + type = (this->vendor_id << 8) | this->subtype; + + return this->send_message(this->id, connection_id, msg.ptr, msg.len, + type); + } + return TNC_RESULT_FATAL; } METHOD(imv_agent_t, set_recommendation, TNC_Result, @@ -363,16 +526,40 @@ METHOD(imv_agent_t, set_recommendation, TNC_Result, } METHOD(imv_agent_t, receive_message, TNC_Result, - private_imv_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg, - TNC_MessageType msg_type, pa_tnc_msg_t **pa_tnc_msg) + private_imv_agent_t *this, imv_state_t *state, chunk_t msg, + TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, pa_tnc_msg_t **pa_tnc_msg) { pa_tnc_msg_t *pa_msg, *error_msg; pa_tnc_attr_t *error_attr; enumerator_t *enumerator; + TNC_MessageType msg_type; + TNC_UInt32 msg_flags, src_imv_id, dst_imc_id; + TNC_ConnectionID connection_id; TNC_Result result; - DBG2(DBG_IMV, "IMV %u \"%s\" received message type 0x%08x for Connection ID %u", - this->id, this->name, msg_type, connection_id); + connection_id = state->get_connection_id(state); + + if (state->has_long(state)) + { + if (dst_imv_id != TNC_IMVID_ANY) + { + DBG2(DBG_IMV, "IMV %u \"%s\" received message for Connection ID %u " + "from IMC %u to IMV %u", this->id, this->name, + connection_id, src_imc_id, dst_imv_id); + } + else + { + DBG2(DBG_IMV, "IMV %u \"%s\" received message for Connection ID %u " + "from IMC %u", this->id, this->name, connection_id, + src_imc_id); + } + } + else + { + DBG2(DBG_IMV, "IMV %u \"%s\" received message for Connection ID %u", + this->id, this->name, connection_id); + } *pa_tnc_msg = NULL; pa_msg = pa_tnc_msg_create_from_data(msg); @@ -383,12 +570,6 @@ METHOD(imv_agent_t, receive_message, TNC_Result, *pa_tnc_msg = pa_msg; break; case VERIFY_ERROR: - if (!this->send_message) - { - /* TNCS doen't have a SendMessage() function */ - return TNC_RESULT_FATAL; - } - /* build error message */ error_msg = pa_tnc_msg_create(); enumerator = pa_msg->create_error_enumerator(pa_msg); @@ -402,8 +583,37 @@ METHOD(imv_agent_t, receive_message, TNC_Result, /* send error message */ msg = error_msg->get_encoding(error_msg); - result = this->send_message(this->id, connection_id, + + if (state->has_long(state) && this->send_message_long) + { + if (state->has_excl(state)) + { + msg_flags = TNC_MESSAGE_FLAGS_EXCLUSIVE; + dst_imc_id = src_imc_id; + } + else + { + msg_flags = 0; + dst_imc_id = TNC_IMCID_ANY; + } + src_imv_id = (dst_imv_id == TNC_IMVID_ANY) ? this->id + : dst_imv_id; + + result = this->send_message_long(src_imv_id, connection_id, + msg_flags, msg.ptr, msg.len, msg_vid, + msg_subtype, dst_imc_id); + } + else if (this->send_message) + { + msg_type = (msg_vid << 8) | msg_subtype; + + result = this->send_message(this->id, connection_id, msg.ptr, msg.len, msg_type); + } + else + { + result = TNC_RESULT_FATAL; + } /* clean up */ error_msg->destroy(error_msg); @@ -412,7 +622,10 @@ METHOD(imv_agent_t, receive_message, TNC_Result, case FAILED: default: pa_msg->destroy(pa_msg); - return set_recommendation(this, connection_id, + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + return this->provide_recommendation(this->id, connection_id, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, TNC_IMV_EVALUATION_RESULT_ERROR); } @@ -471,10 +684,56 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result, return this->provide_recommendation(this->id, connection_id, rec, eval); } +METHOD(imv_agent_t, reserve_additional_ids, TNC_Result, + private_imv_agent_t *this, int count) +{ + TNC_Result result; + TNC_UInt32 id; + void *pointer; + + if (!this->reserve_additional_id) + { + DBG1(DBG_IMV, "IMV %u \"%s\" did not detect the capability to reserve " + "additional IMV IDs from the TNCS", this->id, this->name); + return TNC_RESULT_ILLEGAL_OPERATION; + } + while (count > 0) + { + result = this->reserve_additional_id(this->id, &id); + if (result != TNC_RESULT_SUCCESS) + { + DBG1(DBG_IMV, "IMV %u \"%s\" failed to reserve %d additional IMV IDs", + this->id, this->name, count); + return result; + } + count--; + + /* store the scalar value in the pointer */ + pointer = (void*)id; + this->additional_ids->insert_last(this->additional_ids, pointer); + DBG2(DBG_IMV, "IMV %u \"%s\" reserved additional ID %u", + this->id, this->name, id); + } + return TNC_RESULT_SUCCESS; +} + +METHOD(imv_agent_t, count_additional_ids, int, + private_imv_agent_t *this) +{ + return this->additional_ids->get_count(this->additional_ids); +} + +METHOD(imv_agent_t, create_id_enumerator, enumerator_t*, + private_imv_agent_t *this) +{ + return this->additional_ids->create_enumerator(this->additional_ids); +} + METHOD(imv_agent_t, destroy, void, private_imv_agent_t *this) { DBG1(DBG_IMV, "IMV %u \"%s\" terminated", this->id, this->name); + this->additional_ids->destroy(this->additional_ids); this->connections->destroy_offset(this->connections, offsetof(imv_state_t, destroy)); this->connection_lock->destroy(this->connection_lock); @@ -510,11 +769,16 @@ imv_agent_t *imv_agent_create(const char *name, .receive_message = _receive_message, .set_recommendation = _set_recommendation, .provide_recommendation = _provide_recommendation, + .reserve_additional_ids = _reserve_additional_ids, + .count_additional_ids = _count_additional_ids, + .create_id_enumerator = _create_id_enumerator, .destroy = _destroy, }, .name = name, - .type = (vendor_id << 8) | (subtype & 0xff), + .vendor_id = vendor_id, + .subtype = subtype, .id = id, + .additional_ids = linked_list_create(), .connections = linked_list_create(), .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); diff --git a/src/libimcv/imv/imv_agent.h b/src/libimcv/imv/imv_agent.h index b6c8841f2..de70f3bc1 100644 --- a/src/libimcv/imv/imv_agent.h +++ b/src/libimcv/imv/imv_agent.h @@ -101,24 +101,35 @@ struct imv_agent_t { * Call when a PA-TNC message is to be sent * * @param connection_id network connection ID assigned by TNCS + * @param excl exclusive flag + * @param src_imv_id IMV ID to be set as source + * @param dst_imc_id IMD ID to be set as destination * @param msg message to send * @return TNC result code */ TNC_Result (*send_message)(imv_agent_t *this, - TNC_ConnectionID connection_id, chunk_t msg); + TNC_ConnectionID connection_id, bool excl, + TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, + chunk_t msg); /** * Call when a PA-TNC message was received * - * @param connection_id network connection ID assigned by TNCS + * @param state state for current connection * @param msg received unparsed message - * @param msg_type message type of the received message + * @param msg_vid message vendorID of the received message + * @param msg_subtype message subtype of the received message + * @param src_imc_id source IMC ID + * @param dst_imv_id destination IMV ID * @param pa_tnc_message parsed PA-TNC message or NULL if an error occurred * @return TNC result code */ TNC_Result (*receive_message)(imv_agent_t *this, - TNC_ConnectionID connection_id, chunk_t msg, - TNC_MessageType msg_type, + imv_state_t *state, chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id, pa_tnc_msg_t **pa_tnc_msg); /** @@ -144,6 +155,26 @@ struct imv_agent_t { TNC_ConnectionID connection_id); /** + * Reserve additional IMV IDs from TNCS + * + * @param count number of additional IMV IDs to be assigned + * @return TNC result code + */ + TNC_Result (*reserve_additional_ids)(imv_agent_t *this, int count); + + /** + * Return the number of additional IMV IDs assigned by the TNCS + * + * @return number of additional IMV IDs + */ + int (*count_additional_ids)(imv_agent_t *this); + + /** + * Create an enumerator for the additional IMV IDs + */ + enumerator_t* (*create_id_enumerator)(imv_agent_t *this); + + /** * Destroys an imv_agent_t object */ void (*destroy)(imv_agent_t *this); diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h index 26d07bb02..9e7a29a9f 100644 --- a/src/libimcv/imv/imv_state.h +++ b/src/libimcv/imv/imv_state.h @@ -40,6 +40,29 @@ struct imv_state_t { TNC_ConnectionID (*get_connection_id)(imv_state_t *this); /** + * Checks if long message types are supported for this TNCCS connection + * + * @return TRUE if set, FALSE otherwise + */ + bool (*has_long)(imv_state_t *this); + + /** + * Checks if the exclusive delivery is supported for this TNCCS connection + * + * @return TRUE if set, FALSE otherwise + */ + bool (*has_excl)(imv_state_t *this); + + /** + * Sets the long message types and exclusive flags for this TNCCS connection + * + * @param has_long TNCCS connection supports long message types + * @param has_excl TNCCS connection supports exclusive delivery + * @return TRUE if set, FALSE otherwise + */ + void (*set_flags)(imv_state_t *this, bool has_long, bool has_excl); + + /** * Change the connection state * * @param new_state new connection state diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.c b/src/libimcv/pa_tnc/pa_tnc_msg.c index f8d3b9d0e..b5df0a5b5 100644 --- a/src/libimcv/pa_tnc/pa_tnc_msg.c +++ b/src/libimcv/pa_tnc/pa_tnc_msg.c @@ -311,6 +311,63 @@ err: return VERIFY_ERROR; } +METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool, + private_pa_tnc_msg_t *this) +{ + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + bool fatal_error = FALSE; + + enumerator = this->attributes->create_enumerator(this->attributes); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->get_vendor_id(attr) == PEN_IETF && + attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) + { + ietf_attr_pa_tnc_error_t *error_attr; + pen_t error_vendor_id; + pa_tnc_error_code_t error_code; + chunk_t msg_info, attr_info; + u_int32_t offset; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; + error_vendor_id = error_attr->get_vendor_id(error_attr); + error_code = error_attr->get_error_code(error_attr); + msg_info = error_attr->get_msg_info(error_attr); + + /* skip errors from non-IETF namespaces */ + if (error_vendor_id != PEN_IETF) + { + continue; + } + DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message " + "0x%08x/0x%08x", pa_tnc_error_code_names, error_code, + untoh32(msg_info.ptr), untoh32(msg_info.ptr + 4)); + + switch (error_code) + { + case PA_ERROR_INVALID_PARAMETER: + offset = error_attr->get_offset(error_attr); + DBG1(DBG_IMC, " occurred at offset of %u bytes", offset); + break; + case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED: + attr_info = error_attr->get_attr_info(error_attr); + DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info); + break; + default: + break; + } + + /* remove the processed IETF standard error attribute */ + this->attributes->remove_at(this->attributes, enumerator); + fatal_error = TRUE; + } + } + enumerator->destroy(enumerator); + + return fatal_error; +} + METHOD(pa_tnc_msg_t, create_attribute_enumerator, enumerator_t*, private_pa_tnc_msg_t *this) { @@ -347,6 +404,7 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) .add_attribute = _add_attribute, .build = _build, .process = _process, + .process_ietf_std_errors = _process_ietf_std_errors, .create_attribute_enumerator = _create_attribute_enumerator, .create_error_enumerator = _create_error_enumerator, .destroy = _destroy, diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.h b/src/libimcv/pa_tnc/pa_tnc_msg.h index bff954678..c3ce829d5 100644 --- a/src/libimcv/pa_tnc/pa_tnc_msg.h +++ b/src/libimcv/pa_tnc/pa_tnc_msg.h @@ -62,6 +62,13 @@ struct pa_tnc_msg_t { status_t (*process)(pa_tnc_msg_t *this); /** + * Process and remove all IETF standard error PA-TNC attributes + * + * @return TRUE if at least one error attribute processed + */ + bool (*process_ietf_std_errors)(pa_tnc_msg_t *this); + + /** * Enumerates over all PA-TNC attributes * * @return return attribute enumerator diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation.c b/src/libimcv/plugins/imc_attestation/imc_attestation.c deleted file mode 100644 index 3c26f9b5c..000000000 --- a/src/libimcv/plugins/imc_attestation/imc_attestation.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (C) 2011 Sansar Choinyambuu - * HSR 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_attestation_state.h" - -#include <imc/imc_agent.h> -#include <pa_tnc/pa_tnc_msg.h> -#include <ietf/ietf_attr.h> -#include <ietf/ietf_attr_pa_tnc_error.h> -#include <ietf/ietf_attr_product_info.h> - -#include <libpts.h> - -#include <pts/pts_error.h> - -#include <tcg/tcg_pts_attr_proto_caps.h> -#include <tcg/tcg_pts_attr_meas_algo.h> -#include <tcg/tcg_pts_attr_get_tpm_version_info.h> -#include <tcg/tcg_pts_attr_tpm_version_info.h> -#include <tcg/tcg_pts_attr_get_aik.h> -#include <tcg/tcg_pts_attr_aik.h> -#include <tcg/tcg_pts_attr_req_funct_comp_evid.h> -#include <tcg/tcg_pts_attr_gen_attest_evid.h> -#include <tcg/tcg_pts_attr_simple_comp_evid.h> -#include <tcg/tcg_pts_attr_simple_evid_final.h> -#include <tcg/tcg_pts_attr_req_file_meas.h> -#include <tcg/tcg_pts_attr_file_meas.h> - -#include <tncif_pa_subtypes.h> - -#include <pen/pen.h> -#include <debug.h> -#include <utils/linked_list.h> - -/* IMC definitions */ - -static const char imc_name[] = "Attestation"; - -#define IMC_VENDOR_ID PEN_TCG -#define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS - -static imc_agent_t *imc_attestation; - -/** - * Supported PTS measurement algorithms - */ -static pts_meas_algorithms_t supported_algorithms = 0; - -/** - * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, - TNC_Version min_version, - TNC_Version max_version, - TNC_Version *actual_version) -{ - if (imc_attestation) - { - DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name); - return TNC_RESULT_ALREADY_INITIALIZED; - } - if (!pts_meas_probe_algorithms(&supported_algorithms)) - { - return TNC_RESULT_FATAL; - } - imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE, - imc_id, actual_version); - if (!imc_attestation) - { - 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; -} - -/** - * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, - TNC_ConnectionID connection_id, - TNC_ConnectionState new_state) -{ - imc_state_t *state; - /* TODO: Not used so far */ - //imc_attestation_state_t *attestation_state; - - if (!imc_attestation) - { - 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_attestation_state_create(connection_id); - return imc_attestation->create_state(imc_attestation, state); - case TNC_CONNECTION_STATE_DELETE: - return imc_attestation->delete_state(imc_attestation, connection_id); - case TNC_CONNECTION_STATE_HANDSHAKE: - case TNC_CONNECTION_STATE_ACCESS_ISOLATED: - case TNC_CONNECTION_STATE_ACCESS_NONE: - default: - return imc_attestation->change_state(imc_attestation, connection_id, - new_state, NULL); - } -} - - -/** - * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, - TNC_ConnectionID connection_id) -{ - imc_state_t *state; - imc_attestation_state_t *attestation_state; - pts_t *pts; - char *platform_info; - TNC_Result result = TNC_RESULT_SUCCESS; - - if (!imc_attestation) - { - DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); - return TNC_RESULT_NOT_INITIALIZED; - } - - /* get current IMC state */ - if (!imc_attestation->get_state(imc_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - attestation_state = (imc_attestation_state_t*)state; - pts = attestation_state->get_pts(attestation_state); - - platform_info = pts->get_platform_info(pts); - if (platform_info) - { - pa_tnc_msg_t *pa_tnc_msg; - pa_tnc_attr_t *attr; - - pa_tnc_msg = pa_tnc_msg_create(); - attr = ietf_attr_product_info_create(0, 0, platform_info); - pa_tnc_msg->add_attribute(pa_tnc_msg, attr); - pa_tnc_msg->build(pa_tnc_msg); - result = imc_attestation->send_message(imc_attestation, connection_id, - pa_tnc_msg->get_encoding(pa_tnc_msg)); - pa_tnc_msg->destroy(pa_tnc_msg); - } - - return result; -} - -/** - * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, - TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) -{ - pa_tnc_msg_t *pa_tnc_msg; - pa_tnc_attr_t *attr; - linked_list_t *attr_list; - imc_state_t *state; - imc_attestation_state_t *attestation_state; - enumerator_t *enumerator; - pts_t *pts; - TNC_Result result; - bool fatal_error = FALSE; - - if (!imc_attestation) - { - DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); - return TNC_RESULT_NOT_INITIALIZED; - } - - /* get current IMC state */ - if (!imc_attestation->get_state(imc_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - attestation_state = (imc_attestation_state_t*)state; - pts = attestation_state->get_pts(attestation_state); - - /* parse received PA-TNC message and automatically handle any errors */ - result = imc_attestation->receive_message(imc_attestation, connection_id, - chunk_create(msg, msg_len), msg_type, - &pa_tnc_msg); - - /* no parsed PA-TNC attributes available if an error occurred */ - if (!pa_tnc_msg) - { - return result; - } - - attr_list = linked_list_create(); - - /* analyze PA-TNC attributes */ - enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); - while (enumerator->enumerate(enumerator, &attr)) - { - if (attr->get_vendor_id(attr) == PEN_IETF && - attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) - { - ietf_attr_pa_tnc_error_t *error_attr; - pa_tnc_error_code_t error_code; - chunk_t msg_info, attr_info; - u_int32_t offset; - - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_code = error_attr->get_error_code(error_attr); - msg_info = error_attr->get_msg_info(error_attr); - - DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B", - pa_tnc_error_code_names, error_code, &msg_info); - switch (error_code) - { - case PA_ERROR_INVALID_PARAMETER: - offset = error_attr->get_offset(error_attr); - DBG1(DBG_IMC, " occurred at offset of %u bytes", offset); - break; - case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED: - attr_info = error_attr->get_attr_info(error_attr); - DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info); - break; - default: - break; - } - fatal_error = TRUE; - } - else if (attr->get_vendor_id(attr) == PEN_TCG) - { - switch (attr->get_type(attr)) - { - case TCG_PTS_REQ_PROTO_CAPS: - { - tcg_pts_attr_proto_caps_t *attr_cast; - pts_proto_caps_flag_t imc_flags, imv_flags; - - attr_cast = (tcg_pts_attr_proto_caps_t*)attr; - imv_flags = attr_cast->get_flags(attr_cast); - imc_flags = pts->get_proto_caps(pts); - pts->set_proto_caps(pts, imc_flags & imv_flags); - - /* Send PTS Protocol Capabilities attribute */ - attr = tcg_pts_attr_proto_caps_create(imc_flags & imv_flags, - FALSE); - attr_list->insert_last(attr_list, attr); - break; - } - case TCG_PTS_MEAS_ALGO: - { - tcg_pts_attr_meas_algo_t *attr_cast; - pts_meas_algorithms_t selected_algorithm; - - attr_cast = (tcg_pts_attr_meas_algo_t*)attr; - selected_algorithm = attr_cast->get_algorithms(attr_cast); - - if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) && - (selected_algorithm & PTS_MEAS_ALGO_SHA384)) - { - pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA384); - } - else if ((supported_algorithms & PTS_MEAS_ALGO_SHA256) && - (selected_algorithm & PTS_MEAS_ALGO_SHA256)) - { - pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA256); - } - - else if ((supported_algorithms & PTS_MEAS_ALGO_SHA1) && - (selected_algorithm & PTS_MEAS_ALGO_SHA1)) - { - pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA1); - } - else - { - attr = pts_hash_alg_error_create(supported_algorithms); - attr_list->insert_last(attr_list, attr); - break; - } - - /* Send Measurement Algorithm Selection attribute */ - selected_algorithm = pts->get_meas_algorithm(pts); - attr = tcg_pts_attr_meas_algo_create(selected_algorithm, - TRUE); - attr_list->insert_last(attr_list, attr); - break; - } - - case TCG_PTS_GET_TPM_VERSION_INFO: - { - chunk_t tpm_version_info, attr_info; - - if (!pts->get_tpm_version_info(pts, &tpm_version_info)) - { - attr_info = attr->get_value(attr); - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info); - attr_list->insert_last(attr_list, attr); - break; - } - - /* Send TPM Version Info attribute */ - attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info); - attr_list->insert_last(attr_list, attr); - break; - } - - case TCG_PTS_GET_AIK: - { - certificate_t *aik; - - aik = pts->get_aik(pts); - if (!aik) - { - DBG1(DBG_IMC, "no AIK certificate or public key available"); - break; - } - - /* Send AIK attribute */ - attr = tcg_pts_attr_aik_create(aik); - attr_list->insert_last(attr_list, attr); - break; - } - - /* PTS-based Attestation Evidence */ - case TCG_PTS_REQ_FUNCT_COMP_EVID: - break; - case TCG_PTS_GEN_ATTEST_EVID: - break; - case TCG_PTS_REQ_FILE_MEAS: - { - tcg_pts_attr_req_file_meas_t *attr_cast; - char *pathname; - u_int16_t request_id; - bool is_directory; - u_int32_t delimiter; - pts_file_meas_t *measurements; - pts_error_code_t pts_error; - chunk_t attr_info; - - attr_info = attr->get_value(attr); - attr_cast = (tcg_pts_attr_req_file_meas_t*)attr; - is_directory = attr_cast->get_directory_flag(attr_cast); - request_id = attr_cast->get_request_id(attr_cast); - delimiter = attr_cast->get_delimiter(attr_cast); - pathname = attr_cast->get_pathname(attr_cast); - - if (pts->is_path_valid(pts, pathname, &pts_error) && pts_error) - { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - pts_error, attr_info); - attr_list->insert_last(attr_list, attr); - break; - } - else if (!pts->is_path_valid(pts, pathname, &pts_error)) - { - break; - } - - if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF) - { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_INVALID_DELIMITER, attr_info); - attr_list->insert_last(attr_list, attr); - break; - } - - /* Do PTS File Measurements and send them to PTS-IMV */ - DBG2(DBG_IMC, "measurement request %d for %s '%s'", - request_id, is_directory ? "directory" : "file", - pathname); - measurements = pts->do_measurements(pts, request_id, - pathname, is_directory); - if (!measurements) - { - /* TODO handle error codes from measurements */ - return TNC_RESULT_FATAL; - } - attr = tcg_pts_attr_file_meas_create(measurements); - attr->set_noskip_flag(attr, TRUE); - attr_list->insert_last(attr_list, attr); - break; - } - /* TODO: Not implemented yet */ - case TCG_PTS_DH_NONCE_PARAMS_REQ: - case TCG_PTS_DH_NONCE_FINISH: - case TCG_PTS_REQ_FILE_META: - case TCG_PTS_REQ_INTEG_MEAS_LOG: - /* Attributes using XML */ - case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META: - case TCG_PTS_UPDATE_TEMPL_REF_MANI: - /* On Windows only*/ - case TCG_PTS_REQ_REGISTRY_VALUE: - /* Received on IMV side only*/ - case TCG_PTS_PROTO_CAPS: - case TCG_PTS_DH_NONCE_PARAMS_RESP: - case TCG_PTS_MEAS_ALGO_SELECTION: - case TCG_PTS_TPM_VERSION_INFO: - case TCG_PTS_TEMPL_REF_MANI_SET_META: - case TCG_PTS_AIK: - case TCG_PTS_SIMPLE_COMP_EVID: - case TCG_PTS_SIMPLE_EVID_FINAL: - case TCG_PTS_VERIFICATION_RESULT: - case TCG_PTS_INTEG_REPORT: - case TCG_PTS_UNIX_FILE_META: - case TCG_PTS_FILE_MEAS: - case TCG_PTS_INTEG_MEAS_LOG: - default: - DBG1(DBG_IMC, "received unsupported attribute '%N'", - tcg_attr_names, attr->get_type(attr)); - break; - } - } - } - enumerator->destroy(enumerator); - pa_tnc_msg->destroy(pa_tnc_msg); - - result = TNC_RESULT_SUCCESS; - - if (attr_list->get_count(attr_list)) - { - pa_tnc_msg = pa_tnc_msg_create(); - - enumerator = attr_list->create_enumerator(attr_list); - while (enumerator->enumerate(enumerator, &attr)) - { - pa_tnc_msg->add_attribute(pa_tnc_msg, attr); - } - enumerator->destroy(enumerator); - - pa_tnc_msg->build(pa_tnc_msg); - result = imc_attestation->send_message(imc_attestation, connection_id, - pa_tnc_msg->get_encoding(pa_tnc_msg)); - pa_tnc_msg->destroy(pa_tnc_msg); - } - attr_list->destroy(attr_list); - - return result; -} - -/** - * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, - TNC_ConnectionID connection_id) -{ - if (!imc_attestation) - { - DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return TNC_RESULT_SUCCESS; -} - -/** - * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) -{ - if (!imc_attestation) - { - DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); - return TNC_RESULT_NOT_INITIALIZED; - } - - libpts_deinit(); - - imc_attestation->destroy(imc_attestation); - imc_attestation = NULL; - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, - TNC_TNCC_BindFunctionPointer bind_function) -{ - if (!imc_attestation) - { - DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imc_attestation->bind_functions(imc_attestation, bind_function); -} diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner.c b/src/libimcv/plugins/imc_scanner/imc_scanner.c index ecf758ba0..b24c39c3a 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner.c @@ -39,7 +39,7 @@ static const char imc_name[] = "Scanner"; static imc_agent_t *imc_scanner; /** - * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, TNC_Version min_version, @@ -66,7 +66,7 @@ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, } /** - * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, TNC_ConnectionID connection_id, @@ -237,15 +237,15 @@ static TNC_Result send_message(TNC_ConnectionID connection_id) msg = pa_tnc_msg_create(); msg->add_attribute(msg, attr); msg->build(msg); - result = imc_scanner->send_message(imc_scanner, connection_id, - msg->get_encoding(msg)); + result = imc_scanner->send_message(imc_scanner, connection_id, FALSE, 0, + TNC_IMVID_ANY, msg->get_encoding(msg)); msg->destroy(msg); return result; } /** - * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, TNC_ConnectionID connection_id) @@ -258,20 +258,19 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, return send_message(connection_id); } -/** - * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, +static TNC_Result receive_message(TNC_IMCID imc_id, TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) + TNC_UInt32 msg_flags, + chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, + TNC_UInt32 dst_imc_id) { pa_tnc_msg_t *pa_tnc_msg; - pa_tnc_attr_t *attr; - enumerator_t *enumerator; + imc_state_t *state; TNC_Result result; - bool fatal_error = FALSE; + bool fatal_error; if (!imc_scanner) { @@ -279,10 +278,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, return TNC_RESULT_NOT_INITIALIZED; } + /* get current IMC state */ + if (!imc_scanner->get_state(imc_scanner, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + /* parse received PA-TNC message and automatically handle any errors */ - result = imc_scanner->receive_message(imc_scanner, connection_id, - chunk_create(msg, msg_len), msg_type, - &pa_tnc_msg); + result = imc_scanner->receive_message(imc_scanner, state, msg, msg_vid, + msg_subtype, src_imv_id, dst_imc_id, &pa_tnc_msg); /* no parsed PA-TNC attributes available if an error occurred */ if (!pa_tnc_msg) @@ -290,43 +294,8 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, return result; } - /* analyze PA-TNC attributes */ - enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); - while (enumerator->enumerate(enumerator, &attr)) - { - ietf_attr_pa_tnc_error_t *error_attr; - pa_tnc_error_code_t error_code; - chunk_t msg_info, attr_info; - u_int32_t offset; - - if (attr->get_vendor_id(attr) != PEN_IETF && - attr->get_type(attr) != IETF_ATTR_PA_TNC_ERROR) - { - continue; - } - - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_code = error_attr->get_error_code(error_attr); - msg_info = error_attr->get_msg_info(error_attr); - DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B", - pa_tnc_error_code_names, error_code, &msg_info); - - switch (error_code) - { - case PA_ERROR_INVALID_PARAMETER: - offset = error_attr->get_offset(error_attr); - DBG1(DBG_IMC, " occurred at offset of %u bytes", offset); - break; - case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED: - attr_info = error_attr->get_attr_info(error_attr); - DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info); - break; - default: - break; - } - fatal_error = TRUE; - } - enumerator->destroy(enumerator); + /* preprocess any IETF standard error attributes */ + fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg); pa_tnc_msg->destroy(pa_tnc_msg); /* if no error occurred then always return the same response */ @@ -334,7 +303,44 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, } /** - * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + + msg_vid = msg_type >> 8; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + + return receive_message(imc_id, connection_id, 0, chunk_create(msg, msg_len), + msg_vid, msg_subtype, 0, TNC_IMCID_ANY); +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +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) +{ + return receive_message(imc_id, connection_id, msg_flags, + chunk_create(msg, msg_len), msg_vid, msg_subtype, + src_imv_id, dst_imc_id); +} + +/** + * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, TNC_ConnectionID connection_id) @@ -348,7 +354,7 @@ TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, } /** - * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) { @@ -364,7 +370,7 @@ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) } /** - * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2 + * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, TNC_TNCC_BindFunctionPointer bind_function) diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c index dce7bca13..563105548 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c @@ -37,6 +37,17 @@ struct private_imc_scanner_state_t { * TNCCS connection state */ TNC_ConnectionState state; + + /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + }; METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, @@ -45,6 +56,25 @@ METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, return this->connection_id; } +METHOD(imc_state_t, has_long, bool, + private_imc_scanner_state_t *this) +{ + return this->has_long; +} + +METHOD(imc_state_t, has_excl, bool, + private_imc_scanner_state_t *this) +{ + return this->has_excl; +} + +METHOD(imc_state_t, set_flags, void, + private_imc_scanner_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + METHOD(imc_state_t, change_state, void, private_imc_scanner_state_t *this, TNC_ConnectionState new_state) { @@ -68,6 +98,9 @@ imc_state_t *imc_scanner_state_create(TNC_ConnectionID connection_id) .public = { .interface = { .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, .change_state = _change_state, .destroy = _destroy, }, diff --git a/src/libimcv/plugins/imc_test/imc_test.c b/src/libimcv/plugins/imc_test/imc_test.c index 01e70e8af..fe005ed4a 100644 --- a/src/libimcv/plugins/imc_test/imc_test.c +++ b/src/libimcv/plugins/imc_test/imc_test.c @@ -37,7 +37,7 @@ static const char imc_name[] = "Test"; static imc_agent_t *imc_test; /** - * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, TNC_Version min_version, @@ -64,7 +64,7 @@ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, } /** - * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, TNC_ConnectionID connection_id, @@ -75,21 +75,36 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, TNC_Result result; char *command; bool retry; + int additional_ids; if (!imc_test) { DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); return TNC_RESULT_NOT_INITIALIZED; } + switch (new_state) { case TNC_CONNECTION_STATE_CREATE: command = lib->settings->get_str(lib->settings, - "libimcv.plugins.imc-test.command", "none"); + "libimcv.plugins.imc-test.command", "none"); retry = lib->settings->get_bool(lib->settings, "libimcv.plugins.imc-test.retry", FALSE); state = imc_test_state_create(connection_id, command, retry); - return imc_test->create_state(imc_test, state); + + result = imc_test->create_state(imc_test, state); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + + /* Optionally reserve additional IMC IDs */ + additional_ids = lib->settings->get_int(lib->settings, + "libimcv.plugins.imc-test.additional_ids", 0); + imc_test->reserve_additional_ids(imc_test, additional_ids - + imc_test->count_additional_ids(imc_test)); + + return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_HANDSHAKE: /* get updated IMC state */ @@ -139,56 +154,98 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, } } -static TNC_Result send_message(TNC_ConnectionID connection_id) +static TNC_Result send_message(imc_state_t *state, TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id) { + imc_test_state_t *test_state; pa_tnc_msg_t *msg; pa_tnc_attr_t *attr; - imc_state_t *state; - imc_test_state_t *test_state; + bool excl; + TNC_ConnectionID connection_id; TNC_Result result; - if (!imc_test->get_state(imc_test, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } + connection_id = state->get_connection_id(state); test_state = (imc_test_state_t*)state; attr = ita_attr_command_create(test_state->get_command(test_state)); attr->set_noskip_flag(attr, TRUE); msg = pa_tnc_msg_create(); msg->add_attribute(msg, attr); msg->build(msg); - result = imc_test->send_message(imc_test, connection_id, - msg->get_encoding(msg)); + excl = dst_imv_id != TNC_IMVID_ANY; + result = imc_test->send_message(imc_test, connection_id, excl, src_imc_id, + dst_imv_id, msg->get_encoding(msg)); msg->destroy(msg); return result; } /** - * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, TNC_ConnectionID connection_id) { + imc_state_t *state; + enumerator_t *enumerator; + void *pointer; + TNC_UInt32 additional_id; + TNC_Result result; + if (!imc_test) { DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); return TNC_RESULT_NOT_INITIALIZED; } - return send_message(connection_id); + + /* get current IMC state */ + if (!imc_test->get_state(imc_test, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + + /* send PA message for primary IMC ID */ + result = send_message(state, imc_id, TNC_IMVID_ANY); + + /* Exit if there are no additional IMC IDs */ + if (!imc_test->count_additional_ids(imc_test)) + { + return result; + } + + /* Do we have support for transporting multiple IMC IDs? */ + if (!state->has_long(state)) + { + DBG1(DBG_IMC, "IMC %u \"%s\" did not detect support for transporting " + "multiple IMC IDs", imc_id, imc_name); + return result; + } + + /* send PA messages for additional IMC IDs */ + enumerator = imc_test->create_id_enumerator(imc_test); + while (result == TNC_RESULT_SUCCESS && + enumerator->enumerate(enumerator, &pointer)) + { + /* interpret pointer as scalar value */ + additional_id = (TNC_UInt32)pointer; + result = send_message(state, additional_id, TNC_IMVID_ANY); + } + enumerator->destroy(enumerator); + + return result; } -/** - * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2 - */ -TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, +static TNC_Result receive_message(TNC_IMCID imc_id, TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) + TNC_UInt32 msg_flags, + chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, + TNC_UInt32 dst_imc_id) { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; + imc_state_t *state; enumerator_t *enumerator; TNC_Result result; bool fatal_error = FALSE; @@ -199,10 +256,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, return TNC_RESULT_NOT_INITIALIZED; } + /* get current IMC state */ + if (!imc_test->get_state(imc_test, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + /* parse received PA-TNC message and automatically handle any errors */ - result = imc_test->receive_message(imc_test, connection_id, - chunk_create(msg, msg_len), msg_type, - &pa_tnc_msg); + result = imc_test->receive_message(imc_test, state, msg, msg_vid, + msg_subtype, src_imv_id, dst_imc_id, &pa_tnc_msg); /* no parsed PA-TNC attributes available if an error occurred */ if (!pa_tnc_msg) @@ -210,41 +272,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, return result; } + /* preprocess any IETF standard error attributes */ + fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg); + /* analyze PA-TNC attributes */ enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_IETF && - attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) - { - ietf_attr_pa_tnc_error_t *error_attr; - pa_tnc_error_code_t error_code; - chunk_t msg_info, attr_info; - u_int32_t offset; - - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_code = error_attr->get_error_code(error_attr); - msg_info = error_attr->get_msg_info(error_attr); - - DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B", - pa_tnc_error_code_names, error_code, &msg_info); - switch (error_code) - { - case PA_ERROR_INVALID_PARAMETER: - offset = error_attr->get_offset(error_attr); - DBG1(DBG_IMC, " occurred at offset of %u bytes", offset); - break; - case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED: - attr_info = error_attr->get_attr_info(error_attr); - DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info); - break; - default: - break; - } - fatal_error = TRUE; - } - else if (attr->get_vendor_id(attr) == PEN_ITA && - attr->get_type(attr) == ITA_ATTR_COMMAND) + if (attr->get_vendor_id(attr) == PEN_ITA && + attr->get_type(attr) == ITA_ATTR_COMMAND) { ita_attr_command_t *ita_attr; char *command; @@ -257,11 +293,49 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, pa_tnc_msg->destroy(pa_tnc_msg); /* if no error occurred then always return the same response */ - return fatal_error ? TNC_RESULT_FATAL : send_message(connection_id); + return fatal_error ? TNC_RESULT_FATAL : + send_message(state, dst_imc_id, src_imv_id); +} + +/** + * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + + msg_vid = msg_type >> 8; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + + return receive_message(imc_id, connection_id, 0, chunk_create(msg, msg_len), + msg_vid, msg_subtype, 0, TNC_IMCID_ANY); +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +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) +{ + return receive_message(imc_id, connection_id, msg_flags, + chunk_create(msg, msg_len), msg_vid, msg_subtype, + src_imv_id, dst_imc_id); } /** - * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, TNC_ConnectionID connection_id) @@ -275,7 +349,7 @@ TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, } /** - * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2 + * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) { @@ -291,7 +365,7 @@ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) } /** - * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2 + * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3 */ TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, TNC_TNCC_BindFunctionPointer bind_function) diff --git a/src/libimcv/plugins/imc_test/imc_test_state.c b/src/libimcv/plugins/imc_test/imc_test_state.c index cc7e18a4d..2adfd7d64 100644 --- a/src/libimcv/plugins/imc_test/imc_test_state.c +++ b/src/libimcv/plugins/imc_test/imc_test_state.c @@ -15,6 +15,7 @@ #include "imc_test_state.h" #include <debug.h> +#include <utils/linked_list.h> typedef struct private_imc_test_state_t private_imc_test_state_t; @@ -39,6 +40,16 @@ struct private_imc_test_state_t { TNC_ConnectionState state; /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** * Command to transmit to IMV */ char *command; @@ -52,6 +63,7 @@ struct private_imc_test_state_t { * Do a handshake retry */ bool handshake_retry; + }; METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, @@ -60,6 +72,25 @@ METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, return this->connection_id; } +METHOD(imc_state_t, has_long, bool, + private_imc_test_state_t *this) +{ + return this->has_long; +} + +METHOD(imc_state_t, has_excl, bool, + private_imc_test_state_t *this) +{ + return this->has_excl; +} + +METHOD(imc_state_t, set_flags, void, + private_imc_test_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + METHOD(imc_state_t, change_state, void, private_imc_test_state_t *this, TNC_ConnectionState new_state) { @@ -123,6 +154,9 @@ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id, .public = { .interface = { .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, .change_state = _change_state, .destroy = _destroy, }, diff --git a/src/libimcv/plugins/imc_test/imc_test_state.h b/src/libimcv/plugins/imc_test/imc_test_state.h index 384285af8..d9160df94 100644 --- a/src/libimcv/plugins/imc_test/imc_test_state.h +++ b/src/libimcv/plugins/imc_test/imc_test_state.h @@ -21,6 +21,7 @@ #ifndef IMC_TEST_STATE_H_ #define IMC_TEST_STATE_H_ +#include <tncifimc.h> #include <imc/imc_state.h> #include <library.h> @@ -63,6 +64,7 @@ struct imc_test_state_t { * @return TRUE if a handshake retry should be done */ bool (*do_handshake_retry)(imc_test_state_t *this); + }; /** diff --git a/src/libimcv/plugins/imv_attestation/Makefile.am b/src/libimcv/plugins/imv_attestation/Makefile.am deleted file mode 100644 index bfff6e877..000000000 --- a/src/libimcv/plugins/imv_attestation/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libtncif \ - -I$(top_srcdir)/src/libimcv -I$(top_srcdir)/src/libpts - -AM_CFLAGS = -rdynamic - -imcv_LTLIBRARIES = imv-attestation.la - -imv_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \ - $(top_builddir)/src/libstrongswan/libstrongswan.la \ - $(top_builddir)/src/libpts/libpts.la - -imv_attestation_la_SOURCES = imv_attestation.c \ - imv_attestation_state.h imv_attestation_state.c - -imv_attestation_la_LDFLAGS = -module -avoid-version - diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation.c b/src/libimcv/plugins/imv_attestation/imv_attestation.c deleted file mode 100644 index 86de5a9cf..000000000 --- a/src/libimcv/plugins/imv_attestation/imv_attestation.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Copyright (C) 2011 Sansar Choinyambuu - * HSR 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 "imv_attestation_state.h" - -#include <imv/imv_agent.h> -#include <pa_tnc/pa_tnc_msg.h> -#include <ietf/ietf_attr.h> -#include <ietf/ietf_attr_pa_tnc_error.h> -#include <ietf/ietf_attr_product_info.h> - -#include <libpts.h> - -#include <pts/pts_database.h> -#include <pts/pts_creds.h> -#include <pts/pts_error.h> - -#include <tcg/tcg_attr.h> -#include <tcg/tcg_pts_attr_proto_caps.h> -#include <tcg/tcg_pts_attr_meas_algo.h> -#include <tcg/tcg_pts_attr_get_tpm_version_info.h> -#include <tcg/tcg_pts_attr_tpm_version_info.h> -#include <tcg/tcg_pts_attr_get_aik.h> -#include <tcg/tcg_pts_attr_aik.h> -#include <tcg/tcg_pts_attr_req_funct_comp_evid.h> -#include <tcg/tcg_pts_attr_gen_attest_evid.h> -#include <tcg/tcg_pts_attr_simple_comp_evid.h> -#include <tcg/tcg_pts_attr_simple_evid_final.h> -#include <tcg/tcg_pts_attr_req_file_meas.h> -#include <tcg/tcg_pts_attr_file_meas.h> - -#include <tncif_pa_subtypes.h> - -#include <pen/pen.h> -#include <debug.h> -#include <credentials/credential_manager.h> - -/* IMV definitions */ - -static const char imv_name[] = "Attestation"; - -#define IMV_VENDOR_ID PEN_TCG -#define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS - -static imv_agent_t *imv_attestation; - -/** - * Supported PTS measurement algorithms - */ -static pts_meas_algorithms_t supported_algorithms = 0; - -/** - * PTS file measurement database - */ -static pts_database_t *pts_db; - -/** - * PTS credentials - */ -static pts_creds_t *pts_creds; - -/** - * PTS credential manager - */ -static credential_manager_t *pts_credmgr; - -/** - * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, - TNC_Version min_version, - TNC_Version max_version, - TNC_Version *actual_version) -{ - char *hash_alg, *uri, *cadir; - - if (imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); - return TNC_RESULT_ALREADY_INITIALIZED; - } - if (!pts_meas_probe_algorithms(&supported_algorithms)) - { - return TNC_RESULT_FATAL; - } - imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE, - imv_id, actual_version); - if (!imv_attestation) - { - return TNC_RESULT_FATAL; - } - - libpts_init(); - - if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1) - { - DBG1(DBG_IMV, "no common IF-IMV version"); - return TNC_RESULT_NO_COMMON_VERSION; - } - - /** - * Specify supported PTS measurement algorithms - * - * sha1 : PTS_MEAS_ALGO_SHA1 - * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 - * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384 - * - * we expect the PTS-IMC to select the strongest supported algorithm - */ - hash_alg = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-attestation.hash_algorithm", "sha256"); - if (!strcaseeq(hash_alg, "sha384") && !strcaseeq(hash_alg, "sha2_384")) - { - /* remove SHA384 algorithm */ - supported_algorithms &= ~PTS_MEAS_ALGO_SHA384; - } - if (strcaseeq(hash_alg, "sha1")) - { - /* remove SHA256 algorithm */ - supported_algorithms &= ~PTS_MEAS_ALGO_SHA256; - } - - /* create a PTS credential manager */ - pts_credmgr = credential_manager_create(); - - /* create PTS credential set */ - cadir = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-attestation.cadir", NULL); - pts_creds = pts_creds_create(cadir); - if (pts_creds) - { - pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds)); - } - - /* attach file measurement database */ - uri = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-attestation.database", NULL); - pts_db = pts_database_create(uri); - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_ConnectionState new_state) -{ - imv_state_t *state; - imv_attestation_state_t *attestation_state; - TNC_Result result; - - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - switch (new_state) - { - case TNC_CONNECTION_STATE_CREATE: - state = imv_attestation_state_create(connection_id); - return imv_attestation->create_state(imv_attestation, state); - case TNC_CONNECTION_STATE_DELETE: - return imv_attestation->delete_state(imv_attestation, connection_id); - case TNC_CONNECTION_STATE_HANDSHAKE: - result = imv_attestation->change_state(imv_attestation, connection_id, - new_state, &state); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - attestation_state = (imv_attestation_state_t*)state; - - /* TODO: Get some configurations */ - - return TNC_RESULT_SUCCESS; - default: - return imv_attestation->change_state(imv_attestation, connection_id, - new_state, NULL); - } -} - -static TNC_Result send_message(TNC_ConnectionID connection_id) -{ - pa_tnc_msg_t *msg; - pa_tnc_attr_t *attr; - pts_t *pts; - imv_state_t *state; - imv_attestation_state_t *attestation_state; - imv_attestation_handshake_state_t handshake_state; - TNC_Result result; - - if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - attestation_state = (imv_attestation_state_t*)state; - handshake_state = attestation_state->get_handshake_state(attestation_state); - pts = attestation_state->get_pts(attestation_state); - - msg = pa_tnc_msg_create(); - - - /* Switch on the attribute type IMV has received */ - switch (handshake_state) - { - case IMV_ATTESTATION_STATE_INIT: - { - pts_proto_caps_flag_t flags; - - /* Send Request Protocol Capabilities attribute */ - flags = pts->get_proto_caps(pts); - attr = tcg_pts_attr_proto_caps_create(flags, TRUE); - attr->set_noskip_flag(attr, TRUE); - msg->add_attribute(msg, attr); - - /* Send Measurement Algorithms attribute */ - attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE); - attr->set_noskip_flag(attr, TRUE); - msg->add_attribute(msg, attr); - - attestation_state->set_handshake_state(attestation_state, - IMV_ATTESTATION_STATE_MEAS); - break; - } - - case IMV_ATTESTATION_STATE_MEAS: - { - enumerator_t *enumerator; - u_int32_t delimiter = SOLIDUS_UTF; - char *platform_info, *pathname; - u_int16_t request_id; - int id, type; - bool is_dir; - - attestation_state->set_handshake_state(attestation_state, - IMV_ATTESTATION_STATE_END); - - /* Does the PTS-IMC have TPM support? */ - if (pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T) - { - /* Send Get TPM Version attribute */ - attr = tcg_pts_attr_get_tpm_version_info_create(); - attr->set_noskip_flag(attr, TRUE); - msg->add_attribute(msg, attr); - - /* Send Get AIK attribute */ - attr = tcg_pts_attr_get_aik_create(); - attr->set_noskip_flag(attr, TRUE); - msg->add_attribute(msg, attr); - } - - /* Get Platform and OS of the PTS-IMC */ - platform_info = pts->get_platform_info(pts); - - if (!pts_db || !platform_info) - { - DBG1(DBG_IMV, "%s%s%s not available", - (pts_db) ? "" : "pts database", - (!pts_db && !platform_info) ? "and" : "", - (platform_info) ? "" : "platform info"); - break; - } - DBG1(DBG_IMV, "platform is '%s'", platform_info); - - /* Send Request File Measurement attribute */ - enumerator = pts_db->create_file_enumerator(pts_db, platform_info); - if (!enumerator) - { - break; - } - while (enumerator->enumerate(enumerator, &id, &type, &pathname)) - { - is_dir = (type != 0); - request_id = attestation_state->add_request(attestation_state, - id, is_dir); - DBG2(DBG_IMV, "measurement request %d for %s '%s'", - request_id, is_dir ? "directory" : "file", pathname); - attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id, - delimiter, pathname); - attr->set_noskip_flag(attr, TRUE); - msg->add_attribute(msg, attr); - } - enumerator->destroy(enumerator); - break; - } - case IMV_ATTESTATION_STATE_COMP_EVID: - case IMV_ATTESTATION_STATE_IML: - DBG1(DBG_IMV, "Attestation IMV has nothing to send: \"%s\"", - handshake_state); - return TNC_RESULT_FATAL; - default: - DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"", - handshake_state); - return TNC_RESULT_FATAL; - } - - msg->build(msg); - result = imv_attestation->send_message(imv_attestation, connection_id, - msg->get_encoding(msg)); - msg->destroy(msg); - - return result; -} - -/** - * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) -{ - pa_tnc_msg_t *pa_tnc_msg; - pa_tnc_attr_t *attr; - imv_state_t *state; - imv_attestation_state_t *attestation_state; - pts_t *pts; - enumerator_t *enumerator; - TNC_Result result; - bool fatal_error = FALSE; - bool measurement_error = FALSE; - - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - - /* get current IMV state */ - if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - attestation_state = (imv_attestation_state_t*)state; - pts = attestation_state->get_pts(attestation_state); - - /* parse received PA-TNC message and automatically handle any errors */ - result = imv_attestation->receive_message(imv_attestation, connection_id, - chunk_create(msg, msg_len), msg_type, - &pa_tnc_msg); - - /* no parsed PA-TNC attributes available if an error occurred */ - if (!pa_tnc_msg) - { - return result; - } - - /* analyze PA-TNC attributes */ - enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); - while (enumerator->enumerate(enumerator, &attr)) - { - if (attr->get_vendor_id(attr) == PEN_IETF) - { - if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) - { - ietf_attr_pa_tnc_error_t *error_attr; - pen_t error_vendor_id; - pa_tnc_error_code_t error_code; - chunk_t msg_info, attr_info; - u_int32_t offset; - - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_vendor_id = error_attr->get_vendor_id(error_attr); - error_code = error_attr->get_error_code(error_attr); - msg_info = error_attr->get_msg_info(error_attr); - - if (error_vendor_id == PEN_IETF) - { - DBG1(DBG_IMV, "received PA-TNC error '%N' " - "concerning message %#B", - pa_tnc_error_code_names, error_code, &msg_info); - - switch (error_code) - { - case PA_ERROR_INVALID_PARAMETER: - offset = error_attr->get_offset(error_attr); - DBG1(DBG_IMV, " occurred at offset of %u bytes", - offset); - break; - case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED: - attr_info = error_attr->get_attr_info(error_attr); - DBG1(DBG_IMV, " unsupported attribute %#B", - &attr_info); - break; - default: - break; - } - } - else if (error_vendor_id == PEN_TCG) - { - DBG1(DBG_IMV, "received TCG-PTS error '%N'", - pts_error_code_names, error_code); - DBG1(DBG_IMV, "error information: %B", &msg_info); - } - fatal_error = TRUE; - } - else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION) - { - ietf_attr_product_info_t *attr_cast; - char *platform_info; - - attr_cast = (ietf_attr_product_info_t*)attr; - platform_info = attr_cast->get_info(attr_cast, NULL, NULL); - pts->set_platform_info(pts, platform_info); - } - } - else if (attr->get_vendor_id(attr) == PEN_TCG) - { - switch (attr->get_type(attr)) - { - case TCG_PTS_PROTO_CAPS: - { - tcg_pts_attr_proto_caps_t *attr_cast; - pts_proto_caps_flag_t flags; - - attr_cast = (tcg_pts_attr_proto_caps_t*)attr; - flags = attr_cast->get_flags(attr_cast); - pts->set_proto_caps(pts, flags); - break; - } - case TCG_PTS_MEAS_ALGO_SELECTION: - { - tcg_pts_attr_meas_algo_t *attr_cast; - pts_meas_algorithms_t selected_algorithm; - - attr_cast = (tcg_pts_attr_meas_algo_t*)attr; - selected_algorithm = attr_cast->get_algorithms(attr_cast); - pts->set_meas_algorithm(pts, selected_algorithm); - break; - } - case TCG_PTS_TPM_VERSION_INFO: - { - tcg_pts_attr_tpm_version_info_t *attr_cast; - chunk_t tpm_version_info; - - attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr; - tpm_version_info = attr_cast->get_tpm_version_info(attr_cast); - pts->set_tpm_version_info(pts, tpm_version_info); - break; - } - case TCG_PTS_AIK: - { - tcg_pts_attr_aik_t *attr_cast; - certificate_t *aik, *issuer; - enumerator_t *e; - bool trusted = FALSE; - - attr_cast = (tcg_pts_attr_aik_t*)attr; - aik = attr_cast->get_aik(attr_cast); - if (!aik) - { - /* TODO generate error attribute */ - break; - } - if (aik->get_type(aik) == CERT_X509) - { - DBG1(DBG_IMV, "verifying AIK certificate"); - e = pts_credmgr->create_trusted_enumerator(pts_credmgr, - KEY_ANY, aik->get_issuer(aik), FALSE); - while (e->enumerate(e, &issuer)) - { - if (aik->issued_by(aik, issuer)) - { - trusted = TRUE; - break; - } - } - e->destroy(e); - DBG1(DBG_IMV, "AIK certificate is %strusted", - trusted ? "" : "not "); - } - pts->set_aik(pts, aik); - break; - } - - /* PTS-based Attestation Evidence */ - case TCG_PTS_SIMPLE_COMP_EVID: - break; - case TCG_PTS_SIMPLE_EVID_FINAL: - break; - case TCG_PTS_FILE_MEAS: - { - tcg_pts_attr_file_meas_t *attr_cast; - u_int16_t request_id; - int file_count, file_id; - pts_meas_algorithms_t algo; - pts_file_meas_t *measurements; - char *platform_info; - enumerator_t *e_hash; - bool is_dir; - - platform_info = pts->get_platform_info(pts); - if (!pts_db || !platform_info) - { - break; - } - - attr_cast = (tcg_pts_attr_file_meas_t*)attr; - measurements = attr_cast->get_measurements(attr_cast); - algo = pts->get_meas_algorithm(pts); - request_id = measurements->get_request_id(measurements); - file_count = measurements->get_file_count(measurements); - - DBG1(DBG_IMV, "measurement request %d returned %d file%s:", - request_id, file_count, (file_count == 1) ? "":"s"); - - if (!attestation_state->check_off_request(attestation_state, - request_id, &file_id, &is_dir)) - { - DBG1(DBG_IMV, " no entry found for this request"); - break; - } - - /* check hashes from database against measurements */ - e_hash = pts_db->create_hash_enumerator(pts_db, - platform_info, algo, file_id, is_dir); - if (!measurements->verify(measurements, e_hash, is_dir)) - { - measurement_error = TRUE; - } - e_hash->destroy(e_hash); - break; - } - - /* TODO: Not implemented yet */ - case TCG_PTS_DH_NONCE_PARAMS_RESP: - case TCG_PTS_UNIX_FILE_META: - case TCG_PTS_INTEG_MEAS_LOG: - /* Attributes using XML */ - case TCG_PTS_TEMPL_REF_MANI_SET_META: - case TCG_PTS_VERIFICATION_RESULT: - case TCG_PTS_INTEG_REPORT: - /* On Windows only*/ - case TCG_PTS_WIN_FILE_META: - case TCG_PTS_REGISTRY_VALUE: - /* Received on IMC side only*/ - case TCG_PTS_REQ_PROTO_CAPS: - case TCG_PTS_DH_NONCE_PARAMS_REQ: - case TCG_PTS_DH_NONCE_FINISH: - case TCG_PTS_MEAS_ALGO: - case TCG_PTS_GET_TPM_VERSION_INFO: - case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META: - case TCG_PTS_UPDATE_TEMPL_REF_MANI: - case TCG_PTS_GET_AIK: - case TCG_PTS_REQ_FUNCT_COMP_EVID: - case TCG_PTS_GEN_ATTEST_EVID: - case TCG_PTS_REQ_FILE_META: - case TCG_PTS_REQ_FILE_MEAS: - case TCG_PTS_REQ_INTEG_MEAS_LOG: - default: - DBG1(DBG_IMV, "received unsupported attribute '%N'", - tcg_attr_names, attr->get_type(attr)); - break; - } - } - } - enumerator->destroy(enumerator); - pa_tnc_msg->destroy(pa_tnc_msg); - - - if (fatal_error) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, - TNC_IMV_EVALUATION_RESULT_ERROR); - return imv_attestation->provide_recommendation(imv_attestation, - connection_id); - } - - if (attestation_state->get_handshake_state(attestation_state) & - IMV_ATTESTATION_STATE_END) - { - if (attestation_state->get_request_count(attestation_state)) - { - DBG1(DBG_IMV, "failure due to %d pending file measurements", - attestation_state->get_request_count(attestation_state)); - measurement_error = TRUE; - } - if (measurement_error) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, - TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); - } - else - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_ALLOW, - TNC_IMV_EVALUATION_RESULT_COMPLIANT); - } - return imv_attestation->provide_recommendation(imv_attestation, - connection_id); - } - - return send_message(connection_id); -} - -/** - * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_attestation->provide_recommendation(imv_attestation, connection_id); -} - -/** - * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - imv_state_t *state; - imv_attestation_state_t *attestation_state; - - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - /* get current IMV state */ - if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - attestation_state = (imv_attestation_state_t*)state; - - /* Check if IMV has to initiate the PA-TNC exchange */ - if (attestation_state->get_handshake_state(attestation_state) == - IMV_ATTESTATION_STATE_INIT) - { - return send_message(connection_id); - } - return TNC_RESULT_SUCCESS; -} - -/** - * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) -{ - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (pts_creds) - { - pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds)); - pts_creds->destroy(pts_creds); - } - DESTROY_IF(pts_db); - DESTROY_IF(pts_credmgr); - - libpts_deinit(); - - imv_attestation->destroy(imv_attestation); - imv_attestation = NULL; - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, - TNC_TNCS_BindFunctionPointer bind_function) -{ - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_attestation->bind_functions(imv_attestation, bind_function); -} diff --git a/src/libimcv/plugins/imv_attestation/tables.sql b/src/libimcv/plugins/imv_attestation/tables.sql deleted file mode 100644 index 8cc0e5588..000000000 --- a/src/libimcv/plugins/imv_attestation/tables.sql +++ /dev/null @@ -1,36 +0,0 @@ -/* PTS SQLite database */ - -DROP TABLE IF EXISTS files; -CREATE TABLE files ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - type INTEGER NOT NULL, - path TEXT NOT NULL -); - -DROP TABLE IF EXISTS products; -CREATE TABLE products ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL -); -DROP INDEX IF EXISTS products_name; -CREATE INDEX products_name ON products ( - name -); - -DROP TABLE IF EXISTS product_file; -CREATE TABLE product_file ( - product INTEGER NOT NULL, - file INTEGER NOT NULL, - PRIMARY KEY (product, file) -); - -DROP TABLE IF EXISTS file_hashes; -CREATE TABLE file_hashes ( - file INTEGER NOT NULL, - directory INTEGER DEFAULT 0, - product INTEGER NOT NULL, - algo INTEGER NOT NULL, - hash BLOB NOT NULL, - PRIMARY KEY(file, directory, product, algo) -); - diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner.c b/src/libimcv/plugins/imv_scanner/imv_scanner.c index 5561e6737..845511555 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner.c @@ -111,7 +111,7 @@ static linked_list_t* get_port_list(char *label) /* - * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, TNC_Version min_version, @@ -149,7 +149,7 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, } /** - * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, TNC_ConnectionID connection_id, @@ -175,21 +175,21 @@ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, } } -/** - * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, +static TNC_Result receive_message(TNC_IMVID imv_id, TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) + TNC_UInt32 msg_flags, + chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id) { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; imv_state_t *state; enumerator_t *enumerator; TNC_Result result; - bool fatal_error = FALSE; + bool fatal_error; if (!imv_scanner) { @@ -204,9 +204,8 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, } /* parse received PA-TNC message and automatically handle any errors */ - result = imv_scanner->receive_message(imv_scanner, connection_id, - chunk_create(msg, msg_len), msg_type, - &pa_tnc_msg); + result = imv_scanner->receive_message(imv_scanner, state, msg, msg_vid, + msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg); /* no parsed PA-TNC attributes available if an error occurred */ if (!pa_tnc_msg) @@ -214,44 +213,15 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, return result; } + /* preprocess any IETF standard error attributes */ + fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg); + /* analyze PA-TNC attributes */ enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) != PEN_IETF) - { - continue; - } - - if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) - { - ietf_attr_pa_tnc_error_t *error_attr; - pa_tnc_error_code_t error_code; - chunk_t msg_info, attr_info; - u_int32_t offset; - - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_code = error_attr->get_error_code(error_attr); - msg_info = error_attr->get_msg_info(error_attr); - DBG1(DBG_IMV, "received PA-TNC error '%N' concerning message %#B", - pa_tnc_error_code_names, error_code, &msg_info); - - switch (error_code) - { - case PA_ERROR_INVALID_PARAMETER: - offset = error_attr->get_offset(error_attr); - DBG1(DBG_IMV, " occurred at offset of %u bytes", offset); - break; - case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED: - attr_info = error_attr->get_attr_info(error_attr); - DBG1(DBG_IMV, " unsupported attribute %#B", &attr_info); - break; - default: - break; - } - fatal_error = TRUE; - } - else if (attr->get_type(attr) == IETF_ATTR_PORT_FILTER) + if (attr->get_vendor_id(attr) == PEN_IETF && + attr->get_type(attr) == IETF_ATTR_PORT_FILTER) { ietf_attr_port_filter_t *attr_port_filter; enumerator_t *enumerator; @@ -339,10 +309,47 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, } return imv_scanner->provide_recommendation(imv_scanner, connection_id); + } + +/** + * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + + msg_vid = msg_type >> 8; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + + return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len), + msg_vid, msg_subtype, 0, TNC_IMVID_ANY); +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_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_imc_id, + TNC_UInt32 dst_imv_id) +{ + return receive_message(imv_id, connection_id, msg_flags, + chunk_create(msg, msg_len), msg_vid, msg_subtype, + src_imc_id, dst_imv_id); } /** - * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, TNC_ConnectionID connection_id) @@ -356,7 +363,7 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, } /** - * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, TNC_ConnectionID connection_id) @@ -370,7 +377,7 @@ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, } /** - * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) { @@ -388,7 +395,7 @@ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) } /** - * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2 + * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, TNC_TNCS_BindFunctionPointer bind_function) diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c index a9b048bcb..422cb980d 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c @@ -40,6 +40,16 @@ struct private_imv_scanner_state_t { TNC_ConnectionState state; /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** * IMV action recommendation */ TNC_IMV_Action_Recommendation rec; @@ -86,6 +96,25 @@ METHOD(imv_state_t, get_connection_id, TNC_ConnectionID, return this->connection_id; } +METHOD(imv_state_t, has_long, bool, + private_imv_scanner_state_t *this) +{ + return this->has_long; +} + +METHOD(imv_state_t, has_excl, bool, + private_imv_scanner_state_t *this) +{ + return this->has_excl; +} + +METHOD(imv_state_t, set_flags, void, + private_imv_scanner_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + METHOD(imv_state_t, change_state, void, private_imv_scanner_state_t *this, TNC_ConnectionState new_state) { @@ -191,6 +220,9 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id) .public = { .interface = { .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, diff --git a/src/libimcv/plugins/imv_test/imv_test.c b/src/libimcv/plugins/imv_test/imv_test.c index 88db24983..0afd81aec 100644 --- a/src/libimcv/plugins/imv_test/imv_test.c +++ b/src/libimcv/plugins/imv_test/imv_test.c @@ -37,7 +37,7 @@ static const char imv_name[] = "Test"; static imv_agent_t *imv_test; /** - * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, TNC_Version min_version, @@ -64,16 +64,13 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, } /** - * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, TNC_ConnectionID connection_id, TNC_ConnectionState new_state) { imv_state_t *state; - imv_test_state_t *test_state; - TNC_Result result; - int rounds; if (!imv_test) { @@ -87,60 +84,29 @@ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, return imv_test->create_state(imv_test, state); case TNC_CONNECTION_STATE_DELETE: return imv_test->delete_state(imv_test, connection_id); - case TNC_CONNECTION_STATE_HANDSHAKE: - /* get updated IMV state */ - result = imv_test->change_state(imv_test, connection_id, - new_state, &state); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - test_state = (imv_test_state_t*)state; - - /* set the number of measurement rounds */ - rounds = lib->settings->get_int(lib->settings, - "libimcv.plugins.imv-test.rounds", 0); - test_state->set_rounds(test_state, rounds); - return TNC_RESULT_SUCCESS; default: return imv_test->change_state(imv_test, connection_id, new_state, NULL); } } -static TNC_Result send_message(TNC_ConnectionID connection_id) -{ - pa_tnc_msg_t *msg; - pa_tnc_attr_t *attr; - TNC_Result result; - - attr = ita_attr_command_create("repeat"); - msg = pa_tnc_msg_create(); - msg->add_attribute(msg, attr); - msg->build(msg); - result = imv_test->send_message(imv_test, connection_id, - msg->get_encoding(msg)); - msg->destroy(msg); - - return result; -} - -/** - * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2 - */ -TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, +static TNC_Result receive_message(TNC_IMVID imv_id, TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) + TNC_UInt32 msg_flags, + chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id) { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; imv_state_t *state; - imv_test_state_t *imv_test_state; + imv_test_state_t *test_state; enumerator_t *enumerator; TNC_Result result; - bool fatal_error = FALSE, retry = FALSE; + int rounds; + bool fatal_error, retry = FALSE; if (!imv_test) { @@ -153,11 +119,11 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, { return TNC_RESULT_FATAL; } + test_state = (imv_test_state_t*)state; /* parse received PA-TNC message and automatically handle any errors */ - result = imv_test->receive_message(imv_test, connection_id, - chunk_create(msg, msg_len), msg_type, - &pa_tnc_msg); + result = imv_test->receive_message(imv_test, state, msg, msg_vid, + msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg); /* no parsed PA-TNC attributes available if an error occurred */ if (!pa_tnc_msg) @@ -165,41 +131,20 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, return result; } + /* preprocess any IETF standard error attributes */ + fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg); + + /* add any new IMC and set its number of rounds */ + rounds = lib->settings->get_int(lib->settings, + "libimcv.plugins.imv-test.rounds", 0); + test_state->add_imc(test_state, src_imc_id, rounds); + /* analyze PA-TNC attributes */ enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_IETF && - attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) - { - ietf_attr_pa_tnc_error_t *error_attr; - pa_tnc_error_code_t error_code; - chunk_t msg_info, attr_info; - u_int32_t offset; - - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_code = error_attr->get_error_code(error_attr); - msg_info = error_attr->get_msg_info(error_attr); - - DBG1(DBG_IMV, "received PA-TNC error '%N' concerning message %#B", - pa_tnc_error_code_names, error_code, &msg_info); - switch (error_code) - { - case PA_ERROR_INVALID_PARAMETER: - offset = error_attr->get_offset(error_attr); - DBG1(DBG_IMV, " occurred at offset of %u bytes", offset); - break; - case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED: - attr_info = error_attr->get_attr_info(error_attr); - DBG1(DBG_IMV, " unsupported attribute %#B", &attr_info); - break; - default: - break; - } - fatal_error = TRUE; - } - else if (attr->get_vendor_id(attr) == PEN_ITA && - attr->get_type(attr) == ITA_ATTR_COMMAND) + if (attr->get_vendor_id(attr) == PEN_ITA && + attr->get_type(attr) == ITA_ATTR_COMMAND) { ita_attr_command_t *ita_attr; char *command; @@ -252,22 +197,67 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, /* request a handshake retry ? */ if (retry) { + test_state->set_rounds(test_state, rounds); return imv_test->request_handshake_retry(imv_id, connection_id, TNC_RETRY_REASON_IMV_SERIOUS_EVENT); } /* repeat the measurement ? */ - imv_test_state = (imv_test_state_t*)state; - if (imv_test_state->another_round(imv_test_state)) + if (test_state->another_round(test_state, src_imc_id)) { - return send_message(connection_id); + attr = ita_attr_command_create("repeat"); + pa_tnc_msg = pa_tnc_msg_create(); + pa_tnc_msg->add_attribute(pa_tnc_msg, attr); + pa_tnc_msg->build(pa_tnc_msg); + result = imv_test->send_message(imv_test, connection_id, TRUE, imv_id, + src_imc_id, pa_tnc_msg->get_encoding(pa_tnc_msg)); + pa_tnc_msg->destroy(pa_tnc_msg); + + return result; } return imv_test->provide_recommendation(imv_test, connection_id); } /** - * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + + msg_vid = msg_type >> 8; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + + return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len), + msg_vid, msg_subtype, 0, TNC_IMVID_ANY); +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_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_imc_id, + TNC_UInt32 dst_imv_id) +{ + return receive_message(imv_id, connection_id, msg_flags, + chunk_create(msg, msg_len), msg_vid, msg_subtype, + src_imc_id, dst_imv_id); +} + +/** + * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, TNC_ConnectionID connection_id) @@ -281,7 +271,7 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, } /** - * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, TNC_ConnectionID connection_id) @@ -295,7 +285,7 @@ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, } /** - * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2 + * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) { @@ -311,7 +301,7 @@ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) } /** - * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2 + * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3 */ TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, TNC_TNCS_BindFunctionPointer bind_function) diff --git a/src/libimcv/plugins/imv_test/imv_test_state.c b/src/libimcv/plugins/imv_test/imv_test_state.c index 930da93e4..530090af7 100644 --- a/src/libimcv/plugins/imv_test/imv_test_state.c +++ b/src/libimcv/plugins/imv_test/imv_test_state.c @@ -15,6 +15,7 @@ #include "imv_test_state.h" #include <utils/lexparser.h> +#include <utils/linked_list.h> #include <debug.h> typedef struct private_imv_test_state_t private_imv_test_state_t; @@ -40,6 +41,16 @@ struct private_imv_test_state_t { TNC_ConnectionState state; /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** * IMV action recommendation */ TNC_IMV_Action_Recommendation rec; @@ -50,10 +61,20 @@ struct private_imv_test_state_t { TNC_IMV_Evaluation_Result eval; /** - * IMC-IMV round-trip count + * List of IMCs */ - int rounds; + linked_list_t *imcs; + +}; +typedef struct imc_entry_t imc_entry_t; + +/** + * Define an internal IMC entry + */ +struct imc_entry_t { + TNC_UInt32 imc_id; + int rounds; }; typedef struct entry_t entry_t; @@ -82,6 +103,25 @@ METHOD(imv_state_t, get_connection_id, TNC_ConnectionID, return this->connection_id; } +METHOD(imv_state_t, has_long, bool, + private_imv_test_state_t *this) +{ + return this->has_long; +} + +METHOD(imv_state_t, has_excl, bool, + private_imv_test_state_t *this) +{ + return this->has_excl; +} + +METHOD(imv_state_t, set_flags, void, + private_imv_test_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + METHOD(imv_state_t, change_state, void, private_imv_test_state_t *this, TNC_ConnectionState new_state) { @@ -151,19 +191,73 @@ METHOD(imv_state_t, get_reason_string, bool, METHOD(imv_state_t, destroy, void, private_imv_test_state_t *this) { + this->imcs->destroy_function(this->imcs, free); free(this); } +METHOD(imv_test_state_t, add_imc, void, + private_imv_test_state_t *this, TNC_UInt32 imc_id, int rounds) +{ + enumerator_t *enumerator; + imc_entry_t *imc_entry; + bool found = FALSE; + + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc_entry)) + { + if (imc_entry->imc_id == imc_id) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + imc_entry = malloc_thing(imc_entry_t); + imc_entry->imc_id = imc_id; + imc_entry->rounds = rounds; + this->imcs->insert_last(this->imcs, imc_entry); + } +} + METHOD(imv_test_state_t, set_rounds, void, private_imv_test_state_t *this, int rounds) { - this->rounds = rounds; + enumerator_t *enumerator; + imc_entry_t *imc_entry; + + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc_entry)) + { + imc_entry->rounds = rounds; + } + enumerator->destroy(enumerator); } METHOD(imv_test_state_t, another_round, bool, - private_imv_test_state_t *this) + private_imv_test_state_t *this, TNC_UInt32 imc_id) { - return (this->rounds-- > 0); + enumerator_t *enumerator; + imc_entry_t *imc_entry; + bool not_finished = FALSE; + + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc_entry)) + { + if (imc_entry->rounds > 0) + { + not_finished = TRUE; + } + if (imc_entry->imc_id == imc_id) + { + imc_entry->rounds--; + } + } + enumerator->destroy(enumerator); + + return not_finished; } /** @@ -177,12 +271,16 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id) .public = { .interface = { .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, .get_reason_string = _get_reason_string, .destroy = _destroy, }, + .add_imc = _add_imc, .set_rounds = _set_rounds, .another_round = _another_round, }, @@ -190,6 +288,7 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id) .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, + .imcs = linked_list_create(), ); return &this->public.interface; diff --git a/src/libimcv/plugins/imv_test/imv_test_state.h b/src/libimcv/plugins/imv_test/imv_test_state.h index 7e7b3a8f3..af78d1470 100644 --- a/src/libimcv/plugins/imv_test/imv_test_state.h +++ b/src/libimcv/plugins/imv_test/imv_test_state.h @@ -37,6 +37,14 @@ struct imv_test_state_t { imv_state_t interface; /** + * Add an IMC + * + * @param imc_id ID of the IMC to be added + * @param rounds number of re-measurement rounds + */ + void (*add_imc)(imv_test_state_t *this, TNC_UInt32 imc_id, int rounds); + + /** * Set the IMC-IMV round-trip count * * @param rounds number of re-measurement rounds @@ -46,9 +54,10 @@ struct imv_test_state_t { /** * Check and decrease IMC-IMV round-trip count * + * @param imc_id ID of the IMC to be checked * @return new connection state */ - bool (*another_round)(imv_test_state_t *this); + bool (*another_round)(imv_test_state_t *this, TNC_UInt32 imc_id); }; /** diff --git a/src/libpts/Makefile.am b/src/libpts/Makefile.am index ee729c287..3ff941794 100644 --- a/src/libpts/Makefile.am +++ b/src/libpts/Makefile.am @@ -3,29 +3,56 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libimcv ipseclib_LTLIBRARIES = libpts.la -libpts_la_LIBADD = -ltspi +libpts_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la -ltspi libpts_la_SOURCES = \ libpts.h libpts.c \ pts/pts.h pts/pts.c \ pts/pts_error.h pts/pts_error.c \ - pts/pts_proto_caps.h pts/pts_funct_comp_name.h pts/pts_file_type.h \ + 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_funct_comp_evid.h tcg/tcg_pts_attr_req_funct_comp_evid.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 + +SUBDIRS = . + +if USE_IMC_ATTESTATION + SUBDIRS += plugins/imc_attestation +endif + +if USE_IMV_ATTESTATION + SUBDIRS += plugins/imv_attestation +endif diff --git a/src/libpts/libpts.c b/src/libpts/libpts.c index bd4c3a411..384ee4ed7 100644 --- a/src/libpts/libpts.c +++ b/src/libpts/libpts.c @@ -14,12 +14,23 @@ #include "libpts.h" #include "tcg/tcg_attr.h" +#include "pts/components/pts_component.h" +#include "pts/components/pts_component_manager.h" +#include "pts/components/tcg/tcg_comp_func_name.h" +#include "pts/components/ita/ita_comp_func_name.h" +#include "pts/components/ita/ita_comp_ima.h" +#include "pts/components/ita/ita_comp_tboot.h" +#include "pts/components/ita/ita_comp_tgrub.h" #include <imcv.h> - #include <debug.h> /** + * PTS Functional Component manager + */ +pts_component_manager_t *pts_components; + +/** * Reference count for IMC/IMV instances */ static refcount_t libpts_ref = 0; @@ -37,6 +48,25 @@ bool libpts_init(void) } imcv_pa_tnc_attributes->add_vendor(imcv_pa_tnc_attributes, PEN_TCG, tcg_attr_create_from_data, tcg_attr_names); + + pts_components = pts_component_manager_create(); + pts_components->add_vendor(pts_components, PEN_TCG, + pts_tcg_comp_func_names, PTS_TCG_QUALIFIER_TYPE_SIZE, + pts_tcg_qualifier_flag_names, pts_tcg_qualifier_type_names); + pts_components->add_vendor(pts_components, PEN_ITA, + pts_ita_comp_func_names, PTS_ITA_QUALIFIER_TYPE_SIZE, + pts_ita_qualifier_flag_names, pts_ita_qualifier_type_names); + + pts_components->add_component(pts_components, PEN_ITA, + PTS_ITA_COMP_FUNC_NAME_TGRUB, + pts_ita_comp_tgrub_create); + pts_components->add_component(pts_components, PEN_ITA, + PTS_ITA_COMP_FUNC_NAME_TBOOT, + pts_ita_comp_tboot_create); + pts_components->add_component(pts_components, PEN_ITA, + PTS_ITA_COMP_FUNC_NAME_IMA, + pts_ita_comp_ima_create); + DBG1(DBG_LIB, "libpts initialized"); } ref_get(&libpts_ref); @@ -51,6 +81,10 @@ void libpts_deinit(void) { if (ref_put(&libpts_ref)) { + pts_components->remove_vendor(pts_components, PEN_TCG); + pts_components->remove_vendor(pts_components, PEN_ITA); + pts_components->destroy(pts_components); + if (!imcv_pa_tnc_attributes) { return; diff --git a/src/libpts/libpts.h b/src/libpts/libpts.h index 4c771d236..7b2959728 100644 --- a/src/libpts/libpts.h +++ b/src/libpts/libpts.h @@ -25,6 +25,8 @@ #ifndef LIBPTS_H_ #define LIBPTS_H_ +#include "pts/components/pts_component_manager.h" + #include <library.h> /** @@ -39,4 +41,9 @@ bool libpts_init(void); */ void libpts_deinit(void); +/** + * PTS Functional Component manager + */ +extern pts_component_manager_t* pts_components; + #endif /** LIBPTS_H_ @}*/ diff --git a/src/libimcv/plugins/imc_attestation/Makefile.am b/src/libpts/plugins/imc_attestation/Makefile.am index ee082319d..9d78b935a 100644 --- a/src/libimcv/plugins/imc_attestation/Makefile.am +++ b/src/libpts/plugins/imc_attestation/Makefile.am @@ -11,7 +11,8 @@ imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \ $(top_builddir)/src/libpts/libpts.la imc_attestation_la_SOURCES = imc_attestation.c \ - imc_attestation_state.h imc_attestation_state.c + imc_attestation_state.h imc_attestation_state.c \ + imc_attestation_process.h imc_attestation_process.c imc_attestation_la_LDFLAGS = -module -avoid-version diff --git a/src/libpts/plugins/imc_attestation/imc_attestation.c b/src/libpts/plugins/imc_attestation/imc_attestation.c new file mode 100644 index 000000000..4f77ba093 --- /dev/null +++ b/src/libpts/plugins/imc_attestation/imc_attestation.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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_attestation_state.h" +#include "imc_attestation_process.h" + +#include <imc/imc_agent.h> +#include <pa_tnc/pa_tnc_msg.h> +#include <ietf/ietf_attr.h> +#include <ietf/ietf_attr_pa_tnc_error.h> +#include <ietf/ietf_attr_product_info.h> + +#include <libpts.h> + +#include <pts/pts_error.h> + +#include <tcg/tcg_pts_attr_proto_caps.h> +#include <tcg/tcg_pts_attr_meas_algo.h> + +#include <tncif_pa_subtypes.h> + +#include <pen/pen.h> +#include <debug.h> +#include <utils/linked_list.h> + +/* IMC definitions */ + +static const char imc_name[] = "Attestation"; + +#define IMC_VENDOR_ID PEN_TCG +#define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS + +static imc_agent_t *imc_attestation; + +/** + * Supported PTS measurement algorithms + */ +static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE; + +/** + * Supported PTS Diffie Hellman Groups + */ +static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE; + +/** + * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, + TNC_Version min_version, + TNC_Version max_version, + TNC_Version *actual_version) +{ + if (imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name); + return TNC_RESULT_ALREADY_INITIALIZED; + } + if (!pts_meas_algo_probe(&supported_algorithms) || + !pts_dh_group_probe(&supported_dh_groups)) + { + return TNC_RESULT_FATAL; + } + imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE, + imc_id, actual_version); + if (!imc_attestation) + { + 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; +} + +/** + * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imc_state_t *state; + + if (!imc_attestation) + { + 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_attestation_state_create(connection_id); + return imc_attestation->create_state(imc_attestation, state); + case TNC_CONNECTION_STATE_DELETE: + return imc_attestation->delete_state(imc_attestation, connection_id); + case TNC_CONNECTION_STATE_HANDSHAKE: + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + case TNC_CONNECTION_STATE_ACCESS_NONE: + default: + return imc_attestation->change_state(imc_attestation, connection_id, + new_state, NULL); + } +} + + +/** + * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + imc_state_t *state; + imc_attestation_state_t *attestation_state; + pts_t *pts; + char *platform_info; + TNC_Result result = TNC_RESULT_SUCCESS; + + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + + /* get current IMC state */ + if (!imc_attestation->get_state(imc_attestation, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imc_attestation_state_t*)state; + pts = attestation_state->get_pts(attestation_state); + + platform_info = pts->get_platform_info(pts); + if (platform_info) + { + pa_tnc_msg_t *pa_tnc_msg; + pa_tnc_attr_t *attr; + + pa_tnc_msg = pa_tnc_msg_create(); + attr = ietf_attr_product_info_create(0, 0, platform_info); + pa_tnc_msg->add_attribute(pa_tnc_msg, attr); + pa_tnc_msg->build(pa_tnc_msg); + result = imc_attestation->send_message(imc_attestation, connection_id, + FALSE, 0, TNC_IMVID_ANY, + pa_tnc_msg->get_encoding(pa_tnc_msg)); + pa_tnc_msg->destroy(pa_tnc_msg); + } + + return result; +} + +static TNC_Result receive_message(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_UInt32 msg_flags, + chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, + TNC_UInt32 dst_imc_id) +{ + pa_tnc_msg_t *pa_tnc_msg; + pa_tnc_attr_t *attr; + linked_list_t *attr_list; + imc_state_t *state; + imc_attestation_state_t *attestation_state; + enumerator_t *enumerator; + TNC_Result result; + + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + + /* get current IMC state */ + if (!imc_attestation->get_state(imc_attestation, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imc_attestation_state_t*)state; + + /* parse received PA-TNC message and automatically handle any errors */ + result = imc_attestation->receive_message(imc_attestation, state, msg, + msg_vid, msg_subtype, src_imv_id, dst_imc_id, &pa_tnc_msg); + + /* no parsed PA-TNC attributes available if an error occurred */ + if (!pa_tnc_msg) + { + return result; + } + + /* preprocess any IETF standard error attributes */ + result = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg) ? + TNC_RESULT_FATAL : TNC_RESULT_SUCCESS; + + attr_list = linked_list_create(); + + /* analyze PA-TNC attributes */ + enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->get_vendor_id(attr) == PEN_IETF && + attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) + { + ietf_attr_pa_tnc_error_t *error_attr; + pen_t error_vendor_id; + pa_tnc_error_code_t error_code; + chunk_t msg_info; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; + error_vendor_id = error_attr->get_vendor_id(error_attr); + + if (error_vendor_id == PEN_TCG) + { + error_code = error_attr->get_error_code(error_attr); + msg_info = error_attr->get_msg_info(error_attr); + + DBG1(DBG_IMC, "received TCG-PTS error '%N'", + pts_error_code_names, error_code); + DBG1(DBG_IMC, "error information: %B", &msg_info); + + result = TNC_RESULT_FATAL; + } + } + else if (attr->get_vendor_id(attr) == PEN_TCG) + { + if (!imc_attestation_process(attr, attr_list, attestation_state, + supported_algorithms, supported_dh_groups)) + { + result = TNC_RESULT_FATAL; + break; + } + } + } + enumerator->destroy(enumerator); + pa_tnc_msg->destroy(pa_tnc_msg); + + if (result == TNC_RESULT_SUCCESS && attr_list->get_count(attr_list)) + { + pa_tnc_msg = pa_tnc_msg_create(); + + enumerator = attr_list->create_enumerator(attr_list); + while (enumerator->enumerate(enumerator, &attr)) + { + pa_tnc_msg->add_attribute(pa_tnc_msg, attr); + } + enumerator->destroy(enumerator); + + pa_tnc_msg->build(pa_tnc_msg); + result = imc_attestation->send_message(imc_attestation, connection_id, + FALSE, 0, TNC_IMVID_ANY, + pa_tnc_msg->get_encoding(pa_tnc_msg)); + pa_tnc_msg->destroy(pa_tnc_msg); + } + + attr_list->destroy(attr_list); + return result; +} + +/** + * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + + msg_vid = msg_type >> 8; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + + return receive_message(imc_id, connection_id, 0, chunk_create(msg, msg_len), + msg_vid, msg_subtype, 0, TNC_IMCID_ANY); +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +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) +{ + return receive_message(imc_id, connection_id, msg_flags, + chunk_create(msg, msg_len), msg_vid, msg_subtype, + src_imv_id, dst_imc_id); +} + +/** + * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + if (!imc_attestation) + { + 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 + */ +TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) +{ + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + + libpts_deinit(); + + imc_attestation->destroy(imc_attestation); + imc_attestation = NULL; + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, + TNC_TNCC_BindFunctionPointer bind_function) +{ + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imc_attestation->bind_functions(imc_attestation, bind_function); +} diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_process.c b/src/libpts/plugins/imc_attestation/imc_attestation_process.c new file mode 100644 index 000000000..b70c05370 --- /dev/null +++ b/src/libpts/plugins/imc_attestation/imc_attestation_process.c @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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. + */ + +#define _GNU_SOURCE + +#include <stdio.h> +/* for isdigit */ +#include <ctype.h> + +#include "imc_attestation_process.h" + +#include <ietf/ietf_attr_pa_tnc_error.h> + +#include <libpts.h> +#include <pts/pts.h> + +#include <tcg/tcg_pts_attr_proto_caps.h> +#include <tcg/tcg_pts_attr_meas_algo.h> +#include <tcg/tcg_pts_attr_dh_nonce_params_req.h> +#include <tcg/tcg_pts_attr_dh_nonce_params_resp.h> +#include <tcg/tcg_pts_attr_dh_nonce_finish.h> +#include <tcg/tcg_pts_attr_get_tpm_version_info.h> +#include <tcg/tcg_pts_attr_tpm_version_info.h> +#include <tcg/tcg_pts_attr_get_aik.h> +#include <tcg/tcg_pts_attr_aik.h> +#include <tcg/tcg_pts_attr_req_func_comp_evid.h> +#include <tcg/tcg_pts_attr_gen_attest_evid.h> +#include <tcg/tcg_pts_attr_simple_comp_evid.h> +#include <tcg/tcg_pts_attr_simple_evid_final.h> +#include <tcg/tcg_pts_attr_req_file_meas.h> +#include <tcg/tcg_pts_attr_file_meas.h> +#include <tcg/tcg_pts_attr_req_file_meta.h> +#include <tcg/tcg_pts_attr_unix_file_meta.h> + +#include <debug.h> +#include <utils/lexparser.h> + +#define DEFAULT_NONCE_LEN 20 + +bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, + imc_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups) +{ + chunk_t attr_info; + pts_t *pts; + pts_error_code_t pts_error; + bool valid_path; + + pts = attestation_state->get_pts(attestation_state); + switch (attr->get_type(attr)) + { + case TCG_PTS_REQ_PROTO_CAPS: + { + tcg_pts_attr_proto_caps_t *attr_cast; + pts_proto_caps_flag_t imc_caps, imv_caps; + + attr_cast = (tcg_pts_attr_proto_caps_t*)attr; + imv_caps = attr_cast->get_flags(attr_cast); + imc_caps = pts->get_proto_caps(pts); + pts->set_proto_caps(pts, imc_caps & imv_caps); + + /* Send PTS Protocol Capabilities attribute */ + attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps, FALSE); + attr_list->insert_last(attr_list, attr); + break; + } + case TCG_PTS_MEAS_ALGO: + { + tcg_pts_attr_meas_algo_t *attr_cast; + pts_meas_algorithms_t offered_algorithms, selected_algorithm; + + attr_cast = (tcg_pts_attr_meas_algo_t*)attr; + offered_algorithms = attr_cast->get_algorithms(attr_cast); + selected_algorithm = pts_meas_algo_select(supported_algorithms, + offered_algorithms); + if (selected_algorithm == PTS_MEAS_ALGO_NONE) + { + attr = pts_hash_alg_error_create(supported_algorithms); + attr_list->insert_last(attr_list, attr); + break; + } + + /* Send Measurement Algorithm Selection attribute */ + pts->set_meas_algorithm(pts, selected_algorithm); + attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE); + attr_list->insert_last(attr_list, attr); + break; + } + case TCG_PTS_DH_NONCE_PARAMS_REQ: + { + tcg_pts_attr_dh_nonce_params_req_t *attr_cast; + pts_dh_group_t offered_dh_groups, selected_dh_group; + chunk_t responder_value, responder_nonce; + int nonce_len, min_nonce_len; + + nonce_len = lib->settings->get_int(lib->settings, + "libimcv.plugins.imc-attestation.nonce_len", + DEFAULT_NONCE_LEN); + + attr_cast = (tcg_pts_attr_dh_nonce_params_req_t*)attr; + min_nonce_len = attr_cast->get_min_nonce_len(attr_cast); + if (nonce_len < PTS_MIN_NONCE_LEN || + (min_nonce_len > 0 && nonce_len < min_nonce_len)) + { + attr = pts_dh_nonce_error_create(nonce_len, PTS_MAX_NONCE_LEN); + attr_list->insert_last(attr_list, attr); + break; + } + + offered_dh_groups = attr_cast->get_dh_groups(attr_cast); + selected_dh_group = pts_dh_group_select(supported_dh_groups, + offered_dh_groups); + if (selected_dh_group == PTS_DH_GROUP_NONE) + { + attr = pts_dh_group_error_create(supported_dh_groups); + attr_list->insert_last(attr_list, attr); + break; + } + + /* Create own DH factor and nonce */ + if (!pts->create_dh_nonce(pts, selected_dh_group, nonce_len)) + { + return FALSE; + } + pts->get_my_public_value(pts, &responder_value, &responder_nonce); + + /* Send DH Nonce Parameters Response attribute */ + attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group, + supported_algorithms, responder_nonce, responder_value); + attr_list->insert_last(attr_list, attr); + break; + } + case TCG_PTS_DH_NONCE_FINISH: + { + tcg_pts_attr_dh_nonce_finish_t *attr_cast; + pts_meas_algorithms_t selected_algorithm; + chunk_t initiator_nonce, initiator_value; + int nonce_len; + + attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr; + selected_algorithm = attr_cast->get_hash_algo(attr_cast); + if (!(selected_algorithm & supported_algorithms)) + { + DBG1(DBG_IMC, "PTS-IMV selected unsupported DH hash algorithm"); + return FALSE; + } + pts->set_dh_hash_algorithm(pts, selected_algorithm); + + initiator_value = attr_cast->get_initiator_value(attr_cast); + initiator_nonce = attr_cast->get_initiator_nonce(attr_cast); + + nonce_len = lib->settings->get_int(lib->settings, + "libimcv.plugins.imc-attestation.nonce_len", + DEFAULT_NONCE_LEN); + if (nonce_len != initiator_nonce.len) + { + DBG1(DBG_IMC, "initiator and responder DH nonces " + "have differing lengths"); + return FALSE; + } + + pts->set_peer_public_value(pts, initiator_value, initiator_nonce); + if (!pts->calculate_secret(pts)) + { + return FALSE; + } + break; + } + case TCG_PTS_GET_TPM_VERSION_INFO: + { + chunk_t tpm_version_info, attr_info; + + if (!pts->get_tpm_version_info(pts, &tpm_version_info)) + { + attr_info = attr->get_value(attr); + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + + /* Send TPM Version Info attribute */ + attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info); + attr_list->insert_last(attr_list, attr); + break; + } + case TCG_PTS_GET_AIK: + { + certificate_t *aik; + + aik = pts->get_aik(pts); + if (!aik) + { + DBG1(DBG_IMC, "no AIK certificate or public key available"); + break; + } + + /* Send AIK attribute */ + attr = tcg_pts_attr_aik_create(aik); + attr_list->insert_last(attr_list, attr); + break; + } + case TCG_PTS_REQ_FILE_MEAS: + { + tcg_pts_attr_req_file_meas_t *attr_cast; + char *pathname; + u_int16_t request_id; + bool is_directory; + u_int32_t delimiter; + pts_file_meas_t *measurements; + + attr_info = attr->get_value(attr); + attr_cast = (tcg_pts_attr_req_file_meas_t*)attr; + is_directory = attr_cast->get_directory_flag(attr_cast); + request_id = attr_cast->get_request_id(attr_cast); + delimiter = attr_cast->get_delimiter(attr_cast); + pathname = attr_cast->get_pathname(attr_cast); + valid_path = pts->is_path_valid(pts, pathname, &pts_error); + + if (valid_path && pts_error) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + pts_error, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + else if (!valid_path) + { + break; + } + + if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + TCG_PTS_INVALID_DELIMITER, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + + /* Do PTS File Measurements and send them to PTS-IMV */ + DBG2(DBG_IMC, "measurement request %d for %s '%s'", + request_id, is_directory ? "directory" : "file", + pathname); + measurements = pts->do_measurements(pts, request_id, + pathname, is_directory); + if (!measurements) + { + /* TODO handle error codes from measurements */ + return FALSE; + } + attr = tcg_pts_attr_file_meas_create(measurements); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + break; + } + case TCG_PTS_REQ_FILE_META: + { + tcg_pts_attr_req_file_meta_t *attr_cast; + char *pathname; + bool is_directory; + u_int8_t delimiter; + pts_file_meta_t *metadata; + + attr_info = attr->get_value(attr); + attr_cast = (tcg_pts_attr_req_file_meta_t*)attr; + is_directory = attr_cast->get_directory_flag(attr_cast); + delimiter = attr_cast->get_delimiter(attr_cast); + pathname = attr_cast->get_pathname(attr_cast); + + valid_path = pts->is_path_valid(pts, pathname, &pts_error); + if (valid_path && pts_error) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + pts_error, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + else if (!valid_path) + { + break; + } + if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + TCG_PTS_INVALID_DELIMITER, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + /* Get File Metadata and send them to PTS-IMV */ + DBG2(DBG_IMC, "metadata request for %s '%s'", + is_directory ? "directory" : "file", + pathname); + metadata = pts->get_metadata(pts, pathname, is_directory); + + if (!metadata) + { + /* TODO handle error codes from measurements */ + return FALSE; + } + attr = tcg_pts_attr_unix_file_meta_create(metadata); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + + break; + } + case TCG_PTS_REQ_FUNC_COMP_EVID: + { + tcg_pts_attr_req_func_comp_evid_t *attr_cast; + pts_proto_caps_flag_t negotiated_caps; + pts_comp_func_name_t *name; + pts_comp_evidence_t *evid; + pts_component_t *comp; + u_int32_t depth; + u_int8_t flags; + status_t status; + enumerator_t *e; + + attr_info = attr->get_value(attr); + attr_cast = (tcg_pts_attr_req_func_comp_evid_t*)attr; + + DBG1(DBG_IMC, "evidence requested for %d functional components", + attr_cast->get_count(attr_cast)); + + e = attr_cast->create_enumerator(attr_cast); + while (e->enumerate(e, &flags, &depth, &name)) + { + name->log(name, "* "); + negotiated_caps = pts->get_proto_caps(pts); + + if (flags & PTS_REQ_FUNC_COMP_EVID_TTC) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + TCG_PTS_UNABLE_DET_TTC, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + if (flags & PTS_REQ_FUNC_COMP_EVID_VER && + !(negotiated_caps & PTS_PROTO_CAPS_V)) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + TCG_PTS_UNABLE_LOCAL_VAL, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + if (flags & PTS_REQ_FUNC_COMP_EVID_CURR && + !(negotiated_caps & PTS_PROTO_CAPS_C)) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + TCG_PTS_UNABLE_CUR_EVID, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + if (flags & PTS_REQ_FUNC_COMP_EVID_PCR && + !(negotiated_caps & PTS_PROTO_CAPS_T)) + { + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, + TCG_PTS_UNABLE_DET_PCR, attr_info); + attr_list->insert_last(attr_list, attr); + break; + } + if (depth > 0) + { + DBG1(DBG_IMC, "the Attestation IMC currently does not " + "support sub component measurements"); + return FALSE; + } + comp = pts_components->create(pts_components, name, depth, NULL); + if (!comp) + { + DBG2(DBG_IMC, " not registered: no evidence provided"); + continue; + } + + /* do the component evidence measurement[s] */ + do + { + status = comp->measure(comp, pts, &evid); + if (status == FAILED) + { + break; + } + attestation_state->add_evidence(attestation_state, evid); + } + while (status == NEED_MORE); + comp->destroy(comp); + } + e->destroy(e); + break; + } + case TCG_PTS_GEN_ATTEST_EVID: + { + pts_simple_evid_final_flag_t flags; + pts_meas_algorithms_t comp_hash_algorithm; + pts_comp_evidence_t *evid; + chunk_t pcr_composite, quote_sig; + bool use_quote2; + + /* Send buffered Simple Component Evidences */ + while (attestation_state->next_evidence(attestation_state, &evid)) + { + pts->select_pcr(pts, evid->get_extended_pcr(evid)); + + /* Send Simple Component Evidence */ + attr = tcg_pts_attr_simple_comp_evid_create(evid); + attr_list->insert_last(attr_list, attr); + } + + use_quote2 = lib->settings->get_bool(lib->settings, + "libimcv.plugins.imc-attestation.use_quote2", TRUE); + if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, "e_sig)) + { + DBG1(DBG_IMC, "error occurred during TPM quote operation"); + return FALSE; + } + + /* Send Simple Evidence Final attribute */ + flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 : + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO; + comp_hash_algorithm = PTS_MEAS_ALGO_SHA1; + + attr = tcg_pts_attr_simple_evid_final_create(flags, + comp_hash_algorithm, pcr_composite, quote_sig); + attr_list->insert_last(attr_list, attr); + break; + } + /* TODO: Not implemented yet */ + case TCG_PTS_REQ_INTEG_MEAS_LOG: + /* Attributes using XML */ + case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META: + case TCG_PTS_UPDATE_TEMPL_REF_MANI: + /* On Windows only*/ + case TCG_PTS_REQ_REGISTRY_VALUE: + /* Received on IMV side only*/ + case TCG_PTS_PROTO_CAPS: + case TCG_PTS_DH_NONCE_PARAMS_RESP: + case TCG_PTS_MEAS_ALGO_SELECTION: + case TCG_PTS_TPM_VERSION_INFO: + case TCG_PTS_TEMPL_REF_MANI_SET_META: + case TCG_PTS_AIK: + case TCG_PTS_SIMPLE_COMP_EVID: + case TCG_PTS_SIMPLE_EVID_FINAL: + case TCG_PTS_VERIFICATION_RESULT: + case TCG_PTS_INTEG_REPORT: + case TCG_PTS_UNIX_FILE_META: + case TCG_PTS_FILE_MEAS: + case TCG_PTS_INTEG_MEAS_LOG: + default: + DBG1(DBG_IMC, "received unsupported attribute '%N'", + tcg_attr_names, attr->get_type(attr)); + break; + } + return TRUE; +} diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_process.h b/src/libpts/plugins/imc_attestation/imc_attestation_process.h new file mode 100644 index 000000000..b6dca1f56 --- /dev/null +++ b/src/libpts/plugins/imc_attestation/imc_attestation_process.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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_attestation_process_t imc_attestation_process + * @{ @ingroup imc_attestation_process + */ + +#ifndef IMC_ATTESTATION_PROCESS_H_ +#define IMC_ATTESTATION_PROCESS_H_ + +#include "imc_attestation_state.h" + +#include <library.h> + +#include <pa_tnc/pa_tnc_attr.h> + +#include <pts/pts_dh_group.h> +#include <pts/pts_meas_algo.h> + +/** + * Process a TCG PTS attribute + * + * @param attr PA-TNC attribute to be processed + * @param attr_list list with PA-TNC error attributes + * @param attestation_state attestation state of a given connection + * @param supported_algorithms supported PTS measurement algorithms + * @param supported_dh_groups supported DH groups + * @return TRUE if successful + */ +bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, + imc_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups); + +#endif /** IMC_ATTESTATION_PROCESS_H_ @}*/ diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_state.c b/src/libpts/plugins/imc_attestation/imc_attestation_state.c index 9087b711c..72a55f60e 100644 --- a/src/libimcv/plugins/imc_attestation/imc_attestation_state.c +++ b/src/libpts/plugins/imc_attestation/imc_attestation_state.c @@ -15,6 +15,7 @@ #include "imc_attestation_state.h" +#include <utils/linked_list.h> #include <debug.h> typedef struct private_imc_attestation_state_t private_imc_attestation_state_t; @@ -40,10 +41,25 @@ struct private_imc_attestation_state_t { TNC_ConnectionState state; /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** * PTS object */ pts_t *pts; + /** + * PTS Component Evidence list + */ + linked_list_t *list; + }; METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, @@ -52,16 +68,37 @@ METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, return this->connection_id; } +METHOD(imc_state_t, has_long, bool, + private_imc_attestation_state_t *this) +{ + return this->has_long; +} + +METHOD(imc_state_t, has_excl, bool, + private_imc_attestation_state_t *this) +{ + return this->has_excl; +} + +METHOD(imc_state_t, set_flags, void, + private_imc_attestation_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + METHOD(imc_state_t, change_state, void, private_imc_attestation_state_t *this, TNC_ConnectionState new_state) { this->state = new_state; } + METHOD(imc_state_t, destroy, void, private_imc_attestation_state_t *this) { this->pts->destroy(this->pts); + this->list->destroy_offset(this->list, offsetof(pts_comp_evidence_t, destroy)); free(this); } @@ -71,6 +108,18 @@ METHOD(imc_attestation_state_t, get_pts, pts_t*, return this->pts; } +METHOD(imc_attestation_state_t, add_evidence, void, + private_imc_attestation_state_t *this, pts_comp_evidence_t *evidence) +{ + this->list->insert_last(this->list, evidence); +} + +METHOD(imc_attestation_state_t, next_evidence, bool, + private_imc_attestation_state_t *this, pts_comp_evidence_t **evid) +{ + return this->list->remove_first(this->list, (void**)evid) == SUCCESS; +} + /** * Described in header. */ @@ -83,14 +132,20 @@ imc_state_t *imc_attestation_state_create(TNC_ConnectionID connection_id) .public = { .interface = { .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, .change_state = _change_state, .destroy = _destroy, }, .get_pts = _get_pts, + .add_evidence = _add_evidence, + .next_evidence = _next_evidence, }, .connection_id = connection_id, .state = TNC_CONNECTION_STATE_CREATE, .pts = pts_create(TRUE), + .list = linked_list_create(), ); platform_info = lib->settings->get_str(lib->settings, diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_state.h b/src/libpts/plugins/imc_attestation/imc_attestation_state.h index d083f3b57..22b0bba23 100644 --- a/src/libimcv/plugins/imc_attestation/imc_attestation_state.h +++ b/src/libpts/plugins/imc_attestation/imc_attestation_state.h @@ -24,6 +24,7 @@ #include <imc/imc_state.h> #include <pts/pts.h> +#include <pts/components/pts_comp_evidence.h> #include <library.h> typedef struct imc_attestation_state_t imc_attestation_state_t; @@ -45,6 +46,21 @@ struct imc_attestation_state_t { */ pts_t* (*get_pts)(imc_attestation_state_t *this); + /** + * Add an entry to the Component Evidence list + * + * @param entry Component Evidence entry + */ + void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *entry); + + /** + * Removes next Component Evidence entry from list and returns it + * + * @param evid Next Component Evidence entry + * @return TRUE if next entry is available + */ + bool (*next_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t** evid); + }; /** diff --git a/src/libpts/plugins/imv_attestation/.gitignore b/src/libpts/plugins/imv_attestation/.gitignore new file mode 100644 index 000000000..79548ebac --- /dev/null +++ b/src/libpts/plugins/imv_attestation/.gitignore @@ -0,0 +1 @@ +attest diff --git a/src/libpts/plugins/imv_attestation/Makefile.am b/src/libpts/plugins/imv_attestation/Makefile.am new file mode 100644 index 000000000..a550a3552 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/Makefile.am @@ -0,0 +1,33 @@ + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv \ + -I$(top_srcdir)/src/libpts + +AM_CFLAGS = -rdynamic -DPLUGINS=\""${attest_plugins}\"" + +imcv_LTLIBRARIES = imv-attestation.la + +imv_attestation_la_LIBADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libpts/libpts.la + +imv_attestation_la_SOURCES = imv_attestation.c \ + imv_attestation_state.h imv_attestation_state.c \ + imv_attestation_process.h imv_attestation_process.c \ + imv_attestation_build.h imv_attestation_build.c + +imv_attestation_la_LDFLAGS = -module -avoid-version + +ipsec_PROGRAMS = attest +attest_SOURCES = attest.c \ + attest_usage.h attest_usage.c \ + attest_db.h attest_db.c \ + tables.sql data.sql +attest_LDADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libpts/libpts.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +attest.o : $(top_builddir)/config.status diff --git a/src/libpts/plugins/imv_attestation/attest.c b/src/libpts/plugins/imv_attestation/attest.c new file mode 100644 index 000000000..9200820e8 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/attest.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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. + */ + +#define _GNU_SOURCE +#include <getopt.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <syslog.h> + +#include <library.h> +#include <debug.h> + +#include <imcv.h> +#include <libpts.h> +#include <pts/pts_meas_algo.h> + +#include "attest_db.h" +#include "attest_usage.h" + +/** + * global debug output variables + */ +static int debug_level = 2; +static bool stderr_quiet = TRUE; + +/** + * attest dbg function + */ +static void attest_dbg(debug_t group, level_t level, char *fmt, ...) +{ + int priority = LOG_INFO; + char buffer[8192]; + char *current = buffer, *next; + va_list args; + + if (level <= debug_level) + { + if (!stderr_quiet) + { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + } + + /* write in memory buffer first */ + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + /* do a syslog with every line */ + while (current) + { + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + syslog(priority, "%s\n", current); + current = next; + } + } +} + +/** + * global attestation database object + */ +attest_db_t *attest; + +/** + * atexit handler to close db on shutdown + */ +static void cleanup(void) +{ + attest->destroy(attest); + libpts_deinit(); + libimcv_deinit(); + closelog(); +} + +static void do_args(int argc, char *argv[]) +{ + enum { + OP_UNDEF, + OP_USAGE, + OP_KEYS, + OP_COMPONENTS, + OP_FILES, + OP_HASHES, + OP_MEASUREMENTS, + OP_PRODUCTS, + OP_ADD, + OP_DEL, + } op = OP_UNDEF; + + /* reinit getopt state */ + optind = 0; + + while (TRUE) + { + int c; + + struct option long_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "components", no_argument, NULL, 'c' }, + { "files", no_argument, NULL, 'f' }, + { "keys", no_argument, NULL, 'k' }, + { "products", no_argument, NULL, 'p' }, + { "hashes", no_argument, NULL, 'H' }, + { "measurements", no_argument, NULL, 'm' }, + { "add", no_argument, NULL, 'a' }, + { "delete", no_argument, NULL, 'd' }, + { "del", no_argument, NULL, 'd' }, + { "aik", required_argument, NULL, 'A' }, + { "component", required_argument, NULL, 'C' }, + { "comp", required_argument, NULL, 'C' }, + { "directory", required_argument, NULL, 'D' }, + { "dir", required_argument, NULL, 'D' }, + { "file", required_argument, NULL, 'F' }, + { "key", required_argument, NULL, 'K' }, + { "owner", required_argument, NULL, 'O' }, + { "product", required_argument, NULL, 'P' }, + { "sha1", no_argument, NULL, '1' }, + { "sha256", no_argument, NULL, '2' }, + { "sha384", no_argument, NULL, '3' }, + { "did", required_argument, NULL, '4' }, + { "fid", required_argument, NULL, '5' }, + { "pid", required_argument, NULL, '6' }, + { "cid", required_argument, NULL, '7' }, + { "kid", required_argument, NULL, '8' }, + { 0,0,0,0 } + }; + + c = getopt_long(argc, argv, "", long_opts, NULL); + switch (c) + { + case EOF: + break; + case 'h': + op = OP_USAGE; + break; + case 'c': + op = OP_COMPONENTS; + continue; + case 'f': + op = OP_FILES; + continue; + case 'k': + op = OP_KEYS; + continue; + case 'p': + op = OP_PRODUCTS; + continue; + case 'H': + op = OP_HASHES; + continue; + case 'm': + op = OP_MEASUREMENTS; + continue; + case 'a': + op = OP_ADD; + continue; + case 'd': + op = OP_DEL; + continue; + case 'A': + { + certificate_t *aik_cert; + public_key_t *aik_key; + chunk_t aik; + + aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_X509, BUILD_FROM_FILE, optarg, BUILD_END); + if (!aik_cert) + { + printf("AIK certificate '%s' could not be loaded\n", optarg); + exit(EXIT_FAILURE); + } + aik_key = aik_cert->get_public_key(aik_cert); + aik_cert->destroy(aik_cert); + + if (!aik_key) + { + printf("AIK public key could not be retrieved\n"); + exit(EXIT_FAILURE); + } + if (!aik_key->get_fingerprint(aik_key, KEYID_PUBKEY_INFO_SHA1, + &aik)) + { + printf("AIK fingerprint could not be computed\n"); + aik_key->destroy(aik_key); + exit(EXIT_FAILURE); + } + aik = chunk_clone(aik); + aik_key->destroy(aik_key); + + if (!attest->set_key(attest, aik, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + } + case 'C': + if (!attest->set_component(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case 'D': + if (!attest->set_directory(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case 'F': + if (!attest->set_file(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case 'K': + { + chunk_t aik; + + aik = chunk_from_hex(chunk_create(optarg, strlen(optarg)), NULL); + if (!attest->set_key(attest, aik, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + } + case 'O': + attest->set_owner(attest, optarg); + continue; + case 'P': + if (!attest->set_product(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case '1': + attest->set_algo(attest, PTS_MEAS_ALGO_SHA1); + continue; + case '2': + attest->set_algo(attest, PTS_MEAS_ALGO_SHA256); + continue; + case '3': + attest->set_algo(attest, PTS_MEAS_ALGO_SHA384); + continue; + case '4': + if (!attest->set_did(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '5': + if (!attest->set_fid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '6': + if (!attest->set_pid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '7': + if (!attest->set_cid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '8': + if (!attest->set_kid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + } + break; + } + + switch (op) + { + case OP_USAGE: + usage(); + break; + case OP_PRODUCTS: + attest->list_products(attest); + break; + case OP_KEYS: + attest->list_keys(attest); + break; + case OP_COMPONENTS: + attest->list_components(attest); + break; + case OP_FILES: + attest->list_files(attest); + break; + case OP_HASHES: + attest->list_hashes(attest); + break; + case OP_MEASUREMENTS: + attest->list_measurements(attest); + break; + case OP_ADD: + attest->add(attest); + break; + case OP_DEL: + attest->delete(attest); + break; + default: + usage(); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char *argv[]) +{ + char *uri; + + /* enable attest debugging hook */ + dbg = attest_dbg; + openlog("attest", 0, LOG_DEBUG); + + atexit(library_deinit); + + /* initialize library */ + if (!library_init(NULL)) + { + exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); + } + if (!lib->plugins->load(lib->plugins, NULL, + lib->settings->get_str(lib->settings, "attest.load", PLUGINS))) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + + uri = lib->settings->get_str(lib->settings, "attest.database", NULL); + if (!uri) + { + fprintf(stderr, "database URI attest.database not set.\n"); + exit(SS_RC_INITIALIZATION_FAILED); + } + attest = attest_db_create(uri); + if (!attest) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + atexit(cleanup); + libimcv_init(); + libpts_init(); + + do_args(argc, argv); + + exit(EXIT_SUCCESS); +} + diff --git a/src/libpts/plugins/imv_attestation/attest_db.c b/src/libpts/plugins/imv_attestation/attest_db.c new file mode 100644 index 000000000..88d19eee1 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/attest_db.c @@ -0,0 +1,1200 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 "attest_db.h" + +#include "libpts.h" +#include "pts/components/pts_comp_func_name.h" + +typedef struct private_attest_db_t private_attest_db_t; + +/** + * Private data of an attest_db_t object. + */ +struct private_attest_db_t { + + /** + * Public members of attest_db_state_t + */ + attest_db_t public; + + /** + * Component Functional Name to be queried + */ + pts_comp_func_name_t *cfn; + + /** + * Primary key of the Component Functional Name to be queried + */ + int cid; + + /** + * TRUE if Component Functional Name has been set + */ + bool comp_set; + + /** + * Directory containing the Measurement file to be queried + */ + char *dir; + + /** + * Primary key of the directory to be queried + */ + int did; + + /** + * TRUE if directory has been set + */ + bool dir_set; + + /** + * Measurement file to be queried + */ + char *file; + + /** + * Primary key of measurement file to be queried + */ + int fid; + + /** + * TRUE if file has been set + */ + bool file_set; + + /** + * AIK to be queried + */ + chunk_t key; + + /** + * Primary key of the AIK to be queried + */ + int kid; + + /** + * TRUE if AIK has been set + */ + bool key_set; + + /** + * Software product to be queried + */ + char *product; + + /** + * Primary key of software product to be queried + */ + int pid; + + /** + * TRUE if product has been set + */ + bool product_set; + + /** + * File measurement hash algorithm + */ + pts_meas_algorithms_t algo; + + /** + * Optional owner (user/host name) + */ + char *owner; + + /** + * Attestation database + */ + database_t *db; + +}; + +char* print_cfn(pts_comp_func_name_t *cfn) +{ + static char buf[BUF_LEN]; + char flags[8]; + int type, vid, name, qualifier, n; + enum_name_t *names, *types; + + vid = cfn->get_vendor_id(cfn), + name = cfn->get_name(cfn); + qualifier = cfn->get_qualifier(cfn); + n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier); + + names = pts_components->get_comp_func_names(pts_components, vid); + types = pts_components->get_qualifier_type_names(pts_components, vid); + type = pts_components->get_qualifier(pts_components, cfn, flags); + if (names && types) + { + n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N", + pen_names, vid, names, name, flags, types, type); + } + return buf; +} + +METHOD(attest_db_t, set_component, bool, + private_attest_db_t *this, char *comp, bool create) +{ + enumerator_t *e; + char *pos1, *pos2; + int vid, name, qualifier; + pts_comp_func_name_t *cfn; + + if (this->comp_set) + { + printf("component has already been set\n"); + return FALSE; + } + + /* parse component string */ + pos1 = strchr(comp, '/'); + pos2 = strchr(comp, '-'); + if (!pos1 || !pos2) + { + printf("component string must have the form \"vendor_id/name-qualifier\"\n"); + return FALSE; + } + vid = atoi(comp); + name = atoi(pos1 + 1); + qualifier = atoi(pos2 + 1); + cfn = pts_comp_func_name_create(vid, name, qualifier); + + e = this->db->query(this->db, + "SELECT id FROM components " + "WHERE vendor_id = ? AND name = ? AND qualifier = ?", + DB_INT, vid, DB_INT, name, DB_INT, qualifier, DB_INT); + if (e) + { + if (e->enumerate(e, &this->cid)) + { + this->comp_set = TRUE; + this->cfn = cfn; + } + e->destroy(e); + } + if (this->comp_set) + { + return TRUE; + } + + if (!create) + { + printf("component '%s' not found in database\n", print_cfn(cfn)); + cfn->destroy(cfn); + return FALSE; + } + + /* Add a new database entry */ + this->comp_set = this->db->execute(this->db, &this->cid, + "INSERT INTO components (vendor_id, name, qualifier) " + "VALUES (?, ?, ?)", + DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1; + + printf("component '%s' %sinserted into database\n", print_cfn(cfn), + this->comp_set ? "" : "could not be "); + if (this->comp_set) + { + this->cfn = cfn; + } + else + { + cfn->destroy(cfn); + } + return this->comp_set; +} + +METHOD(attest_db_t, set_cid, bool, + private_attest_db_t *this, int cid) +{ + enumerator_t *e; + int vid, name, qualifier; + + if (this->comp_set) + { + printf("component has already been set\n"); + return FALSE; + } + this->cid = cid; + + e = this->db->query(this->db, "SELECT vendor_id, name, qualifier " + "FROM components WHERE id = ?", + DB_INT, cid, DB_INT, DB_INT, DB_INT); + if (e) + { + if (e->enumerate(e, &vid, &name, &qualifier)) + { + this->cfn = pts_comp_func_name_create(vid, name, qualifier); + this->comp_set = TRUE; + } + else + { + printf("no component found with cid %d\n", cid); + } + e->destroy(e); + } + return this->comp_set; +} + +METHOD(attest_db_t, set_directory, bool, + private_attest_db_t *this, char *dir, bool create) +{ + enumerator_t *e; + + if (this->dir_set) + { + printf("directory has already been set\n"); + return FALSE; + } + free(this->dir); + this->dir = strdup(dir); + + e = this->db->query(this->db, + "SELECT id FROM files WHERE type = 1 AND path = ?", + DB_TEXT, dir, DB_INT); + if (e) + { + if (e->enumerate(e, &this->did)) + { + this->dir_set = TRUE; + } + e->destroy(e); + } + if (this->dir_set) + { + return TRUE; + } + + if (!create) + { + printf("directory '%s' not found in database\n", dir); + return FALSE; + } + + /* Add a new database entry */ + this->dir_set = this->db->execute(this->db, &this->did, + "INSERT INTO files (type, path) VALUES (1, ?)", + DB_TEXT, dir) == 1; + + printf("directory '%s' %sinserted into database\n", dir, + this->dir_set ? "" : "could not be "); + + return this->dir_set; +} + +METHOD(attest_db_t, set_did, bool, + private_attest_db_t *this, int did) +{ + enumerator_t *e; + char *dir; + + if (this->dir_set) + { + printf("directory has already been set\n"); + return FALSE; + } + this->did = did; + + e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?", + DB_INT, did, DB_TEXT); + if (e) + { + if (e->enumerate(e, &dir)) + { + free(this->dir); + this->dir = strdup(dir); + this->dir_set = TRUE; + } + else + { + printf("no directory found with did %d\n", did); + } + e->destroy(e); + } + return this->dir_set; +} + +METHOD(attest_db_t, set_file, bool, + private_attest_db_t *this, char *file, bool create) +{ + enumerator_t *e; + + if (this->file_set) + { + printf("file has already been set\n"); + return FALSE; + } + this->file = strdup(file); + + e = this->db->query(this->db, "SELECT id FROM files WHERE path = ?", + DB_TEXT, file, DB_INT); + if (e) + { + if (e->enumerate(e, &this->fid)) + { + this->file_set = TRUE; + } + e->destroy(e); + } + if (this->file_set) + { + return TRUE; + } + + if (!create) + { + printf("file '%s' not found in database\n", file); + return FALSE; + } + + /* Add a new database entry */ + this->file_set = this->db->execute(this->db, &this->fid, + "INSERT INTO files (type, path) VALUES (0, ?)", + DB_TEXT, file) == 1; + + printf("file '%s' %sinserted into database\n", file, + this->file_set ? "" : "could not be "); + + return this->file_set; +} + +METHOD(attest_db_t, set_fid, bool, + private_attest_db_t *this, int fid) +{ + enumerator_t *e; + char *file; + + if (this->file_set) + { + printf("file has already been set\n"); + return FALSE; + } + this->fid = fid; + + e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?", + DB_INT, fid, DB_TEXT); + if (e) + { + if (e->enumerate(e, &file)) + { + this->file = strdup(file); + this->file_set = TRUE; + } + else + { + printf("no file found with fid %d\n", fid); + } + e->destroy(e); + } + return this->file_set; +} + +METHOD(attest_db_t, set_key, bool, + private_attest_db_t *this, chunk_t key, bool create) +{ + enumerator_t *e; + char *owner; + + if (this->key_set) + { + printf("key has already been set\n"); + return FALSE; + } + this->key = key; + + e = this->db->query(this->db, "SELECT id, owner FROM keys WHERE keyid= ?", + DB_BLOB, this->key, DB_INT, DB_TEXT); + if (e) + { + if (e->enumerate(e, &this->kid, &owner)) + { + free(this->owner); + this->owner = strdup(owner); + this->key_set = TRUE; + } + e->destroy(e); + } + if (this->key_set) + { + return TRUE; + } + + if (!create) + { + printf("key '%#B' not found in database\n", &this->key); + return FALSE; + } + + /* Add a new database entry */ + if (!this->owner) + { + this->owner = strdup(""); + } + this->key_set = this->db->execute(this->db, &this->kid, + "INSERT INTO keys (keyid, owner) VALUES (?, ?)", + DB_BLOB, this->key, DB_TEXT, this->owner) == 1; + + printf("key '%#B' %sinserted into database\n", &this->key, + this->key_set ? "" : "could not be "); + + return this->key_set; + +}; + +METHOD(attest_db_t, set_kid, bool, + private_attest_db_t *this, int kid) +{ + enumerator_t *e; + chunk_t key; + char *owner; + + if (this->key_set) + { + printf("key has already been set\n"); + return FALSE; + } + this->kid = kid; + + e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?", + DB_INT, kid, DB_BLOB, DB_TEXT); + if (e) + { + if (e->enumerate(e, &key, &owner)) + { + this->owner = strdup(owner); + this->key = chunk_clone(key); + this->key_set = TRUE; + } + else + { + printf("no key found with kid %d\n", kid); + } + e->destroy(e); + } + return this->key_set; + +}; + +METHOD(attest_db_t, set_product, bool, + private_attest_db_t *this, char *product, bool create) +{ + enumerator_t *e; + + if (this->product_set) + { + printf("product has already been set\n"); + return FALSE; + } + this->product = strdup(product); + + e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?", + DB_TEXT, product, DB_INT); + if (e) + { + if (e->enumerate(e, &this->pid)) + { + this->product_set = TRUE; + } + e->destroy(e); + } + if (this->product_set) + { + return TRUE; + } + + if (!create) + { + printf("product '%s' not found in database\n", product); + return FALSE; + } + + /* Add a new database entry */ + this->product_set = this->db->execute(this->db, &this->pid, + "INSERT INTO products (name) VALUES (?)", + DB_TEXT, product) == 1; + + printf("product '%s' %sinserted into database\n", product, + this->product_set ? "" : "could not be "); + + return this->product_set; +} + +METHOD(attest_db_t, set_pid, bool, + private_attest_db_t *this, int pid) +{ + enumerator_t *e; + char *product; + + if (this->product_set) + { + printf("product has already been set\n"); + return FALSE; + } + this->pid = pid; + + e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?", + DB_INT, pid, DB_TEXT); + if (e) + { + if (e->enumerate(e, &product)) + { + this->product = strdup(product); + this->product_set = TRUE; + } + else + { + printf("no product found with pid %d in database\n", pid); + } + e->destroy(e); + } + return this->product_set; +} + +METHOD(attest_db_t, set_algo, void, + private_attest_db_t *this, pts_meas_algorithms_t algo) +{ + this->algo = algo; +} + +METHOD(attest_db_t, set_owner, void, + private_attest_db_t *this, char *owner) +{ + free(this->owner); + this->owner = strdup(owner); +} + +METHOD(attest_db_t, list_components, void, + private_attest_db_t *this) +{ + enumerator_t *e; + pts_comp_func_name_t *cfn; + int cid, vid, name, qualifier, count = 0; + + if (this->kid) + { + e = this->db->query(this->db, + "SELECT c.id, c.vendor_id, c.name, c.qualifier " + "FROM components AS c " + "JOIN key_component AS kc ON c.id = kc.component " + "WHERE kc.key = ? ORDER BY c.vendor_id, c.name, c.qualifier", + DB_INT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT); + } + else + { + e = this->db->query(this->db, + "SELECT id, vendor_id, name, qualifier FROM components " + "ORDER BY vendor_id, name, qualifier", + DB_INT, DB_INT, DB_INT, DB_INT); + } + if (e) + { + while (e->enumerate(e, &cid, &vid, &name, &qualifier)) + { + cfn = pts_comp_func_name_create(vid, name, qualifier); + printf("%3d: %s\n", cid, print_cfn(cfn)); + cfn->destroy(cfn); + count++; + } + e->destroy(e); + + printf("%d component%s found", count, (count == 1) ? "" : "s"); + if (this->key_set) + { + printf(" for key %#B", &this->key); + } + printf("\n"); + } +} + +METHOD(attest_db_t, list_keys, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t keyid; + char *owner; + int kid, count = 0; + + if (this->cid) + { + e = this->db->query(this->db, + "SELECT k.id, k.keyid, k.owner FROM keys AS k " + "JOIN key_component AS kc ON k.id = kc.key " + "WHERE kc.component = ? ORDER BY k.keyid", + DB_INT, this->cid, DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &kid, &keyid, &owner)) + { + printf("%3d: %#B '%s'\n", kid, &keyid, owner); + count++; + } + e->destroy(e); + } + } + else + { + e = this->db->query(this->db, "SELECT id, keyid, owner FROM keys " + "ORDER BY keyid", + DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &kid, &keyid, &owner)) + { + printf("%3d: %#B '%s'\n", kid, &keyid, owner); + count++; + } + e->destroy(e); + } + } + + printf("%d key%s found", count, (count == 1) ? "" : "s"); + if (this->comp_set) + { + printf(" for component '%s'", print_cfn(this->cfn)); + } + printf("\n"); +} + +METHOD(attest_db_t, list_files, void, + private_attest_db_t *this) +{ + enumerator_t *e; + char *file, *file_type[] = { " ", "d", "r" }; + int fid, type, meas, meta, count = 0; + + if (this->pid) + { + e = this->db->query(this->db, + "SELECT f.id, f.type, f.path, pf.measurement, pf.metadata " + "FROM files AS f " + "JOIN product_file AS pf ON f.id = pf.file " + "WHERE pf.product = ? ORDER BY f.path", + DB_INT, this->pid, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &fid, &type, &file, &meas, &meta)) + { + type = (type < 0 || type > 2) ? 0 : type; + printf("%3d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ", + file_type[type], file); + count++; + } + e->destroy(e); + } + } + else + { + e = this->db->query(this->db, + "SELECT id, type, path FROM files " + "ORDER BY path", + DB_INT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &fid, &type, &file)) + { + type = (type < 0 || type > 2) ? 0 : type; + printf("%3d: %s %s\n", fid, file_type[type], file); + count++; + } + e->destroy(e); + } + } + + printf("%d file%s found", count, (count == 1) ? "" : "s"); + if (this->product_set) + { + printf(" for product '%s'", this->product); + } + printf("\n"); +} + +METHOD(attest_db_t, list_products, void, + private_attest_db_t *this) +{ + enumerator_t *e; + char *product; + int pid, meas, meta, count = 0; + + if (this->fid) + { + e = this->db->query(this->db, + "SELECT p.id, p.name, pf.measurement, pf.metadata " + "FROM products AS p " + "JOIN product_file AS pf ON p.id = pf.product " + "WHERE pf.file = ? ORDER BY p.name", + DB_INT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &pid, &product, &meas, &meta)) + { + printf("%3d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ", + product); + count++; + } + e->destroy(e); + } + } + else + { + e = this->db->query(this->db, "SELECT id, name FROM products " + "ORDER BY name", + DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &pid, &product)) + { + printf("%3d: %s\n", pid, product); + count++; + } + e->destroy(e); + } + } + + printf("%d product%s found", count, (count == 1) ? "" : "s"); + if (this->file_set) + { + printf(" for file '%s'", this->file); + } + printf("\n"); +} + +/** + * get the directory if there is one from the files tables + */ +static void get_directory(private_attest_db_t *this, int did, char **directory) +{ + enumerator_t *e; + char *dir; + + free(*directory); + *directory = strdup(""); + + if (did) + { + e = this->db->query(this->db, + "SELECT path from files WHERE id = ?", + DB_INT, did, DB_TEXT); + if (e) + { + if (e->enumerate(e, &dir)) + { + free(*directory); + *directory = strdup(dir); + } + e->destroy(e); + } + } +} + +static bool slash(char *directory, char *file) +{ + return *file != '/' && directory[max(0, strlen(directory)-1)] != '/'; +} + +METHOD(attest_db_t, list_hashes, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t hash; + char *file, *dir, *product; + int fid, fid_old = 0, did, did_old = 0, count = 0; + + dir = strdup(""); + + if (this->pid && this->fid) + { + e = this->db->query(this->db, + "SELECT hash FROM file_hashes " + "WHERE algo = ? AND file = ? AND directory = ? AND product = ?", + DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did, + DB_INT, this->pid, DB_BLOB); + if (e) + { + while (e->enumerate(e, &hash)) + { + if (this->fid != fid_old) + { + printf("%3d: %s%s%s\n", this->fid, this->dir, + slash(this->dir, this->file) ? "/" : "", this->file); + fid_old = this->fid; + } + printf(" %#B\n", &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for product '%s'\n", count, + hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + (count == 1) ? "" : "s", this->product); + } + } + else if (this->pid) + { + e = this->db->query(this->db, + "SELECT f.id, f. f.path, fh.hash, fh.directory " + "FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "WHERE fh.algo = ? AND fh.product = ? " + "ORDER BY fh.directory, f.path", + DB_INT, this->algo, DB_INT, this->pid, + DB_INT, DB_TEXT, DB_BLOB, DB_INT); + if (e) + { + while (e->enumerate(e, &fid, &file, &hash, &did)) + { + if (fid != fid_old || did != did_old) + { + if (did != did_old) + { + get_directory(this, did, &dir); + } + printf("%3d: %s%s%s\n", fid, + dir, slash(dir, file) ? "/" : "", file); + fid_old = fid; + did_old = did; + } + printf(" %#B\n", &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for product '%s'\n", count, + hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + (count == 1) ? "" : "s", this->product); + } + } + else if (this->fid) + { + e = this->db->query(this->db, + "SELECT p.name, fh.hash, fh.directory " + "FROM file_hashes AS fh " + "JOIN products AS p ON p.id = fh.product " + "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?" + "ORDER BY p.name", + DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did, + DB_TEXT, DB_BLOB, DB_INT); + if (e) + { + while (e->enumerate(e, &product, &hash, &did)) + { + printf("%#B '%s'\n", &hash, product); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for file '%s%s%s'\n", + count, hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + (count == 1) ? "" : "s", this->dir, + slash(this->dir, this->file) ? "/" : "", this->file); + } + } + else + { + e = this->db->query(this->db, + "SELECT f.id, f.path, p.name, fh.hash, fh.directory " + "FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "JOIN products AS p ON p.id = fh.product " + "WHERE fh.algo = ? " + "ORDER BY fh.directory, f.path, p.name", + DB_INT, this->algo, + DB_INT, DB_TEXT, DB_TEXT, DB_BLOB, DB_INT); + if (e) + { + while (e->enumerate(e, &fid, &file, &product, &hash, &did)) + { + if (fid != fid_old || did != did_old) + { + if (did != did_old) + { + get_directory(this, did, &dir); + did_old = did; + } + printf("%3d: %s%s%s\n", fid, + dir, slash(dir, file) ? "/" : "", file); + fid_old = fid; + } + printf(" %#B '%s'\n", &hash, product); + count++; + } + e->destroy(e); + + printf("%d %N value%s found\n", count, hash_algorithm_names, + pts_meas_algo_to_hash(this->algo), (count == 1) ? "" : "s"); + } + } + free(dir); +} + +METHOD(attest_db_t, list_measurements, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t hash, keyid; + pts_comp_func_name_t *cfn; + char *owner; + int seq_no, pcr, vid, name, qualifier; + int cid, cid_old = 0, kid, kid_old = 0, count = 0; + + if (this->kid && this->cid) + { + e = this->db->query(this->db, + "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner " + "FROM component_hashes AS ch " + "JOIN keys AS k ON k.id = ch.key " + "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? " + "ORDER BY seq_no", + DB_INT, this->algo, DB_INT, this->kid, DB_INT, this->cid, + DB_INT, DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &seq_no, &pcr, &hash, &owner)) + { + if (this->kid != kid_old) + { + printf("%3d: %#B '%s'\n", this->kid, &this->key, owner); + kid_old = this->kid; + } + printf("%5d %02d %#B\n", seq_no, pcr, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for component '%s'\n", count, + hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + (count == 1) ? "" : "s", print_cfn(this->cfn)); + } + } + else if (this->cid) + { + e = this->db->query(this->db, + "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner " + "FROM component_hashes AS ch " + "JOIN keys AS k ON k.id = ch.key " + "WHERE ch.algo = ? AND ch.component = ? " + "ORDER BY keyid, seq_no", + DB_INT, this->algo, DB_INT, this->cid, + DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &seq_no, &pcr, &hash, &kid, &keyid, &owner)) + { + if (kid != kid_old) + { + printf("%3d: %#B '%s'\n", kid, &keyid, owner); + kid_old = kid; + } + printf("%5d %02d %#B\n", seq_no, pcr, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for component '%s'\n", count, + hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + (count == 1) ? "" : "s", print_cfn(this->cfn)); + } + + } + else if (this->kid) + { + e = this->db->query(this->db, + "SELECT ch.seq_no, ch.pcr, ch.hash, " + "c.id, c.vendor_id, c.name, c.qualifier " + "FROM component_hashes AS ch " + "JOIN components AS c ON c.id = ch.component " + "WHERE ch.algo = ? AND ch.key = ? " + "ORDER BY vendor_id, name, qualifier, seq_no", + DB_INT, this->algo, DB_INT, this->kid, DB_INT, DB_INT, DB_BLOB, + DB_INT, DB_INT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &seq_no, &pcr, &hash, &cid, &vid, &name, + &qualifier)) + { + if (cid != cid_old) + { + cfn = pts_comp_func_name_create(vid, name, qualifier); + printf("%3d: %s\n", cid, print_cfn(cfn)); + cfn->destroy(cfn); + cid_old = cid; + } + printf("%5d %02d %#B\n", seq_no, pcr, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for key %#B '%s'\n", count, + hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + (count == 1) ? "" : "s", &this->key, this->owner); + } + } +} + +METHOD(attest_db_t, add, bool, + private_attest_db_t *this) +{ + bool success = FALSE; + + if (this->kid && this->cid) + { + success = this->db->execute(this->db, NULL, + "INSERT INTO key_component (key, component) VALUES (?, ?)", + DB_UINT, this->kid, DB_UINT, this->cid) == 1; + + printf("key/component pair (%d/%d) %sinserted into database\n", + this->kid, this->cid, success ? "" : "could not be "); + } + return success; +} + +METHOD(attest_db_t, delete, bool, + private_attest_db_t *this) +{ + bool success; + + if (this->pid && (this->fid || this->did)) + { + printf("deletion of product/file entries not supported yet\n"); + return FALSE; + } + + if (this->kid && this->cid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM key_component " + "WHERE key = ? AND component = ?", + DB_UINT, this->kid, DB_UINT, this->cid) > 0; + + printf("key/component pair (%d/%d) %sdeleted from database\n", + this->kid, this->cid, success ? "" : "could not be "); + return success; + } + + if (this->cid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM components WHERE id = ?", + DB_UINT, this->cid) > 0; + + printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn), + success ? "" : "could not be "); + return success; + } + + if (this->did) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM files WHERE type = 1 AND id = ?", + DB_UINT, this->did) > 0; + + printf("directory '%s' %sdeleted from database\n", this->dir, + success ? "" : "could not be "); + return success; + } + + if (this->fid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM files WHERE id = ?", + DB_UINT, this->fid) > 0; + + printf("file '%s' %sdeleted from database\n", this->file, + success ? "" : "could not be "); + return success; + } + + if (this->kid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM keys WHERE id = ?", + DB_UINT, this->kid) > 0; + + printf("key %#B %sdeleted from database\n", &this->key, + success ? "" : "could not be "); + return success; + } + if (this->pid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM products WHERE id = ?", + DB_UINT, this->pid) > 0; + + printf("product '%s' %sdeleted from database\n", this->product, + success ? "" : "could not be "); + return success; + } + + printf("empty delete command\n"); + return FALSE; +} + +METHOD(attest_db_t, destroy, void, + private_attest_db_t *this) +{ + DESTROY_IF(this->db); + DESTROY_IF(this->cfn); + free(this->product); + free(this->file); + free(this->dir); + free(this->owner); + free(this->key.ptr); + free(this); +} + +/** + * Described in header. + */ +attest_db_t *attest_db_create(char *uri) +{ + private_attest_db_t *this; + + INIT(this, + .public = { + .set_component = _set_component, + .set_cid = _set_cid, + .set_directory = _set_directory, + .set_did = _set_did, + .set_file = _set_file, + .set_fid = _set_fid, + .set_key = _set_key, + .set_kid = _set_kid, + .set_product = _set_product, + .set_pid = _set_pid, + .set_algo = _set_algo, + .set_owner = _set_owner, + .list_products = _list_products, + .list_files = _list_files, + .list_components = _list_components, + .list_keys = _list_keys, + .list_hashes = _list_hashes, + .list_measurements = _list_measurements, + .add = _add, + .delete = _delete, + .destroy = _destroy, + }, + .dir = strdup(""), + .algo = PTS_MEAS_ALGO_SHA256, + .db = lib->db->create(lib->db, uri), + ); + + if (!this->db) + { + fprintf(stderr, "opening database failed.\n"); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libpts/plugins/imv_attestation/attest_db.h b/src/libpts/plugins/imv_attestation/attest_db.h new file mode 100644 index 000000000..9c9a9dcba --- /dev/null +++ b/src/libpts/plugins/imv_attestation/attest_db.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 attest_db_t attest_db + * @{ @ingroup attest_db + */ + +#ifndef ATTEST_DB_H_ +#define ATTEST_DB_H_ + +#include <pts/pts_meas_algo.h> + +#include <library.h> + +typedef struct attest_db_t attest_db_t; + +/** + * Attestation database object + */ +struct attest_db_t { + + /** + * Set functional component to be queried + * + * @param comp functional component + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_component)(attest_db_t *this, char *comp, bool create); + + /** + * Set primary key of the functional component to be queried + * + * @param fid primary key of functional component + * @return TRUE if successful + */ + bool (*set_cid)(attest_db_t *this, int fid); + + /** + * Set directory to be queried + * + * @param dir directory + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_directory)(attest_db_t *this, char *dir, bool create); + + /** + * Set primary key of the directory to be queried + * + * @param did primary key of directory + * @return TRUE if successful + */ + bool (*set_did)(attest_db_t *this, int did); + + /** + * Set measurement file to be queried + * + * @param file measurement file + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_file)(attest_db_t *this, char *file, bool create); + + /** + * Set primary key of the measurement file to be queried + * + * @param fid primary key of measurement file + * @return TRUE if successful + */ + bool (*set_fid)(attest_db_t *this, int fid); + + /** + * Set functional component to be queried + * + * @param key AIK + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_key)(attest_db_t *this, chunk_t key, bool create); + + /** + * Set primary key of the AIK to be queried + * + * @param kid primary key of AIK + * @return TRUE if successful + */ + bool (*set_kid)(attest_db_t *this, int kid); + + /** + * Set software product to be queried + * + * @param product software product + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_product)(attest_db_t *this, char *product, bool create); + + /** + * Set primary key of the software product to be queried + * + * @param pid primary key of software product + * @return TRUE if successful + */ + bool (*set_pid)(attest_db_t *this, int pid); + + /** + * Set measurement hash algorithm + * + * @param algo hash algorithm + */ + void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo); + + /** + * Set owner [user/host] of an AIK + * + * @param owner user/host name + * @return TRUE if successful + */ + void (*set_owner)(attest_db_t *this, char *owner); + + /** + * List all products stored in the database + */ + void (*list_products)(attest_db_t *this); + + /** + * List selected files stored in the database + */ + void (*list_files)(attest_db_t *this); + + /** + * List all components stored in the database + */ + void (*list_components)(attest_db_t *this); + + /** + * List all AIKs stored in the database + */ + void (*list_keys)(attest_db_t *this); + + /** + * List selected measurement hashes stored in the database + */ + void (*list_hashes)(attest_db_t *this); + + /** + * List selected component measurement stored in the database + */ + void (*list_measurements)(attest_db_t *this); + + /** + * Add an entry to the database + */ + bool (*add)(attest_db_t *this); + + /** + * Delete an entry from the database + */ + bool (*delete)(attest_db_t *this); + + /** + * Destroy attest_db_t object + */ + void (*destroy)(attest_db_t *this); + +}; + +/** + * Create an attest_db_t instance + * + * @param uri database URI + */ +attest_db_t* attest_db_create(char *uri); + +#endif /** ATTEST_DB_H_ @}*/ diff --git a/src/libpts/plugins/imv_attestation/attest_usage.c b/src/libpts/plugins/imv_attestation/attest_usage.c new file mode 100644 index 000000000..e58f821e0 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/attest_usage.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 <stdio.h> + +#include "attest_usage.h" + +/** + * print attest usage info + */ +void usage(void) +{ + printf("\ +Usage:\n\ + ipsec attest --files|--products|--keys|--hashes [options]\n\ + \n\ + ipsec attest --components|-keys|--measurements|--add|--del [options]\n\ + \n\ + ipsec attest --files [--product <name>|--pid <id>]\n\ + Show a list of files with a software product name or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --products [--file <path>|--fid <id>]\n\ + Show a list of supported software products with a file path or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --hashes [--sha1|--sha256|--sha384] [--product <name>|--pid <id>]\n\ + Show a list of measurement hashes for a given software product or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --hashes [--sha1|--sha256|--sha384] [--file <path>|--fid <id>]\n\ + Show a list of measurement hashes for a given file or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --components [--key <digest>|--kid <id>]\n\ + Show a list of components with an AIK digest or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --keys [--components <cfn>|--cid <id>]\n\ + Show a list of AIK key digests with a component or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --measurements [--sha1|--sha256|--sha384] [--component <cfn>|--cid <id>]\n\ + Show a list of component measurements for a given component or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --measurements [--sha1|--sha256|--sha384] [--key <digest>|--kid <id>|--aik <path>]\n\ + Show a list of component measurements for a given AIK or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --add --file <path>|--dir <path>|--product <name>|--component <cfn>\n\ + Add a file, directory, product or component entry\n\ + Component <cfn> entries must be of the form <vendor_id>/<name>-<qualifier>\n\ + \n\ + ipsec attest --add [--owner <name>] --key <digest>|--aik <path>\n\ + Add an AIK public key digest entry preceded by an optional owner name\n\ + \n\ + ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>\n\ + Delete a file or directory entry referenced either by value or primary key\n\ + \n\ + ipsec attest --del --product <name>|--pid <id>|--component <cfn>|--cid <id>\n\ + Delete a product or component entry referenced either by value or primary key\n\ + \n\ + ipsec attest --del --key <digest>|--kid <id>|--aik <path>\n\ + Delete an AIK entry referenced either by value or primary key\n\ + \n"); +} + diff --git a/src/libpts/plugins/imv_attestation/attest_usage.h b/src/libpts/plugins/imv_attestation/attest_usage.h new file mode 100644 index 000000000..bce801e9d --- /dev/null +++ b/src/libpts/plugins/imv_attestation/attest_usage.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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. + */ + +#ifndef ATTEST_USAGE_H_ +#define ATTEST_USAGE_H_ + +/** + * print attest usage info + */ +void usage(void); + + +#endif /* ATTEST_USAGE_H_ */ diff --git a/src/libimcv/plugins/imv_attestation/data.sql b/src/libpts/plugins/imv_attestation/data.sql index 60620dd45..e6e03627a 100644 --- a/src/libimcv/plugins/imv_attestation/data.sql +++ b/src/libpts/plugins/imv_attestation/data.sql @@ -36,272 +36,356 @@ INSERT INTO products ( 'Gentoo Base System release 1.12.11.1 i686' ); +INSERT INTO products ( + name +) VALUES ( + 'Ubuntu 11.10 i686' +); + /* Files */ -INSERT INTO files ( +INSERT INTO files ( /* 1 */ type, path - ) VALUES ( +) VALUES ( 0, '/lib/i386-linux-gnu/libdl.so.2' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, '/lib/x86_64-linux-gnu/libdl.so.2' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, '/lib/libdl.so.2' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, '/sbin/iptables' ); -INSERT INTO files ( +INSERT INTO files ( /* 5 */ type, path - ) VALUES ( +) VALUES ( 0, '/lib/libxtables.so.5' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, '/lib/libxtables.so.2' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 1, '/lib/xtables/' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libxt_udp.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libxt_tcp.so' ); -INSERT INTO files ( +INSERT INTO files ( /* 10 */ type, path - ) VALUES ( +) VALUES ( 0, 'libxt_esp.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libxt_policy.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libxt_conntrack.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libipt_SNAT.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libipt_DNAT.so' ); -INSERT INTO files ( +INSERT INTO files ( /* 15 */ type, path - ) VALUES ( +) VALUES ( 0, 'libipt_MASQUERADE.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libipt_LOG.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, '/sbin/ip6tables' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libip6t_LOG.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 0, 'libxt_mark.so' ); -INSERT INTO files ( +INSERT INTO files ( /* 20 */ type, path - ) VALUES ( +) VALUES ( 0, 'libxt_MARK.so' ); INSERT INTO files ( type, path - ) VALUES ( +) VALUES ( 1, '/lib/iptables' ); +INSERT INTO files ( + type, path +) VALUES ( + 0, '/etc/tnc_config' +); + /* Product-File */ INSERT INTO product_file ( - product, file + product, file, measurement +) VALUES ( + 1, 1, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 1, 4, 1 +); + +INSERT INTO product_file ( + product, file, measurement ) VALUES ( - 1, 1 + 1, 5, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 1, 4 + 1, 7, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 1, 5 + 1, 17, 1 ); INSERT INTO product_file ( - product, file + product, file, metadata ) VALUES ( - 1, 7 + 1, 22, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 1, 17 + 2, 2, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 2, 2 + 2, 4, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 2, 4 + 2, 5, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 2, 5 + 2, 7, 1 ); INSERT INTO product_file ( - product, file + product, file, metadata ) VALUES ( - 2, 7 + 2, 22, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 3, 3 + 3, 3, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 3, 4 + 3, 4, 1 ); INSERT INTO product_file ( - product, file + product, file, metadata ) VALUES ( - 4, 3 + 3, 22, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 4, 4 + 4, 3, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 4, 6 + 4, 4, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 4, 7 + 4, 6, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 5, 3 + 4, 7, 1 ); INSERT INTO product_file ( - product, file + product, file, metadata ) VALUES ( - 5, 4 + 4, 22, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 5, 6 + 5, 3, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 5, 7 + 5, 4, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 6, 3 + 5, 6, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 6, 4 + 5, 7, 1 ); INSERT INTO product_file ( - product, file + product, file, metadata ) VALUES ( - 6, 17 + 5, 22, 1 ); INSERT INTO product_file ( - product, file + product, file, measurement ) VALUES ( - 6, 21 + 6, 3, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 6, 4, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 6, 17, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 6, 21, 1 +); + +INSERT INTO product_file ( + product, file, metadata +) VALUES ( + 6, 22, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 7, 1, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 7, 4, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 7, 5, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 7, 7, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 7, 17, 1 +); + +INSERT INTO product_file ( + product, file, metadata +) VALUES ( + 7, 22, 1 ); /* File Hashes */ @@ -327,6 +411,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, product, algo, hash ) VALUES ( + 1, 7, 32768, X'40763935cdea25119002c42f984b994d8d2a6d75' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 7, 16384, X'27c4f867d3f994a361e0b25d7846b3698d29f82b38662f233a97cafc60c44189' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 7, 8192, X'301dad8829308f5a68c603a87bf961b91365f0346ac2f322de3ddcbb4645f56c0e6d2dc503ec2abff8fe8e895ce9304d' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( 2, 2, 32768, X'2a4047437e6fb346e2d854fc415e16b80e75bf6b' ); @@ -489,6 +591,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, product, algo, hash ) VALUES ( + 4, 7, 32768, X'ff6deca0eeb7a257205c5f0ab5f5d821ea184098' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 4, 7, 16384, X'5c84fdf7c529d3c65a001587eda641fe489f83961a621fe514e7852a842690d6' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 4, 7, 8192, X'8bd699f85f5b3efb27204b4699c518f871ef245d03b4bf8d1cc00456025017546030c2f493525754cffcd24cdbc03b21' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( 5, 1, 32768, X'7a3ca72158e60b0c91e48a420848f1b693aea26c' ); @@ -525,6 +645,25 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, product, algo, hash ) VALUES ( + 5, 7, 32768, X'7a3ca72158e60b0c91e48a420848f1b693aea26c' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 5, 7, 16384, X'f9693c7d36c087d51f5012897fa0e8bb94081854d080c84f831f4d693d22f645' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 5, 7, 8192, X'4ec135e54c8840ab575fcdf00c66f996f763863ad30800b0f0a0b02e7899697d6ab9ccfe185ccbc16c19f38d0a27becb' +); + + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( 6, 4, 32768, X'92e66ae282947f66544682039a33fd1dbd402244' ); @@ -579,6 +718,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 8, 7, 7, 32768, X'11ce3b45feb3e66a75490d42ba95071ac6f40a7f' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 8, 7, 7, 16384, X'468ef70f19372bc4a2b1805ffa3621515061fc19fa361374788bd362d638ac02' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 8, 7, 7, 8192, X'63076ae505ce52c37878c9b6891ac516320046403aec25bf347c7011c2d28d5db7e2946d1fae3006ab4ef43716ff4558' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 8, 21, 6, 32768, X'010873de0d682a26e1c6795dd4992248cc47cdd1' ); @@ -633,6 +790,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 9, 7, 7, 32768, X'1d740abd38f9f4bc81ca434a0e25b6e21704248b' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 9, 7, 7, 16384, X'e26bb7175956dc8747a81431e810f830413b6c63756bf5156ab51367fe4f48a0' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 9, 7, 7, 8192, X'5d3637413b9e318d0e0be6a9da86121062b99d1bdb084dfda4222baa71b250de644b4024281760b4eae926e03fac4fdb' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 9, 21, 6, 32768, X'e1df4f3949b09c25e15b9c9b7088a60d683903a8' ); @@ -669,6 +844,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 10, 7, 7, 32768, X'339a58a1b313830c3cc74cb3fb52a5b8152f44e6' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 10, 7, 7, 16384, X'789f2c6a9382bb342964a12947ddf84735d3e3ed3aefbae407098738cdf7c686' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 10, 7, 7, 8192, X'858310a6e4b6311c491c4370990bfd6b9f03a49bb5ddf45b0d788f7043f130016e11be6bd95db66e49e2906a87adf8cb' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 10, 21, 6, 32768, X'87df2d01b85d8354819b431bae0a0a65bfc5d2db' ); @@ -705,6 +898,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 11, 7, 7, 32768, X'2d32ef93126abf8c660d57c67e5076c6394cabe8' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 11, 7, 7, 16384, X'ced29aca7fc2dd0b01d5d544dfb2e1640a6a79c657f589e7dd6636cfd63eda3b' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 11, 7, 7, 8192, X'a2d33fa2d0ee7bffa5e628f88ccb83cd61bb4c5fe6d2edb8b853b83d8c43f498fa6e8da70510f0a1a3ddb36060bbd4d8' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 12, 7, 1, 32768, X'6c0b2df4fc4c9122b5762ae140d53fdd1cf9e89b' ); @@ -723,6 +934,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 12, 7, 7, 32768, X'6c0b2df4fc4c9122b5762ae140d53fdd1cf9e89b' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 12, 7, 7, 16384, X'53c3f2bd5aaf8ef4c40f9af92a67621f5e67840b5ff2db67d1bccbcb56f7eef1' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 12, 7, 7, 8192, X'1a4a6d91bda3ce59e6c444ccc1e758c9c6f0e223fd8c5aac369260cdfa83081c0e8f3753f100490910ec161902f10ba7' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 13, 7, 1, 32768, X'e2f7b92abda769f82796f57a29801870585dcea3' ); @@ -741,6 +970,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 13, 7, 7, 32768, X'e2f7b92abda769f82796f57a29801870585dcea3' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 13, 7, 7, 16384, X'6d3fe67a040dbb469ef498b26cece45806cb7ca04787bba53b7ba1c18e2abd0a' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 13, 7, 7, 8192, X'014852b73cd3eabfa955b7bd56b269d5a0590a2770cf3d656b3d68dbad30884327fc81ff96c6f661c9c4189c3aefa346' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 14, 7, 1, 32768, X'160d2b04d11eb225fb148615b699081869e15b6c' ); @@ -759,6 +1006,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 14, 7, 7, 32768, X'160d2b04d11eb225fb148615b699081869e15b6c' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 14, 7, 7, 16384, X'1f5a2ceae1418f9c1fbf51eb7d84f74d488908cde5931a5461746d1e24682a25' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 14, 7, 7, 8192, X'f701cb25b0e9a9f32d3bba9b274ca0e8838363d13b7283b842d6c9673442890e538127c3b64ca4b177de1d243b44cf0d' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 15, 7, 1, 32768, X'5a0d07ab036603a76759e5f61f7d04f2d3c056cc' ); @@ -777,6 +1042,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 15, 7, 7, 32768, X'5a0d07ab036603a76759e5f61f7d04f2d3c056cc' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 15, 7, 7, 16384, X'85491714e860062c441ff50d93ad79350449596b89b2e409b513c2d883321c9d' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 15, 7, 7, 8192, X'8038830a994c779bc200e844d8768280feca9dd5d58de6cd359b87cc68846799edfd16e36e83002da4bb309cfd3b353d' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 16, 7, 1, 32768, X'd6c8dfbaae7ab28b5cef2626a2af3f99a6ea4365' ); @@ -793,6 +1076,24 @@ INSERT INTO file_hashes ( ); INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 16, 7, 7, 32768, X'd6c8dfbaae7ab28b5cef2626a2af3f99a6ea4365' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 16, 7, 7, 16384, X'd0d6f784e937227cce99e3be860be078d0397a6fb5a5bc9d95a19ef855609dbc' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 16, 7, 7, 8192, X'4be6e7978a6e4fb8a792815f2bbe28c2e66276401fb98ca90e49a5c2f2c94a1c7aac635d501d35d1db0fd53a0cb9d0fa' +); + +INSERT INTO file_hashes ( file, product, algo, hash ) VALUES ( 17, 1, 32768, X'8a7c41167bc0fcc1dec8329a868ba265c23857f5' @@ -829,6 +1130,24 @@ INSERT INTO file_hashes ( ); INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 17, 7, 32768, X'8a7c41167bc0fcc1dec8329a868ba265c23857f5' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 17, 7, 16384, X'f8eb857d7bb850f44c15363ba699442c2810663ac5a83a5f49e06e0fd8144b0e' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 17, 7, 8192, X'f40cb6e557ab18d70080e7995e3f96cc272842e822bf52bc1c59075313c2cd832f96cf03a8524905f3d3f7a61441c651' +); + +INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( 18, 7, 1, 32768, X'23296f48276e160b6d99b1b42a9114df720bb1ab' @@ -849,6 +1168,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 18, 7, 7, 32768, X'23296f48276e160b6d99b1b42a9114df720bb1ab' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 18, 7, 7, 16384, X'78cd0a598080e31453f477e8d8a12ec794e859f4076ed92e53d2053d6d16762c' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 18, 7, 7, 8192, X'4da3955f1fd968ecf95cff825d42715b544e577f28f411a020a270834235125bc0c8872bac8dd3466349ac8ab0aa2d74' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 19, 7, 1, 32768, X'd537d437f058136eb3d7be517dbe7647b623c619' ); @@ -867,6 +1204,24 @@ INSERT INTO file_hashes ( INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( + 19, 7, 7, 32768, X'd537d437f058136eb3d7be517dbe7647b623c619' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 19, 7, 7, 16384, X'6a837037ad3fc4d06270d99cee2714dcf96b91aeb54d3483009219337961f834' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 19, 7, 7, 8192, X'7b5b16840da590a995fab23533f41982c5b136bff8e9b9a90b3c919a12cee20d312091455057a8bba9d9fbe314e6203d' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( 20, 7, 1, 32768, X'f9e3531abb67a020cf667d46ca823675dd0a0dd4' ); @@ -882,3 +1237,69 @@ INSERT INTO file_hashes ( 20, 7, 1, 8192, X'84200bd318bb022915150842ddf4002e061ef593604ad0d07021dc662cc40bfa749cce084ddf25d0e5137f6380f613d8' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 20, 7, 7, 32768, X'f9e3531abb67a020cf667d46ca823675dd0a0dd4' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 20, 7, 7, 16384, X'569bafa2dabbcfa0ba9c7c411eacfeb8930f9d856a1a43cf8aa3662a67c13e35' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 20, 7, 7, 8192, X'84200bd318bb022915150842ddf4002e061ef593604ad0d07021dc662cc40bfa749cce084ddf25d0e5137f6380f613d8' +); + +/* AIKs */ + +INSERT INTO keys ( + keyid, owner +) VALUES ( + X'b772a6730776b9f028e5adfccd40b55c320a13b6', 'Andreas, merthyr (Fujitsu Siemens Lifebook S6420)' +); + +/* Components */ + +INSERT INTO components ( + vendor_id, name, qualifier +) VALUES ( + 36906, 1, 33 /* ITA TGRUB */ +); + +INSERT INTO components ( + vendor_id, name, qualifier +) VALUES ( + 36906, 2, 33 /* ITA TBOOT */ +); + +INSERT INTO components ( + vendor_id, name, qualifier +) VALUES ( + 36906, 3, 33 /* ITA IMA */ +); + +/* AIK Component */ + +INSERT INTO key_component ( + key, component, depth, seq_no +) VALUES ( + 2, 2, 0, 1 +); + +INSERT INTO key_component ( + key, component, depth, seq_no +) VALUES ( + 1, 3, 0, 1 +); + +INSERT INTO key_component ( + key, component, depth, seq_no +) VALUES ( + 1, 2, 0, 2 +); + diff --git a/src/libpts/plugins/imv_attestation/imv_attestation.c b/src/libpts/plugins/imv_attestation/imv_attestation.c new file mode 100644 index 000000000..6bd5984e0 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/imv_attestation.c @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "imv_attestation_state.h" +#include "imv_attestation_process.h" +#include "imv_attestation_build.h" + +#include <imv/imv_agent.h> +#include <pa_tnc/pa_tnc_msg.h> +#include <ietf/ietf_attr.h> +#include <ietf/ietf_attr_pa_tnc_error.h> +#include <ietf/ietf_attr_product_info.h> + +#include <libpts.h> + +#include <pts/pts.h> +#include <pts/pts_database.h> +#include <pts/pts_creds.h> + +#include <tcg/tcg_attr.h> + +#include <tncif_pa_subtypes.h> + +#include <pen/pen.h> +#include <debug.h> +#include <credentials/credential_manager.h> +#include <utils/linked_list.h> + +/* IMV definitions */ + +static const char imv_name[] = "Attestation"; + +#define IMV_VENDOR_ID PEN_TCG +#define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS + +static imv_agent_t *imv_attestation; + +/** + * Supported PTS measurement algorithms + */ +static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE; + +/** + * Supported PTS Diffie Hellman Groups + */ +static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE; + +/** + * PTS file measurement database + */ +static pts_database_t *pts_db; + +/** + * PTS credentials + */ +static pts_creds_t *pts_creds; + +/** + * PTS credential manager + */ +static credential_manager_t *pts_credmgr; + +/** + * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, + TNC_Version min_version, + TNC_Version max_version, + TNC_Version *actual_version) +{ + char *hash_alg, *dh_group, *uri, *cadir; + + if (imv_attestation) + { + DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); + return TNC_RESULT_ALREADY_INITIALIZED; + } + if (!pts_meas_algo_probe(&supported_algorithms) || + !pts_dh_group_probe(&supported_dh_groups)) + { + return TNC_RESULT_FATAL; + } + imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE, + imv_id, actual_version); + if (!imv_attestation) + { + return TNC_RESULT_FATAL; + } + + libpts_init(); + + if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1) + { + DBG1(DBG_IMV, "no common IF-IMV version"); + return TNC_RESULT_NO_COMMON_VERSION; + } + + hash_alg = lib->settings->get_str(lib->settings, + "libimcv.plugins.imv-attestation.hash_algorithm", "sha256"); + dh_group = lib->settings->get_str(lib->settings, + "libimcv.plugins.imv-attestation.dh_group", "ecp256"); + + if (!pts_meas_algo_update(hash_alg, &supported_algorithms) || + !pts_dh_group_update(dh_group, &supported_dh_groups)) + { + return TNC_RESULT_FATAL; + } + + /* create a PTS credential manager */ + pts_credmgr = credential_manager_create(); + + /* create PTS credential set */ + cadir = lib->settings->get_str(lib->settings, + "libimcv.plugins.imv-attestation.cadir", NULL); + pts_creds = pts_creds_create(cadir); + if (pts_creds) + { + pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds)); + } + + /* attach file measurement database */ + uri = lib->settings->get_str(lib->settings, + "libimcv.plugins.imv-attestation.database", NULL); + pts_db = pts_database_create(uri); + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imv_state_t *state; + + if (!imv_attestation) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imv_attestation_state_create(connection_id); + return imv_attestation->create_state(imv_attestation, state); + case TNC_CONNECTION_STATE_DELETE: + return imv_attestation->delete_state(imv_attestation, connection_id); + case TNC_CONNECTION_STATE_HANDSHAKE: + default: + return imv_attestation->change_state(imv_attestation, connection_id, + new_state, NULL); + } +} + +static TNC_Result send_message(TNC_ConnectionID connection_id) +{ + pa_tnc_msg_t *msg; + pa_tnc_attr_t *attr; + imv_state_t *state; + imv_attestation_state_t *attestation_state; + TNC_Result result; + linked_list_t *attr_list; + enumerator_t *enumerator; + + if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imv_attestation_state_t*)state; + attr_list = linked_list_create(); + + if (imv_attestation_build(attr_list, attestation_state, supported_algorithms, + supported_dh_groups, pts_db)) + { + if (attr_list->get_count(attr_list)) + { + msg = pa_tnc_msg_create(); + + /* move PA-TNC attributes to PA-TNC message */ + enumerator = attr_list->create_enumerator(attr_list); + while (enumerator->enumerate(enumerator, &attr)) + { + msg->add_attribute(msg, attr); + } + enumerator->destroy(enumerator); + + msg->build(msg); + result = imv_attestation->send_message(imv_attestation, + connection_id, FALSE, 0, TNC_IMCID_ANY, + msg->get_encoding(msg)); + msg->destroy(msg); + } + else + { + result = TNC_RESULT_SUCCESS; + } + attr_list->destroy(attr_list); + } + else + { + attr_list->destroy_offset(attr_list, offsetof(pa_tnc_attr_t, destroy)); + result = TNC_RESULT_FATAL; + } + + return result; +} + +static TNC_Result receive_message(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_UInt32 msg_flags, + chunk_t msg, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id) +{ + pa_tnc_msg_t *pa_tnc_msg; + pa_tnc_attr_t *attr; + linked_list_t *attr_list; + imv_state_t *state; + imv_attestation_state_t *attestation_state; + pts_t *pts; + enumerator_t *enumerator; + TNC_Result result; + + if (!imv_attestation) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + + /* get current IMV state */ + if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imv_attestation_state_t*)state; + pts = attestation_state->get_pts(attestation_state); + + /* parse received PA-TNC message and automatically handle any errors */ + result = imv_attestation->receive_message(imv_attestation, state, msg, + msg_vid, msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg); + + /* no parsed PA-TNC attributes available if an error occurred */ + if (!pa_tnc_msg) + { + return result; + } + + /* preprocess any IETF standard error attributes */ + result = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg) ? + TNC_RESULT_FATAL : TNC_RESULT_SUCCESS; + + attr_list = linked_list_create(); + + /* analyze PA-TNC attributes */ + enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->get_vendor_id(attr) == PEN_IETF) + { + if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) + { + ietf_attr_pa_tnc_error_t *error_attr; + pen_t error_vendor_id; + pa_tnc_error_code_t error_code; + chunk_t msg_info; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; + error_vendor_id = error_attr->get_vendor_id(error_attr); + + if (error_vendor_id == PEN_TCG) + { + error_code = error_attr->get_error_code(error_attr); + msg_info = error_attr->get_msg_info(error_attr); + + DBG1(DBG_IMV, "received TCG-PTS error '%N'", + pts_error_code_names, error_code); + DBG1(DBG_IMV, "error information: %B", &msg_info); + + result = TNC_RESULT_FATAL; + } + } + else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION) + { + ietf_attr_product_info_t *attr_cast; + char *platform_info; + + attr_cast = (ietf_attr_product_info_t*)attr; + platform_info = attr_cast->get_info(attr_cast, NULL, NULL); + pts->set_platform_info(pts, platform_info); + } + } + else if (attr->get_vendor_id(attr) == PEN_TCG) + { + if (!imv_attestation_process(attr, attr_list, attestation_state, + supported_algorithms,supported_dh_groups, pts_db, pts_credmgr)) + { + result = TNC_RESULT_FATAL; + break; + } + } + } + enumerator->destroy(enumerator); + pa_tnc_msg->destroy(pa_tnc_msg); + + if (result != TNC_RESULT_SUCCESS) + { + attr_list->destroy_offset(attr_list, offsetof(pa_tnc_attr_t, destroy)); + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + return imv_attestation->provide_recommendation(imv_attestation, + connection_id); + } + + if (attr_list->get_count(attr_list)) + { + pa_tnc_msg = pa_tnc_msg_create(); + + /* move PA-TNC attributes to PA-TNC message */ + enumerator = attr_list->create_enumerator(attr_list); + while (enumerator->enumerate(enumerator, &attr)) + { + pa_tnc_msg->add_attribute(pa_tnc_msg, attr); + } + enumerator->destroy(enumerator); + + pa_tnc_msg->build(pa_tnc_msg); + result = imv_attestation->send_message(imv_attestation, connection_id, + FALSE, 0, TNC_IMCID_ANY, + pa_tnc_msg->get_encoding(pa_tnc_msg)); + + pa_tnc_msg->destroy(pa_tnc_msg); + attr_list->destroy(attr_list); + + return result; + } + attr_list->destroy(attr_list); + + /* check the IMV state for the next PA-TNC attributes to send */ + result = send_message(connection_id); + if (result != TNC_RESULT_SUCCESS) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + return imv_attestation->provide_recommendation(imv_attestation, + connection_id); + } + + if (attestation_state->get_handshake_state(attestation_state) == + IMV_ATTESTATION_STATE_END) + { + if (attestation_state->get_file_meas_request_count(attestation_state)) + { + DBG1(DBG_IMV, "failure due to %d pending file measurements", + attestation_state->get_file_meas_request_count(attestation_state)); + attestation_state->set_measurement_error(attestation_state); + } + if (attestation_state->get_component_count(attestation_state)) + { + DBG1(DBG_IMV, "failure due to %d components waiting for evidence", + attestation_state->get_component_count(attestation_state)); + attestation_state->set_measurement_error(attestation_state); + } + if (attestation_state->get_measurement_error(attestation_state)) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, + TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); + } + else + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_COMPLIANT); + } + return imv_attestation->provide_recommendation(imv_attestation, + connection_id); + } + + return result; +} + +/** + * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + TNC_VendorID msg_vid; + TNC_MessageSubtype msg_subtype; + + msg_vid = msg_type >> 8; + msg_subtype = msg_type & TNC_SUBTYPE_ANY; + + return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len), + msg_vid, msg_subtype, 0, TNC_IMVID_ANY); +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_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_imc_id, + TNC_UInt32 dst_imv_id) +{ + return receive_message(imv_id, connection_id, msg_flags, + chunk_create(msg, msg_len), msg_vid, msg_subtype, + src_imc_id, dst_imv_id); +} + +/** + * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, + TNC_ConnectionID connection_id) +{ + if (!imv_attestation) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_attestation->provide_recommendation(imv_attestation, + connection_id); +} + +/** + * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, + TNC_ConnectionID connection_id) +{ + imv_state_t *state; + imv_attestation_state_t *attestation_state; + + if (!imv_attestation) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + /* get current IMV state */ + if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imv_attestation_state_t*)state; + + /* Check if IMV has to initiate the PA-TNC exchange */ + if (attestation_state->get_handshake_state(attestation_state) == + IMV_ATTESTATION_STATE_INIT) + { + return send_message(connection_id); + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) +{ + if (!imv_attestation) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + if (pts_creds) + { + pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds)); + pts_creds->destroy(pts_creds); + } + DESTROY_IF(pts_db); + DESTROY_IF(pts_credmgr); + + libpts_deinit(); + + imv_attestation->destroy(imv_attestation); + imv_attestation = NULL; + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, + TNC_TNCS_BindFunctionPointer bind_function) +{ + if (!imv_attestation) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_attestation->bind_functions(imv_attestation, bind_function); +} diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_build.c b/src/libpts/plugins/imv_attestation/imv_attestation_build.c new file mode 100644 index 000000000..4f2cc1e95 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/imv_attestation_build.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "imv_attestation_build.h" +#include "imv_attestation_state.h" + +#include <libpts.h> +#include <tcg/tcg_pts_attr_proto_caps.h> +#include <tcg/tcg_pts_attr_meas_algo.h> +#include <tcg/tcg_pts_attr_dh_nonce_params_req.h> +#include <tcg/tcg_pts_attr_dh_nonce_finish.h> +#include <tcg/tcg_pts_attr_get_tpm_version_info.h> +#include <tcg/tcg_pts_attr_get_aik.h> +#include <tcg/tcg_pts_attr_req_func_comp_evid.h> +#include <tcg/tcg_pts_attr_gen_attest_evid.h> +#include <tcg/tcg_pts_attr_req_file_meas.h> +#include <tcg/tcg_pts_attr_req_file_meta.h> + +#include <debug.h> + +bool imv_attestation_build(linked_list_t *attr_list, + imv_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db) +{ + imv_attestation_handshake_state_t handshake_state; + pts_t *pts; + pa_tnc_attr_t *attr = NULL; + + handshake_state = attestation_state->get_handshake_state(attestation_state); + pts = attestation_state->get_pts(attestation_state); + + /** + * Skip DH Nonce Parameters Request attribute when + * DH Nonce Exchange is not selected by PTS-IMC side + */ + if (handshake_state == IMV_ATTESTATION_STATE_NONCE_REQ && + !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D)) + { + DBG2(DBG_IMV, "PTS-IMC does not support DH Nonce negotiation - " + "advancing to TPM Initialization"); + handshake_state = IMV_ATTESTATION_STATE_TPM_INIT; + } + + /** + * Skip TPM Version Info and AIK attributes when + * no TPM is available on the PTS-IMC side + */ + if (handshake_state == IMV_ATTESTATION_STATE_TPM_INIT && + !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T)) + { + DBG2(DBG_IMV, "PTS-IMC made no TPM available - " + "advancing to File Measurements"); + handshake_state = IMV_ATTESTATION_STATE_MEAS; + } + + switch (handshake_state) + { + case IMV_ATTESTATION_STATE_INIT: + { + pts_proto_caps_flag_t flags; + + /* Send Request Protocol Capabilities attribute */ + flags = pts->get_proto_caps(pts); + attr = tcg_pts_attr_proto_caps_create(flags, TRUE); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + + /* Send Measurement Algorithms attribute */ + attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_NONCE_REQ); + break; + } + case IMV_ATTESTATION_STATE_NONCE_REQ: + { + int min_nonce_len; + + /* Send DH nonce parameters request attribute */ + min_nonce_len = lib->settings->get_int(lib->settings, + "libimcv.plugins.imv-attestation.min_nonce_len", 0); + attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len, + supported_dh_groups); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_TPM_INIT); + break; + } + case IMV_ATTESTATION_STATE_TPM_INIT: + { + pts_meas_algorithms_t selected_algorithm; + chunk_t initiator_value, initiator_nonce; + + if ((pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D)) + { + /* Send DH nonce finish attribute */ + selected_algorithm = pts->get_meas_algorithm(pts); + pts->get_my_public_value(pts, &initiator_value, &initiator_nonce); + attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm, + initiator_value, initiator_nonce); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + } + + /* Send Get TPM Version attribute */ + attr = tcg_pts_attr_get_tpm_version_info_create(); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + + /* Send Get AIK attribute */ + attr = tcg_pts_attr_get_aik_create(); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_MEAS); + break; + } + case IMV_ATTESTATION_STATE_MEAS: + { + enumerator_t *enumerator; + u_int32_t delimiter = SOLIDUS_UTF; + char *platform_info, *pathname; + u_int16_t request_id; + int id, type; + bool is_dir; + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_COMP_EVID); + + /* Get Platform and OS of the PTS-IMC */ + platform_info = pts->get_platform_info(pts); + + if (!pts_db || !platform_info) + { + DBG1(DBG_IMV, "%s%s%s not available", + (pts_db) ? "" : "pts database", + (!pts_db && !platform_info) ? "and" : "", + (platform_info) ? "" : "platform info"); + break; + } + DBG1(DBG_IMV, "platform is '%s'", platform_info); + + /* Send Request File Metadata attribute */ + enumerator = pts_db->create_file_meta_enumerator(pts_db, + platform_info); + if (!enumerator) + { + break; + } + while (enumerator->enumerate(enumerator, &type, &pathname)) + { + is_dir = (type != 0); + DBG2(DBG_IMV, "metadata request for %s '%s'", + is_dir ? "directory" : "file", pathname); + attr = tcg_pts_attr_req_file_meta_create(is_dir, delimiter, + pathname); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + } + enumerator->destroy(enumerator); + + /* Send Request File Measurement attribute */ + enumerator = pts_db->create_file_meas_enumerator(pts_db, + platform_info); + if (!enumerator) + { + break; + } + while (enumerator->enumerate(enumerator, &id, &type, &pathname)) + { + is_dir = (type != 0); + request_id = attestation_state->add_file_meas_request( + attestation_state, id, is_dir); + DBG2(DBG_IMV, "measurement request %d for %s '%s'", + request_id, is_dir ? "directory" : "file", pathname); + attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id, + delimiter, pathname); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + } + enumerator->destroy(enumerator); + break; + } + case IMV_ATTESTATION_STATE_COMP_EVID: + { + tcg_pts_attr_req_func_comp_evid_t *attr_cast; + enumerator_t *enumerator; + pts_component_t *comp; + pts_comp_func_name_t *comp_name; + chunk_t keyid; + int kid, vid, name, qualifier; + u_int8_t flags; + u_int32_t depth; + bool first = TRUE, first_component = TRUE; + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_END); + + if (!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T) || + !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D)) + { + DBG2(DBG_IMV, "PTS-IMC made no TPM available - " + "skipping Component Measurements"); + break; + } + if (!pts->get_aik_keyid(pts, &keyid)) + { + DBG1(DBG_IMV, "retrieval of AIK keyid failed"); + return FALSE; + } + if (!pts_db) + { + DBG1(DBG_IMV, "pts database not available"); + break; + } + if (pts_db->check_aik_keyid(pts_db, keyid, &kid) != SUCCESS) + { + return FALSE; + } + enumerator = pts_db->create_comp_evid_enumerator(pts_db, kid); + if (!enumerator) + { + break; + } + while (enumerator->enumerate(enumerator, &vid, &name, + &qualifier, &depth)) + { + if (first) + { + DBG2(DBG_IMV, "evidence request by"); + first = FALSE; + } + comp_name = pts_comp_func_name_create(vid, name, qualifier); + comp_name->log(comp_name, " "); + + comp = pts_components->create(pts_components, comp_name, + depth, pts_db); + if (!comp) + { + DBG2(DBG_IMV, " not registered: removed from request"); + comp_name->destroy(comp_name); + continue; + } + attestation_state->add_component(attestation_state, comp); + if (first_component) + { + attr = tcg_pts_attr_req_func_comp_evid_create(); + attr->set_noskip_flag(attr, TRUE); + first_component = FALSE; + } + flags = comp->get_evidence_flags(comp); + /* TODO check flags against negotiated_caps */ + attr_cast = (tcg_pts_attr_req_func_comp_evid_t *)attr; + attr_cast->add_component(attr_cast, flags, depth, comp_name); + } + enumerator->destroy(enumerator); + + if (attr) + { + /* Send Request Functional Component Evidence attribute */ + attr_list->insert_last(attr_list, attr); + + /* Send Generate Attestation Evidence attribute */ + attr = tcg_pts_attr_gen_attest_evid_create(); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_EVID_FINAL); + } + break; + } + case IMV_ATTESTATION_STATE_EVID_FINAL: + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_END); + break; + case IMV_ATTESTATION_STATE_END: + break; + } + return TRUE; +} diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_build.h b/src/libpts/plugins/imv_attestation/imv_attestation_build.h new file mode 100644 index 000000000..7f934fd09 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/imv_attestation_build.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 imv_attestation_build_t imv_attestation_build + * @{ @ingroup imv_attestation_build + */ + +#ifndef IMV_ATTESTATION_BUILD_H_ +#define IMV_ATTESTATION_BUILD_H_ + +#include "imv_attestation_state.h" + +#include <pa_tnc/pa_tnc_msg.h> +#include <library.h> + +#include <pts/pts_database.h> +#include <pts/pts_dh_group.h> +#include <pts/pts_meas_algo.h> + +/** + * Process a TCG PTS attribute + * + * @param attr_list list of PA-TNC attriubutes to be built + * @param attestation_state attestation state of a given connection + * @param supported_algorithms supported PTS measurement algorithms + * @param supported_dh_groups supported DH groups + * @param pts_db PTS configuration database + * @return TRUE if successful + */ +bool imv_attestation_build(linked_list_t *attr_list, + imv_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db); + +#endif /** IMV_ATTESTATION_BUILD_H_ @}*/ diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.c b/src/libpts/plugins/imv_attestation/imv_attestation_process.c new file mode 100644 index 000000000..a742b6697 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.c @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "imv_attestation_process.h" + +#include <ietf/ietf_attr_pa_tnc_error.h> + +#include <pts/pts.h> + +#include <tcg/tcg_pts_attr_aik.h> +#include <tcg/tcg_pts_attr_dh_nonce_params_resp.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_simple_comp_evid.h> +#include <tcg/tcg_pts_attr_simple_evid_final.h> +#include <tcg/tcg_pts_attr_tpm_version_info.h> +#include <tcg/tcg_pts_attr_unix_file_meta.h> + +#include <debug.h> +#include <crypto/hashers/hasher.h> + +#include <inttypes.h> + +bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, + imv_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db, + credential_manager_t *pts_credmgr) +{ + pts_t *pts; + + pts = attestation_state->get_pts(attestation_state); + + switch (attr->get_type(attr)) + { + case TCG_PTS_PROTO_CAPS: + { + tcg_pts_attr_proto_caps_t *attr_cast; + pts_proto_caps_flag_t flags; + + attr_cast = (tcg_pts_attr_proto_caps_t*)attr; + flags = attr_cast->get_flags(attr_cast); + pts->set_proto_caps(pts, flags); + break; + } + case TCG_PTS_MEAS_ALGO_SELECTION: + { + tcg_pts_attr_meas_algo_t *attr_cast; + pts_meas_algorithms_t selected_algorithm; + + attr_cast = (tcg_pts_attr_meas_algo_t*)attr; + selected_algorithm = attr_cast->get_algorithms(attr_cast); + if (!(selected_algorithm & supported_algorithms)) + { + DBG1(DBG_IMV, "PTS-IMC selected unsupported" + " measurement algorithm"); + return FALSE; + } + pts->set_meas_algorithm(pts, selected_algorithm); + break; + } + case TCG_PTS_DH_NONCE_PARAMS_RESP: + { + tcg_pts_attr_dh_nonce_params_resp_t *attr_cast; + int nonce_len, min_nonce_len; + pts_dh_group_t dh_group; + pts_meas_algorithms_t offered_algorithms, selected_algorithm; + chunk_t responder_value, responder_nonce; + + attr_cast = (tcg_pts_attr_dh_nonce_params_resp_t*)attr; + responder_nonce = attr_cast->get_responder_nonce(attr_cast); + + /* check compliance of responder nonce length */ + min_nonce_len = lib->settings->get_int(lib->settings, + "libimcv.plugins.imv-attestation.min_nonce_len", 0); + nonce_len = responder_nonce.len; + if (nonce_len < PTS_MIN_NONCE_LEN || + (min_nonce_len > 0 && nonce_len < min_nonce_len)) + { + attr = pts_dh_nonce_error_create( + max(PTS_MIN_NONCE_LEN, min_nonce_len), + PTS_MAX_NONCE_LEN); + attr_list->insert_last(attr_list, attr); + break; + } + + dh_group = attr_cast->get_dh_group(attr_cast); + if (!(dh_group & supported_dh_groups)) + { + DBG1(DBG_IMV, "PTS-IMC selected unsupported DH group"); + return FALSE; + } + + offered_algorithms = attr_cast->get_hash_algo_set(attr_cast); + selected_algorithm = pts_meas_algo_select(supported_algorithms, + offered_algorithms); + if (selected_algorithm == PTS_MEAS_ALGO_NONE) + { + attr = pts_hash_alg_error_create(supported_algorithms); + attr_list->insert_last(attr_list, attr); + break; + } + pts->set_dh_hash_algorithm(pts, selected_algorithm); + + if (!pts->create_dh_nonce(pts, dh_group, nonce_len)) + { + return FALSE; + } + + responder_value = attr_cast->get_responder_value(attr_cast); + pts->set_peer_public_value(pts, responder_value, + responder_nonce); + + /* Calculate secret assessment value */ + if (!pts->calculate_secret(pts)) + { + return FALSE; + } + break; + } + case TCG_PTS_TPM_VERSION_INFO: + { + tcg_pts_attr_tpm_version_info_t *attr_cast; + chunk_t tpm_version_info; + + attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr; + tpm_version_info = attr_cast->get_tpm_version_info(attr_cast); + pts->set_tpm_version_info(pts, tpm_version_info); + break; + } + case TCG_PTS_AIK: + { + tcg_pts_attr_aik_t *attr_cast; + certificate_t *aik, *issuer; + public_key_t *public; + chunk_t keyid; + enumerator_t *e; + bool trusted = FALSE; + + attr_cast = (tcg_pts_attr_aik_t*)attr; + aik = attr_cast->get_aik(attr_cast); + if (!aik) + { + DBG1(DBG_IMV, "AIK unavailable"); + return FALSE; + } + if (aik->get_type(aik) == CERT_X509) + { + public = aik->get_public_key(aik); + public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid); + DBG1(DBG_IMV, "verifying AIK certificate with keyid %#B", &keyid); + public->destroy(public); + + e = pts_credmgr->create_trusted_enumerator(pts_credmgr, + KEY_ANY, aik->get_issuer(aik), FALSE); + while (e->enumerate(e, &issuer)) + { + if (aik->issued_by(aik, issuer)) + { + trusted = TRUE; + break; + } + } + e->destroy(e); + DBG1(DBG_IMV, "AIK certificate is %strusted", + trusted ? "" : "not "); + if (!trusted) + { + return FALSE; + } + } + pts->set_aik(pts, aik); + break; + } + case TCG_PTS_FILE_MEAS: + { + tcg_pts_attr_file_meas_t *attr_cast; + u_int16_t request_id; + int file_count, file_id; + pts_meas_algorithms_t algo; + pts_file_meas_t *measurements; + char *platform_info; + enumerator_t *e_hash; + bool is_dir; + + platform_info = pts->get_platform_info(pts); + if (!pts_db || !platform_info) + { + DBG1(DBG_IMV, "%s%s%s not available", + (pts_db) ? "" : "pts database", + (!pts_db && !platform_info) ? "and" : "", + (platform_info) ? "" : "platform info"); + break; + } + + attr_cast = (tcg_pts_attr_file_meas_t*)attr; + measurements = attr_cast->get_measurements(attr_cast); + algo = pts->get_meas_algorithm(pts); + request_id = measurements->get_request_id(measurements); + file_count = measurements->get_file_count(measurements); + + DBG1(DBG_IMV, "measurement request %d returned %d file%s:", + request_id, file_count, (file_count == 1) ? "":"s"); + + if (!attestation_state->check_off_file_meas_request(attestation_state, + request_id, &file_id, &is_dir)) + { + DBG1(DBG_IMV, " no entry found for file measurement request %d", + request_id); + break; + } + + /* check hashes from database against measurements */ + e_hash = pts_db->create_file_hash_enumerator(pts_db, + platform_info, algo, file_id, is_dir); + if (!measurements->verify(measurements, e_hash, is_dir)) + { + attestation_state->set_measurement_error(attestation_state); + } + e_hash->destroy(e_hash); + break; + } + case TCG_PTS_UNIX_FILE_META: + { + tcg_pts_attr_file_meta_t *attr_cast; + int file_count; + pts_file_meta_t *metadata; + pts_file_metadata_t *entry; + time_t created, modified, accessed; + bool utc = FALSE; + enumerator_t *e; + + attr_cast = (tcg_pts_attr_file_meta_t*)attr; + metadata = attr_cast->get_metadata(attr_cast); + file_count = metadata->get_file_count(metadata); + + DBG1(DBG_IMV, "metadata request returned %d file%s:", + file_count, (file_count == 1) ? "":"s"); + + e = metadata->create_enumerator(metadata); + while (e->enumerate(e, &entry)) + { + DBG1(DBG_IMV, " '%s' (%"PRIu64" bytes)" + " owner %"PRIu64", group %"PRIu64", type %N", + entry->filename, entry->filesize, entry->owner, + entry->group, pts_file_type_names, entry->type); + + created = entry->created; + modified = entry->modified; + accessed = entry->accessed; + + DBG1(DBG_IMV, " created %T, modified %T, accessed %T", + &created, utc, &modified, utc, &accessed, utc); + } + e->destroy(e); + break; + } + case TCG_PTS_SIMPLE_COMP_EVID: + { + tcg_pts_attr_simple_comp_evid_t *attr_cast; + pts_comp_func_name_t *name; + pts_comp_evidence_t *evidence; + pts_component_t *comp; + u_int32_t depth; + status_t status; + + attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr; + evidence = attr_cast->get_comp_evidence(attr_cast); + name = evidence->get_comp_func_name(evidence, &depth); + + comp = attestation_state->check_off_component(attestation_state, name); + if (!comp) + { + DBG1(DBG_IMV, " no entry found for component evidence request"); + break; + } + status = comp->verify(comp, pts, evidence); + + switch (status) + { + default: + case FAILED: + attestation_state->set_measurement_error(attestation_state); + comp->destroy(comp); + break; + case SUCCESS: + name->log(name, " successfully measured "); + comp->destroy(comp); + break; + case NEED_MORE: + /* re-enter component into list */ + attestation_state->add_component(attestation_state, comp); + } + break; + } + case TCG_PTS_SIMPLE_EVID_FINAL: + { + tcg_pts_attr_simple_evid_final_t *attr_cast; + u_int8_t flags; + pts_meas_algorithms_t comp_hash_algorithm; + chunk_t pcr_comp, tpm_quote_sig, evid_sig; + chunk_t pcr_composite, quote_info; + bool use_quote2, use_ver_info; + + attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr; + flags = attr_cast->get_quote_info(attr_cast, &comp_hash_algorithm, + &pcr_comp, &tpm_quote_sig); + + if (flags != PTS_SIMPLE_EVID_FINAL_NO) + { + use_quote2 = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 || + flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER); + use_ver_info = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER); + + /* Construct PCR Composite and TPM Quote Info structures */ + if (!pts->get_quote_info(pts, use_quote2, use_ver_info, + comp_hash_algorithm, &pcr_composite, "e_info)) + { + DBG1(DBG_IMV, "unable to construct TPM Quote Info"); + return FALSE; + } + + if (!chunk_equals(pcr_comp, pcr_composite)) + { + DBG1(DBG_IMV, "received PCR Composite does not match " + "constructed one"); + free(pcr_composite.ptr); + free(quote_info.ptr); + return FALSE; + } + DBG2(DBG_IMV, "received PCR Composite matches constructed one"); + free(pcr_composite.ptr); + + if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig)) + { + free(quote_info.ptr); + return FALSE; + } + DBG2(DBG_IMV, "TPM Quote Info signature verification successful"); + free(quote_info.ptr); + + /* Finalize any pending measurement registrations */ + attestation_state->check_off_registrations(attestation_state); + } + + if (attr_cast->get_evid_sig(attr_cast, &evid_sig)) + { + /** TODO: What to do with Evidence Signature */ + DBG1(DBG_IMV, "this version of the Attestation IMV can not " + "handle Evidence Signatures"); + } + break; + } + + /* TODO: Not implemented yet */ + case TCG_PTS_INTEG_MEAS_LOG: + /* Attributes using XML */ + case TCG_PTS_TEMPL_REF_MANI_SET_META: + case TCG_PTS_VERIFICATION_RESULT: + case TCG_PTS_INTEG_REPORT: + /* On Windows only*/ + case TCG_PTS_WIN_FILE_META: + case TCG_PTS_REGISTRY_VALUE: + /* Received on IMC side only*/ + case TCG_PTS_REQ_PROTO_CAPS: + case TCG_PTS_DH_NONCE_PARAMS_REQ: + case TCG_PTS_DH_NONCE_FINISH: + case TCG_PTS_MEAS_ALGO: + case TCG_PTS_GET_TPM_VERSION_INFO: + case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META: + case TCG_PTS_UPDATE_TEMPL_REF_MANI: + case TCG_PTS_GET_AIK: + case TCG_PTS_REQ_FUNC_COMP_EVID: + case TCG_PTS_GEN_ATTEST_EVID: + case TCG_PTS_REQ_FILE_META: + case TCG_PTS_REQ_FILE_MEAS: + case TCG_PTS_REQ_INTEG_MEAS_LOG: + default: + DBG1(DBG_IMV, "received unsupported attribute '%N'", + tcg_attr_names, attr->get_type(attr)); + break; + } + return TRUE; +} + diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.h b/src/libpts/plugins/imv_attestation/imv_attestation_process.h new file mode 100644 index 000000000..4d4eeefbb --- /dev/null +++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 imv_attestation_process_t imv_attestation_process + * @{ @ingroup imv_attestation_process + */ + +#ifndef IMV_ATTESTATION_PROCESS_H_ +#define IMV_ATTESTATION_PROCESS_H_ + +#include "imv_attestation_state.h" + +#include <library.h> +#include <utils/linked_list.h> +#include <credentials/credential_manager.h> +#include <crypto/hashers/hasher.h> + +#include <pa_tnc/pa_tnc_attr.h> + +#include <pts/pts_database.h> +#include <pts/pts_dh_group.h> +#include <pts/pts_meas_algo.h> + +/** + * Process a TCG PTS attribute + * + * @param attr PA-TNC attribute to be processed + * @param attr_list list with PA-TNC error attributes + * @param attestation_state attestation state of a given connection + * @param supported_algorithms supported PTS measurement algorithms + * @param supported_dh_groups supported DH groups + * @param pts_db PTS configuration database + * @param pts_credmgr PTS credential manager + * @return TRUE if successful + */ +bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, + imv_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db, + credential_manager_t *pts_credmgr); + +#endif /** IMV_ATTESTATION_PROCESS_H_ @}*/ diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c b/src/libpts/plugins/imv_attestation/imv_attestation_state.c index 6305dac2f..a58fd3ec3 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.c @@ -20,12 +20,12 @@ #include <debug.h> typedef struct private_imv_attestation_state_t private_imv_attestation_state_t; -typedef struct request_t request_t; +typedef struct file_meas_request_t file_meas_request_t; /** * PTS File/Directory Measurement request entry */ -struct request_t { +struct file_meas_request_t { u_int16_t id; int file_id; bool is_dir; @@ -52,6 +52,16 @@ struct private_imv_attestation_state_t { TNC_ConnectionState state; /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** * IMV Attestation handshake state */ imv_attestation_handshake_state_t handshake_state; @@ -67,20 +77,30 @@ struct private_imv_attestation_state_t { TNC_IMV_Evaluation_Result eval; /** - * Request counter + * File Measurement Request counter */ - u_int16_t request_counter; + u_int16_t file_meas_request_counter; /** * List of PTS File/Directory Measurement requests */ - linked_list_t *requests; + linked_list_t *file_meas_requests; + + /** + * List of Functional Components + */ + linked_list_t *components; /** * PTS object */ pts_t *pts; + /** + * Measurement error + */ + bool measurement_error; + }; typedef struct entry_t entry_t; @@ -97,9 +117,12 @@ struct entry_t { * Table of multi-lingual reason string entries */ static entry_t reasons[] = { - { "en", "IMC Attestation Measurement/s of requested file didn't match" }, - { "mn", "IMC Attestation Шалгахаар тохируулсан файлуудын хэмжилтүүд таарсангүй" }, - { "de", "IMC Attestation Messung/en von angefordeten Datein stimmt nicht überein" }, + { "en", "IMV Attestation: Incorrect/pending file measurement/component" + " evidence or invalid TPM Quote signature received" }, + { "mn", "IMV Attestation: Буруу/хүлээгдэж байгаа файл/компонент хэмжилт " + "эсвэл буруу TPM Quote гарын үсэг" }, + { "de", "IMV Attestation: Falsche/Fehlende Dateimessung/Komponenten Beweis " + "oder ungültige TPM Quote Unterschrift ist erhalten" }, }; METHOD(imv_state_t, get_connection_id, TNC_ConnectionID, @@ -108,6 +131,25 @@ METHOD(imv_state_t, get_connection_id, TNC_ConnectionID, return this->connection_id; } +METHOD(imv_state_t, has_long, bool, + private_imv_attestation_state_t *this) +{ + return this->has_long; +} + +METHOD(imv_state_t, has_excl, bool, + private_imv_attestation_state_t *this) +{ + return this->has_excl; +} + +METHOD(imv_state_t, set_flags, void, + private_imv_attestation_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + METHOD(imv_state_t, change_state, void, private_imv_attestation_state_t *this, TNC_ConnectionState new_state) { @@ -177,19 +219,22 @@ METHOD(imv_state_t, get_reason_string, bool, METHOD(imv_state_t, destroy, void, private_imv_attestation_state_t *this) { - this->requests->destroy_function(this->requests, free); + this->file_meas_requests->destroy_function(this->file_meas_requests, free); + this->components->destroy_offset(this->components, + offsetof(pts_component_t, destroy)); this->pts->destroy(this->pts); free(this); } -METHOD(imv_attestation_state_t, get_handshake_state, imv_attestation_handshake_state_t, - private_imv_attestation_state_t *this) +METHOD(imv_attestation_state_t, get_handshake_state, + imv_attestation_handshake_state_t, private_imv_attestation_state_t *this) { return this->handshake_state; } METHOD(imv_attestation_state_t, set_handshake_state, void, - private_imv_attestation_state_t *this, imv_attestation_handshake_state_t new_state) + private_imv_attestation_state_t *this, + imv_attestation_handshake_state_t new_state) { this->handshake_state = new_state; } @@ -200,29 +245,29 @@ METHOD(imv_attestation_state_t, get_pts, pts_t*, return this->pts; } -METHOD(imv_attestation_state_t, add_request, u_int16_t, +METHOD(imv_attestation_state_t, add_file_meas_request, u_int16_t, private_imv_attestation_state_t *this, int file_id, bool is_dir) { - request_t *request; + file_meas_request_t *request; - request = malloc_thing(request_t); - request->id = ++this->request_counter; + request = malloc_thing(file_meas_request_t); + request->id = ++this->file_meas_request_counter; request->file_id = file_id; request->is_dir = is_dir; - this->requests->insert_last(this->requests, request); + this->file_meas_requests->insert_last(this->file_meas_requests, request); - return this->request_counter; + return this->file_meas_request_counter; } -METHOD(imv_attestation_state_t, check_off_request, bool, +METHOD(imv_attestation_state_t, check_off_file_meas_request, bool, private_imv_attestation_state_t *this, u_int16_t id, int *file_id, bool* is_dir) { enumerator_t *enumerator; - request_t *request; + file_meas_request_t *request; bool found = FALSE; - enumerator = this->requests->create_enumerator(this->requests); + enumerator = this->file_meas_requests->create_enumerator(this->file_meas_requests); while (enumerator->enumerate(enumerator, &request)) { if (request->id == id) @@ -230,7 +275,7 @@ METHOD(imv_attestation_state_t, check_off_request, bool, found = TRUE; *file_id = request->file_id; *is_dir = request->is_dir; - this->requests->remove_at(this->requests, enumerator); + this->file_meas_requests->remove_at(this->file_meas_requests, enumerator); free(request); break; } @@ -239,10 +284,72 @@ METHOD(imv_attestation_state_t, check_off_request, bool, return found; } -METHOD(imv_attestation_state_t, get_request_count, int, +METHOD(imv_attestation_state_t, get_file_meas_request_count, int, + private_imv_attestation_state_t *this) +{ + return this->file_meas_requests->get_count(this->file_meas_requests); +} + +METHOD(imv_attestation_state_t, add_component, void, + private_imv_attestation_state_t *this, pts_component_t *entry) +{ + this->components->insert_last(this->components, entry); +} + +METHOD(imv_attestation_state_t, check_off_component, pts_component_t*, + private_imv_attestation_state_t *this, pts_comp_func_name_t *name) +{ + enumerator_t *enumerator; + pts_component_t *entry, *found = NULL; + + enumerator = this->components->create_enumerator(this->components); + while (enumerator->enumerate(enumerator, &entry)) + { + if (name->equals(name, entry->get_comp_func_name(entry))) + { + found = entry; + this->components->remove_at(this->components, enumerator); + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +METHOD(imv_attestation_state_t, check_off_registrations, void, + private_imv_attestation_state_t *this) +{ + enumerator_t *enumerator; + pts_component_t *entry; + + enumerator = this->components->create_enumerator(this->components); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->check_off_registrations(entry)) + { + this->components->remove_at(this->components, enumerator); + entry->destroy(entry); + } + } + enumerator->destroy(enumerator); +} + +METHOD(imv_attestation_state_t, get_component_count, int, + private_imv_attestation_state_t *this) +{ + return this->components->get_count(this->components); +} + +METHOD(imv_attestation_state_t, get_measurement_error, bool, + private_imv_attestation_state_t *this) +{ + return this->measurement_error; +} + +METHOD(imv_attestation_state_t, set_measurement_error, void, private_imv_attestation_state_t *this) { - return this->requests->get_count(this->requests); + this->measurement_error = TRUE; } /** @@ -257,6 +364,9 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .public = { .interface = { .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, @@ -266,16 +376,23 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .get_handshake_state = _get_handshake_state, .set_handshake_state = _set_handshake_state, .get_pts = _get_pts, - .add_request = _add_request, - .check_off_request = _check_off_request, - .get_request_count = _get_request_count, + .add_file_meas_request = _add_file_meas_request, + .check_off_file_meas_request = _check_off_file_meas_request, + .get_file_meas_request_count = _get_file_meas_request_count, + .add_component = _add_component, + .check_off_component = _check_off_component, + .check_off_registrations = _check_off_registrations, + .get_component_count = _get_component_count, + .get_measurement_error = _get_measurement_error, + .set_measurement_error = _set_measurement_error, }, .connection_id = connection_id, .state = TNC_CONNECTION_STATE_CREATE, .handshake_state = IMV_ATTESTATION_STATE_INIT, .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, - .requests = linked_list_create(), + .file_meas_requests = linked_list_create(), + .components = linked_list_create(), .pts = pts_create(FALSE), ); diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.h b/src/libpts/plugins/imv_attestation/imv_attestation_state.h index a79fc91cc..0e2c04da4 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_state.h +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.h @@ -24,6 +24,7 @@ #include <imv/imv_state.h> #include <pts/pts.h> +#include <pts/components/pts_component.h> #include <library.h> typedef struct imv_attestation_state_t imv_attestation_state_t; @@ -34,9 +35,11 @@ typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t */ enum imv_attestation_handshake_state_t { IMV_ATTESTATION_STATE_INIT, + IMV_ATTESTATION_STATE_NONCE_REQ, + IMV_ATTESTATION_STATE_TPM_INIT, IMV_ATTESTATION_STATE_MEAS, IMV_ATTESTATION_STATE_COMP_EVID, - IMV_ATTESTATION_STATE_IML, + IMV_ATTESTATION_STATE_EVID_FINAL, IMV_ATTESTATION_STATE_END, }; @@ -55,7 +58,8 @@ struct imv_attestation_state_t { * * @return the handshake state of IMV */ - imv_attestation_handshake_state_t (*get_handshake_state)(imv_attestation_state_t *this); + imv_attestation_handshake_state_t (*get_handshake_state)( + imv_attestation_state_t *this); /** * Set state of the handshake @@ -79,15 +83,15 @@ struct imv_attestation_state_t { * @param is_dir TRUE if directory * @return unique request ID */ - u_int16_t (*add_request)(imv_attestation_state_t *this, int file_id, - bool is_dir); + u_int16_t (*add_file_meas_request)(imv_attestation_state_t *this, + int file_id, bool is_dir); /** * Returns the number of pending file/directory measurement requests * * @return number of pending requests */ - int (*get_request_count)(imv_attestation_state_t *this); + int (*get_file_meas_request_count)(imv_attestation_state_t *this); /** * Check for presence of request_id and if found remove it from the list @@ -97,8 +101,48 @@ struct imv_attestation_state_t { * @param is_dir return TRUE if request was for a directory * @return TRUE if request ID found, FALSE otherwise */ - bool (*check_off_request)(imv_attestation_state_t *this, u_int16_t id, - int *file_id, bool *is_dir); + bool (*check_off_file_meas_request)(imv_attestation_state_t *this, + u_int16_t id, int *file_id, bool *is_dir); + + /** + * Add an entry to the list of Functional Components waiting for evidence + * + * @param entry Functional Component + */ + void (*add_component)(imv_attestation_state_t *this, pts_component_t *entry); + + /** + * Returns the number of Functional Component waiting for evidence + * + * @return Number of waiting Functional Components + */ + int (*get_component_count)(imv_attestation_state_t *this); + + /** + * Check for presence of Functional Component and remove and return it + * + * @param name Name of the requested Functional Component + * @return Functional Component if found, NULL otherwise + */ + pts_component_t* (*check_off_component)(imv_attestation_state_t *this, + pts_comp_func_name_t *name); + + /** + * Tell the Functional Components to finalize any measurement registrations + */ + void (*check_off_registrations)(imv_attestation_state_t *this); + + /** + * Indicates if a file measurement error occurred + * + * @return TRUE in case of measurement error + */ + bool (*get_measurement_error)(imv_attestation_state_t *this); + + /** + * Call if a file measurement error is encountered + */ + void (*set_measurement_error)(imv_attestation_state_t *this); }; diff --git a/src/libpts/plugins/imv_attestation/tables.sql b/src/libpts/plugins/imv_attestation/tables.sql new file mode 100644 index 000000000..703557a07 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/tables.sql @@ -0,0 +1,82 @@ +/* PTS SQLite database */ + +DROP TABLE IF EXISTS files; +CREATE TABLE files ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + type INTEGER NOT NULL, + path TEXT NOT NULL +); + +DROP TABLE IF EXISTS products; +CREATE TABLE products ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL +); +DROP INDEX IF EXISTS products_name; +CREATE INDEX products_name ON products ( + name +); + +DROP TABLE IF EXISTS product_file; +CREATE TABLE product_file ( + product INTEGER NOT NULL, + file INTEGER NOT NULL, + measurement INTEGER DEFAULT 0, + metadata INTEGER DEFAULT 0, + PRIMARY KEY (product, file) +); + +DROP TABLE IF EXISTS file_hashes; +CREATE TABLE file_hashes ( + file INTEGER NOT NULL, + directory INTEGER DEFAULT 0, + product INTEGER NOT NULL, + algo INTEGER NOT NULL, + hash BLOB NOT NULL, + PRIMARY KEY(file, directory, product, algo) +); + +DROP TABLE IF EXISTS keys; +CREATE TABLE keys ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + keyid BLOB NOT NULL, + owner TEXT NOT NULL +); +DROP INDEX IF EXISTS keys_keyid; +CREATE INDEX keys_keyid ON keys ( + keyid +); +DROP INDEX IF EXISTS keys_owner; +CREATE INDEX keys_owner ON keys ( + owner +); + +DROP TABLE IF EXISTS components; +CREATE TABLE components ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + vendor_id INTEGER NOT NULL, + name INTEGER NOT NULL, + qualifier INTEGER DEFAULT 0 +); + + +DROP TABLE IF EXISTS key_component; +CREATE TABLE key_component ( + key INTEGER NOT NULL, + component INTEGER NOT NULL, + depth INTEGER DEFAULT 0, + seq_no INTEGER DEFAULT 0, + PRIMARY KEY (key, component) +); + + +DROP TABLE IF EXISTS component_hashes; +CREATE TABLE component_hashes ( + component INTEGER NOT NULL, + key INTEGER NOT NULL, + seq_no INTEGER NOT NULL, + pcr INTEGER NOT NULL, + algo INTEGER NOT NULL, + hash BLOB NOT NULL, + PRIMARY KEY(component, key, seq_no, algo) +); diff --git a/src/libpts/pts/components/ita/ita_comp_func_name.c b/src/libpts/pts/components/ita/ita_comp_func_name.c new file mode 100644 index 000000000..a593281ba --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_func_name.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 "ita_comp_func_name.h" + +char pts_ita_qualifier_flag_names[] = { 'K', 'S' }; + +ENUM_BEGIN(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_UNKNOWN, + PTS_ITA_QUALIFIER_TYPE_TNC, + "Unknown", + "Trusted Platform", + "Operating System", + "Graphical User Interface", + "Application", + "Networking", + "Library", + "TNC Defined Component" +); +ENUM_NEXT(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL, + PTS_ITA_QUALIFIER_TYPE_ALL, + PTS_ITA_QUALIFIER_TYPE_TNC, + "All Matching Components" +); +ENUM_END(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL); + +ENUM(pts_ita_comp_func_names, PTS_ITA_COMP_FUNC_NAME_IGNORE, + PTS_ITA_COMP_FUNC_NAME_IMA, + "Ignore", + "Trusted GRUB Boot Loader", + "Trusted Boot", + "Linux IMA" +); + diff --git a/src/libpts/pts/components/ita/ita_comp_func_name.h b/src/libpts/pts/components/ita/ita_comp_func_name.h new file mode 100644 index 000000000..eb2f363f3 --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_func_name.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_FUNC_NAME_H_ +#define PTS_ITA_COMP_FUNC_NAME_H_ + +typedef enum pts_ita_qualifier_type_t pts_ita_qualifier_type_t; +typedef enum pts_ita_comp_func_name_t pts_ita_comp_func_name_t; + +#include <library.h> + +/** + * PTS Component Functional Name Qualifier Flags for the ITA namespace + */ +#define PTS_ITA_QUALIFIER_FLAG_KERNEL (1<<5) +#define PTS_ITA_QUALIFIER_FLAG_SUB (1<<4) + +extern char pts_ita_qualifier_flag_names[]; + +/** + * Size of the PTS Component Functional Name Qualifier Type field + */ +#define PTS_ITA_QUALIFIER_TYPE_SIZE 4 + +/** + * PTS Component Functional Name Qualifier Types for the ITA namespace + * equal to section 5.2 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_ita_qualifier_type_t { + /** Unknown */ + PTS_ITA_QUALIFIER_TYPE_UNKNOWN = 0x0, + /** Trusted Platform */ + PTS_ITA_QUALIFIER_TYPE_TRUSTED = 0x1, + /** Operating System */ + PTS_ITA_QUALIFIER_TYPE_OS = 0x2, + /** Graphical User Interface */ + PTS_ITA_QUALIFIER_TYPE_GUI = 0x3, + /** Application */ + PTS_ITA_QUALIFIER_TYPE_APP = 0x4, + /** Networking */ + PTS_ITA_QUALIFIER_TYPE_NET = 0x5, + /** Library */ + PTS_ITA_QUALIFIER_TYPE_LIB = 0x6, + /** TNC Defined Component */ + PTS_ITA_QUALIFIER_TYPE_TNC = 0x7, + /** All Matching Components */ + PTS_ITA_QUALIFIER_TYPE_ALL = 0xF, +}; + +extern enum_name_t *pts_ita_qualifier_type_names; + +/** + * PTS Component Functional Name Binary Enumeration for the ITA namespace + */ +enum pts_ita_comp_func_name_t { + /** Ignore */ + PTS_ITA_COMP_FUNC_NAME_IGNORE = 0x0000, + /** Trusted GRUB Boot Loader */ + PTS_ITA_COMP_FUNC_NAME_TGRUB = 0x0001, + /** Trusted Boot */ + PTS_ITA_COMP_FUNC_NAME_TBOOT = 0x0002, + /** Linux Integrity Measurement Architecture */ + PTS_ITA_COMP_FUNC_NAME_IMA = 0x0003, +}; + +extern enum_name_t *pts_ita_comp_func_names; + +#endif /** PTS_ITA_COMP_FUNC_NAME_H_ @}*/ diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c new file mode 100644 index 000000000..a7da76651 --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_ima.c @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * + * HSR 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 "ita_comp_ima.h" +#include "ita_comp_func_name.h" + +#include "libpts.h" +#include "pts/components/pts_component.h" + +#include <debug.h> +#include <pen/pen.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/" +#define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements" +#define IMA_PCR_MAX 16 + +typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t; + +/** + * Private data of a pts_ita_comp_ima_t object. + * + */ +struct pts_ita_comp_ima_t { + + /** + * Public pts_component_t interface. + */ + pts_component_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * AIK keyid + */ + chunk_t keyid; + + /** + * Sub-component depth + */ + u_int32_t depth; + + /** + * PTS measurement database + */ + pts_database_t *pts_db; + + /** + * Primary key for Component Functional Name database entry + */ + int cid; + + /** + * Primary key for AIK database entry + */ + int kid; + + /** + * Component is registering measurements + */ + bool is_registering; + + /** + * IMA BIOS measurement time + */ + time_t bios_measurement_time; + + /** + * IMA BIOS measurements + */ + linked_list_t *list; + + /** + * Expected measurement count + */ + int count; + + /** + * Measurement sequence number + */ + int seq_no; + + /** + * Shadow PCR registers + */ + chunk_t pcrs[IMA_PCR_MAX]; +}; + +typedef struct entry_t entry_t; + +/** + * Linux IMA measurement entry + */ +struct entry_t { + + /** + * PCR register + */ + u_int32_t pcr; + + /** + * SHA1 measurement hash + */ + chunk_t measurement; +}; + +/** + * Free an entry_t object + */ +static void free_entry(entry_t *this) +{ + free(this->measurement.ptr); + free(this); +} + +/** + * Load a PCR measurement file and determine the creation date + */ +static bool load_measurements(char *file, linked_list_t *list, time_t *created) +{ + u_int32_t pcr, num, len; + entry_t *entry; + struct stat st; + ssize_t res; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) + { + DBG1(DBG_PTS, " opening '%s' failed: %s", file, strerror(errno)); + return FALSE; + } + + if (fstat(fd, &st) == -1) + { + DBG1(DBG_PTS, " getting statistics of '%s' failed: %s", file, + strerror(errno)); + close(fd); + return FALSE; + } + *created = st.st_ctime; + + while (TRUE) + { + res = read(fd, &pcr, 4); + if (res == 0) + { + DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)", + file, list->get_count(list)); + close(fd); + return TRUE; + } + + entry = malloc_thing(entry_t); + entry->pcr = pcr; + entry->measurement = chunk_alloc(HASH_SIZE_SHA1); + + if (res != 4) + { + break; + } + if (read(fd, &num, 4) != 4) + { + break; + } + if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1) + { + break; + } + if (read(fd, &len, 4) != 4) + { + break; + } + if (lseek(fd, len, SEEK_CUR) == -1) + { + break; + } + list->insert_last(list, entry); + } + + DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", + file, strerror(errno)); + close(fd); + return FALSE; +} + +METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, + pts_ita_comp_ima_t *this) +{ + return this->name; +} + +METHOD(pts_component_t, get_evidence_flags, u_int8_t, + pts_ita_comp_ima_t *this) +{ + return PTS_REQ_FUNC_COMP_EVID_PCR; +} + +METHOD(pts_component_t, get_depth, u_int32_t, + pts_ita_comp_ima_t *this) +{ + return this->depth; +} + +METHOD(pts_component_t, measure, status_t, + pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence) +{ + pts_comp_evidence_t *evid; + chunk_t pcr_before, pcr_after; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; + size_t pcr_len; + entry_t *entry; + hasher_t *hasher; + + hash_algo = PTS_MEAS_ALGO_SHA1; + pcr_len = pts->get_pcr_len(pts); + pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + + if (this->list->get_count(this->list) == 0) + { + if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH, this->list, + &this->bios_measurement_time)) + { + return FAILED; + } + } + + if (this->list->remove_first(this->list, (void**)&entry) != SUCCESS) + { + DBG1(DBG_PTS, "could not retrieve measurement entry"); + return FAILED; + } + + pcr_before = chunk_clone(this->pcrs[entry->pcr]); + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + hasher->get_hash(hasher, pcr_before, NULL); + hasher->get_hash(hasher, entry->measurement, this->pcrs[entry->pcr].ptr); + hasher->destroy(hasher); + + pcr_after = chunk_clone(this->pcrs[entry->pcr]); + + evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), + this->depth, entry->pcr, hash_algo, pcr_transform, + this->bios_measurement_time, entry->measurement); + evid->set_pcr_info(evid, pcr_before, pcr_after); + + free(entry); + + return (this->list->get_count(this->list)) ? NEED_MORE : SUCCESS; +} + +METHOD(pts_component_t, verify, status_t, + pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t *evidence) +{ + bool has_pcr_info; + u_int32_t extended_pcr, vid, name; + enum_name_t *names; + pts_meas_algorithms_t algo; + pts_pcr_transform_t transform; + time_t measurement_time; + chunk_t measurement, pcr_before, pcr_after; + + measurement = evidence->get_measurement(evidence, &extended_pcr, + &algo, &transform, &measurement_time); + + if (!this->keyid.ptr) + { + if (!pts->get_aik_keyid(pts, &this->keyid)) + { + return FAILED; + } + this->keyid = chunk_clone(this->keyid); + + if (!this->pts_db) + { + DBG1(DBG_PTS, "pts database not available"); + return FAILED; + } + if (this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->keyid, algo, + &this->cid, &this->kid, &this->count) != SUCCESS) + { + return FAILED; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (this->count) + { + DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence " + "measurements", this->count, pen_names, vid, names, name); + } + else + { + DBG1(DBG_PTS, "registering %N '%N' functional component evidence " + "measurements", pen_names, vid, names, name); + this->is_registering = TRUE; + } + } + + if (this->is_registering) + { + if (this->pts_db->insert_comp_measurement(this->pts_db, measurement, + this->cid, this->kid, ++this->seq_no, + extended_pcr, algo) != SUCCESS) + { + return FAILED; + } + this->count = this->seq_no + 1; + } + else + { + if (this->pts_db->check_comp_measurement(this->pts_db, measurement, + this->cid, this->kid, ++this->seq_no, + extended_pcr, algo) != SUCCESS) + { + return FAILED; + } + } + + has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); + if (has_pcr_info) + { + if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after)) + { + return FAILED; + } + } + + return (this->seq_no < this->count) ? NEED_MORE : SUCCESS; +} + +METHOD(pts_component_t, check_off_registrations, bool, + pts_ita_comp_ima_t *this) +{ + u_int32_t vid, name; + enum_name_t *names; + + if (!this->is_registering) + { + return FALSE; + } + + /* Finalize registration */ + this->is_registering = FALSE; + + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence " + "measurements", this->seq_no, pen_names, vid, names, name); + return TRUE; +} + +METHOD(pts_component_t, destroy, void, + pts_ita_comp_ima_t *this) +{ + int i, count; + u_int32_t vid, name; + enum_name_t *names; + + for (i = 0; i < IMA_PCR_MAX; i++) + { + free(this->pcrs[i].ptr); + } + if (this->is_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->cid, this->kid); + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component " + "evidence measurements", count, pen_names, vid, names, name); + } + this->list->destroy_function(this->list, (void *)free_entry); + this->name->destroy(this->name); + free(this->keyid.ptr); + free(this); +} + +/** + * See header + */ +pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth, + pts_database_t *pts_db) +{ + pts_ita_comp_ima_t *this; + int i; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_evidence_flags = _get_evidence_flags, + .get_depth = _get_depth, + .measure = _measure, + .verify = _verify, + .check_off_registrations = _check_off_registrations, + .destroy = _destroy, + }, + .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA, + qualifier), + .depth = depth, + .pts_db = pts_db, + .list = linked_list_create(), + ); + + for (i = 0; i < IMA_PCR_MAX; i++) + { + this->pcrs[i] = chunk_alloc(HASH_SIZE_SHA1); + memset(this->pcrs[i].ptr, 0x00, HASH_SIZE_SHA1); + } + return &this->public; +} + diff --git a/src/libpts/pts/components/ita/ita_comp_ima.h b/src/libpts/pts/components/ita/ita_comp_ima.h new file mode 100644 index 000000000..1ca27e6f0 --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_ima.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 pts_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_IMA_H_ +#define PTS_ITA_COMP_IMA_H_ + +#include "pts/components/pts_component.h" + +/** + * Create a PTS ITS Functional Component object + * + * @param qualifier PTS Component Functional Name Qualifier + * @param depth Sub-component depth + * @param pts_db PTS measurement database + */ +pts_component_t* pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth, + pts_database_t *pts_db); + +#endif /** PTS_ITA_COMP_IMA_H_ @}*/ diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.c b/src/libpts/pts/components/ita/ita_comp_tboot.c new file mode 100644 index 000000000..287aae727 --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_tboot.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * + * HSR 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 "ita_comp_tboot.h" +#include "ita_comp_func_name.h" + +#include "libpts.h" +#include "pts/components/pts_component.h" + +#include <debug.h> +#include <pen/pen.h> + +typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t; + +/** + * Private data of a pts_ita_comp_tboot_t object. + * + */ +struct pts_ita_comp_tboot_t { + + /** + * Public pts_component_t interface. + */ + pts_component_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * AIK keyid + */ + chunk_t keyid; + + /** + * Sub-component depth + */ + u_int32_t depth; + + /** + * PTS measurement database + */ + pts_database_t *pts_db; + + /** + * Primary key for Component Functional Name database entry + */ + int cid; + + /** + * Primary key for AIK database entry + */ + int kid; + + /** + * Component is registering measurements + */ + bool is_registering; + + /** + * Time of TBOOT measurement + */ + time_t measurement_time; + + /** + * Expected measurement count + */ + int count; + + /** + * Measurement sequence number + */ + int seq_no; + +}; + +METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, + pts_ita_comp_tboot_t *this) +{ + return this->name; +} + +METHOD(pts_component_t, get_evidence_flags, u_int8_t, + pts_ita_comp_tboot_t *this) +{ + return PTS_REQ_FUNC_COMP_EVID_PCR; +} + +METHOD(pts_component_t, get_depth, u_int32_t, + pts_ita_comp_tboot_t *this) +{ + return this->depth; +} + +METHOD(pts_component_t, measure, status_t, + pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t **evidence) +{ + pts_comp_evidence_t *evid; + char *meas_hex, *pcr_before_hex, *pcr_after_hex; + chunk_t measurement, pcr_before, pcr_after; + size_t hash_size, pcr_len; + u_int32_t extended_pcr; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; + + switch (this->seq_no++) + { + case 0: + /* dummy data since currently the TBOOT log is not retrieved */ + time(&this->measurement_time); + meas_hex = lib->settings->get_str(lib->settings, + "libimcv.plugins.imc-attestation.pcr17_meas", NULL); + pcr_before_hex = lib->settings->get_str(lib->settings, + "libimcv.plugins.imc-attestation.pcr17_before", NULL); + pcr_after_hex = lib->settings->get_str(lib->settings, + "libimcv.plugins.imc-attestation.pcr17_after", NULL); + extended_pcr = PCR_TBOOT_POLICY; + break; + case 1: + /* dummy data since currently the TBOOT log is not retrieved */ + meas_hex = lib->settings->get_str(lib->settings, + "libimcv.plugins.imc-attestation.pcr18_meas", NULL); + pcr_before_hex = lib->settings->get_str(lib->settings, + "libimcv.plugins.imc-attestation.pcr18_before", NULL); + pcr_after_hex = lib->settings->get_str(lib->settings, + "libimcv.plugins.imc-attestation.pcr18_after", NULL); + extended_pcr = PCR_TBOOT_MLE; + break; + default: + return FAILED; + } + + hash_algo = pts->get_meas_algorithm(pts); + hash_size = pts_meas_algo_hash_size(hash_algo); + pcr_len = pts->get_pcr_len(pts); + pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + + /* get and check the measurement data */ + measurement = chunk_from_hex( + chunk_create(meas_hex, strlen(meas_hex)), NULL); + pcr_before = chunk_from_hex( + chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL); + pcr_after = chunk_from_hex( + chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL); + if (pcr_before.len != pcr_len || pcr_after.len != pcr_len || + measurement.len != hash_size) + { + DBG1(DBG_PTS, "TBOOT measurement or pcr data have the wrong size"); + free(measurement.ptr); + free(pcr_before.ptr); + free(pcr_after.ptr); + return FAILED; + } + + evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), + this->depth, extended_pcr, + hash_algo, pcr_transform, + this->measurement_time, measurement); + evid->set_pcr_info(evid, pcr_before, pcr_after); + + return (this->seq_no < 2) ? NEED_MORE : SUCCESS; +} + +METHOD(pts_component_t, verify, status_t, + pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t *evidence) +{ + bool has_pcr_info; + u_int32_t extended_pcr, vid, name; + enum_name_t *names; + pts_meas_algorithms_t algo; + pts_pcr_transform_t transform; + time_t measurement_time; + chunk_t measurement, pcr_before, pcr_after; + + measurement = evidence->get_measurement(evidence, &extended_pcr, + &algo, &transform, &measurement_time); + + if (!this->keyid.ptr) + { + if (!pts->get_aik_keyid(pts, &this->keyid)) + { + return FAILED; + } + this->keyid = chunk_clone(this->keyid); + + if (!this->pts_db) + { + DBG1(DBG_PTS, "pts database not available"); + return FAILED; + } + if (this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->keyid, algo, + &this->cid, &this->kid, &this->count) != SUCCESS) + { + return FAILED; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (this->count) + { + DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence " + "measurements", this->count, pen_names, vid, names, name); + } + else + { + DBG1(DBG_PTS, "registering %N '%N' functional component evidence " + "measurements", pen_names, vid, names, name); + this->is_registering = TRUE; + } + } + + if (this->is_registering) + { + if (this->pts_db->insert_comp_measurement(this->pts_db, measurement, + this->cid, this->kid, ++this->seq_no, + extended_pcr, algo) != SUCCESS) + { + return FAILED; + } + this->count = this->seq_no + 1; + } + else + { + if (this->pts_db->check_comp_measurement(this->pts_db, measurement, + this->cid, this->kid, ++this->seq_no, + extended_pcr, algo) != SUCCESS) + { + return FAILED; + } + } + + has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); + if (has_pcr_info) + { + if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after)) + { + return FAILED; + } + } + + return (this->seq_no < this->count) ? NEED_MORE : SUCCESS; +} + +METHOD(pts_component_t, check_off_registrations, bool, + pts_ita_comp_tboot_t *this) +{ + u_int32_t vid, name; + enum_name_t *names; + + if (!this->is_registering) + { + return FALSE; + } + + /* Finalize registration */ + this->is_registering = FALSE; + + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence " + "measurements", this->seq_no, pen_names, vid, names, name); + return TRUE; +} + +METHOD(pts_component_t, destroy, void, + pts_ita_comp_tboot_t *this) +{ + int count; + u_int32_t vid, name; + enum_name_t *names; + + if (this->is_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->cid, this->kid); + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component " + "evidence measurements", count, pen_names, vid, names, name); + } + this->name->destroy(this->name); + free(this->keyid.ptr); + free(this); +} + +/** + * See header + */ +pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth, + pts_database_t *pts_db) +{ + pts_ita_comp_tboot_t *this; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_evidence_flags = _get_evidence_flags, + .get_depth = _get_depth, + .measure = _measure, + .verify = _verify, + .check_off_registrations = _check_off_registrations, + .destroy = _destroy, + }, + .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT, + qualifier), + .depth = depth, + .pts_db = pts_db, + ); + + return &this->public; +} + diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.h b/src/libpts/pts/components/ita/ita_comp_tboot.h new file mode 100644 index 000000000..39554fbc7 --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_tboot.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_TBOOT_H_ +#define PTS_ITA_COMP_TBOOT_H_ + +#include "pts/components/pts_component.h" + +/** + * Create a PTS ITS Functional Component object + * + * @param qualifier PTS Component Functional Name Qualifier + * @param depth Sub-component depth + * @param pts_db PTS measurement database + */ +pts_component_t* pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth, + pts_database_t *pts_db); + +#endif /** PTS_ITA_COMP_TBOOT_H_ @}*/ diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.c b/src/libpts/pts/components/ita/ita_comp_tgrub.c new file mode 100644 index 000000000..0dfd5fd41 --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_tgrub.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * + * HSR 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 "ita_comp_tgrub.h" +#include "ita_comp_func_name.h" + +#include "pts/components/pts_component.h" + +#include <debug.h> +#include <pen/pen.h> + +typedef struct pts_ita_comp_tgrub_t pts_ita_comp_tgrub_t; + +/** + * Private data of a pts_ita_comp_tgrub_t object. + * + */ +struct pts_ita_comp_tgrub_t { + + /** + * Public pts_component_t interface. + */ + pts_component_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * Sub-component depth + */ + u_int32_t depth; + + /** + * PTS measurement database + */ + pts_database_t *pts_db; + +}; + +METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, + pts_ita_comp_tgrub_t *this) +{ + return this->name; +} + +METHOD(pts_component_t, get_evidence_flags, u_int8_t, + pts_ita_comp_tgrub_t *this) +{ + return PTS_REQ_FUNC_COMP_EVID_PCR; +} + +METHOD(pts_component_t, get_depth, u_int32_t, + pts_ita_comp_tgrub_t *this) +{ + return this->depth; +} + +METHOD(pts_component_t, measure, status_t, + pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t **evidence) +{ + pts_comp_evidence_t *evid; + u_int32_t extended_pcr; + time_t measurement_time; + chunk_t measurement, pcr_before, pcr_after; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; + size_t hash_size, pcr_len; + + /* Provisional implementation for TGRUB */ + extended_pcr = PCR_DEBUG; + time(&measurement_time); + + if (!pts->read_pcr(pts, extended_pcr, &pcr_after)) + { + DBG1(DBG_PTS, "error occurred while reading PCR: %d", extended_pcr); + return FAILED; + } + + hash_algo = pts->get_meas_algorithm(pts); + hash_size = pts_meas_algo_hash_size(hash_algo); + pcr_len = pts->get_pcr_len(pts); + pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + + measurement = chunk_alloc(hash_size); + memset(measurement.ptr, 0x00, measurement.len); + + pcr_before = chunk_alloc(pcr_len); + memset(pcr_before.ptr, 0x00, pcr_before.len); + + evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), + this->depth, extended_pcr, + hash_algo, pcr_transform, + measurement_time, measurement); + evid->set_pcr_info(evid, pcr_before, pcr_after); + + return SUCCESS; +} + +METHOD(pts_component_t, verify, status_t, + pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t *evidence) +{ + bool has_pcr_info; + u_int32_t extended_pcr; + pts_meas_algorithms_t algo; + pts_pcr_transform_t transform; + time_t measurement_time; + chunk_t measurement, pcr_before, pcr_after; + + measurement = evidence->get_measurement(evidence, &extended_pcr, + &algo, &transform, &measurement_time); + if (extended_pcr != PCR_DEBUG) + { + return FAILED; + } + + /* TODO check measurement in database */ + + has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); + if (has_pcr_info) + { + if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after)) + { + return FAILED; + } + } + + return SUCCESS; +} + +METHOD(pts_component_t, check_off_registrations, bool, + pts_ita_comp_tgrub_t *this) +{ + return FALSE; +} + +METHOD(pts_component_t, destroy, void, + pts_ita_comp_tgrub_t *this) +{ + this->name->destroy(this->name); + free(this); +} + +/** + * See header + */ +pts_component_t *pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth, + pts_database_t *pts_db) +{ + pts_ita_comp_tgrub_t *this; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_evidence_flags = _get_evidence_flags, + .get_depth = _get_depth, + .measure = _measure, + .verify = _verify, + .check_off_registrations = _check_off_registrations, + .destroy = _destroy, + }, + .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TGRUB, + qualifier), + .depth = depth, + .pts_db = pts_db, + ); + + return &this->public; +} + diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.h b/src/libpts/pts/components/ita/ita_comp_tgrub.h new file mode 100644 index 000000000..52ecc325c --- /dev/null +++ b/src/libpts/pts/components/ita/ita_comp_tgrub.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_TGRUB_H_ +#define PTS_ITA_COMP_TGRUB_H_ + +#include "pts/components/pts_component.h" + +/** + * Create a PTS ITS Functional Component object + * + * @param qualifier PTS Component Functional Name Qualifier + * @param depth Sub-component depth + * @param pts_db PTS measurement database + */ +pts_component_t* pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth, + pts_database_t *pts_db); + +#endif /** PTS_ITA_COMP_TGRUB_H_ @}*/ diff --git a/src/libpts/pts/components/pts_comp_evidence.c b/src/libpts/pts/components/pts_comp_evidence.c new file mode 100644 index 000000000..9eb8dae75 --- /dev/null +++ b/src/libpts/pts/components/pts_comp_evidence.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu, Andreas Steffen + * HSR 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 "pts/components/pts_comp_evidence.h" + +#include <debug.h> + +typedef struct private_pts_comp_evidence_t private_pts_comp_evidence_t; + +/** + * Private data of a pts_comp_evidence_t object. + */ +struct private_pts_comp_evidence_t { + + /** + * Public pts_comp_evidence_t interface. + */ + pts_comp_evidence_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * Sub-Component Depth + */ + u_int32_t depth; + + /** + * Measurement Time + */ + time_t measurement_time; + + /** + * Measurement Time + */ + chunk_t measurement; + + /** + * Measurement Hash Algorithm + */ + pts_meas_algorithms_t hash_algorithm; + + /** + * Is PCR Information included? + */ + bool has_pcr_info; + + /** + * PCR the measurement was extended into + */ + u_int32_t extended_pcr; + + /** + * PCR value before extension + */ + chunk_t pcr_before; + + /** + * PCR value after extension + */ + chunk_t pcr_after; + + /** + * Transformation used for extending measurement into PCR + */ + pts_pcr_transform_t transform; + + /** + * Component Validation Result + */ + pts_comp_evid_validation_t validation; + + /** + * Verification Policy URI + */ + chunk_t policy_uri; + +}; + +METHOD(pts_comp_evidence_t, get_comp_func_name, pts_comp_func_name_t*, + private_pts_comp_evidence_t *this, u_int32_t *depth) +{ + if (depth) + { + *depth = this->depth; + } + return this->name; +} + +METHOD(pts_comp_evidence_t, get_extended_pcr, u_int32_t, + private_pts_comp_evidence_t *this) +{ + return this->extended_pcr; +} + +METHOD(pts_comp_evidence_t, get_measurement, chunk_t, + private_pts_comp_evidence_t *this, u_int32_t *extended_pcr, + pts_meas_algorithms_t *algo, pts_pcr_transform_t *transform, + time_t *measurement_time) +{ + if (extended_pcr) + { + *extended_pcr = this->extended_pcr; + } + if (algo) + { + *algo = this->hash_algorithm; + } + if (transform) + { + *transform = this->transform; + } + if (measurement_time) + { + *measurement_time = this->measurement_time; + } + return this->measurement; +} + +METHOD(pts_comp_evidence_t, get_pcr_info, bool, + private_pts_comp_evidence_t *this, chunk_t *pcr_before, chunk_t *pcr_after) +{ + if (pcr_before) + { + *pcr_before = this->pcr_before; + } + if (pcr_after) + { + *pcr_after = this->pcr_after; + } + return this->has_pcr_info; +} + +METHOD(pts_comp_evidence_t, set_pcr_info, void, + private_pts_comp_evidence_t *this, chunk_t pcr_before, chunk_t pcr_after) +{ + this->has_pcr_info = TRUE; + this->pcr_before = pcr_before; + this->pcr_after = pcr_after; + + DBG2(DBG_PTS, "PCR %2d before value : %#B", this->extended_pcr, &pcr_before); + DBG2(DBG_PTS, "PCR %2d after value : %#B", this->extended_pcr, &pcr_after); +} + +METHOD(pts_comp_evidence_t, get_validation, pts_comp_evid_validation_t, + private_pts_comp_evidence_t *this, chunk_t *uri) +{ + if (uri) + { + *uri = this->policy_uri; + } + return this->validation; +} + +METHOD(pts_comp_evidence_t, set_validation, void, + private_pts_comp_evidence_t *this, pts_comp_evid_validation_t validation, + chunk_t uri) +{ + this->validation = validation; + this->policy_uri = chunk_clone(uri); +} + +METHOD(pts_comp_evidence_t, destroy, void, + private_pts_comp_evidence_t *this) +{ + this->name->destroy(this->name); + free(this->measurement.ptr); + free(this->pcr_before.ptr); + free(this->pcr_after.ptr); + free(this->policy_uri.ptr); + free(this); +} + +/** + * See header + */ +pts_comp_evidence_t *pts_comp_evidence_create(pts_comp_func_name_t *name, + u_int32_t depth, + u_int32_t extended_pcr, + pts_meas_algorithms_t algo, + pts_pcr_transform_t transform, + time_t measurement_time, + chunk_t measurement) +{ + private_pts_comp_evidence_t *this; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_extended_pcr = _get_extended_pcr, + .get_measurement = _get_measurement, + .get_pcr_info = _get_pcr_info, + .set_pcr_info = _set_pcr_info, + .get_validation = _get_validation, + .set_validation = _set_validation, + .destroy = _destroy, + }, + .name = name, + .depth = depth, + .extended_pcr = extended_pcr, + .hash_algorithm = algo, + .transform = transform, + .measurement_time = measurement_time, + .measurement = measurement, + ); + + name->log(name, ""); + DBG2(DBG_PTS, "measurement time: %T", &measurement_time, FALSE); + DBG2(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement); + + return &this->public; +} + +/** + * See header + */ +pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo, + size_t pcr_len) +{ + size_t hash_size; + + hash_size = pts_meas_algo_hash_size(algo); + if (hash_size == 0) + { + return PTS_PCR_TRANSFORM_NO; + } + if (hash_size == pcr_len) + { + return PTS_PCR_TRANSFORM_MATCH; + } + if (hash_size > pcr_len) + { + return PTS_PCR_TRANSFORM_LONG; + } + return PTS_PCR_TRANSFORM_SHORT; +} + diff --git a/src/libpts/pts/components/pts_comp_evidence.h b/src/libpts/pts/components/pts_comp_evidence.h new file mode 100644 index 000000000..fe86aa940 --- /dev/null +++ b/src/libpts/pts/components/pts_comp_evidence.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu, Andreas Steffen + * HSR 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 pts_comp_evidence pts_comp_evidence + * @{ @ingroup pts + */ + +#ifndef PTS_COMP_EVIDENCE_H_ +#define PTS_COMP_EVIDENCE_H_ + +typedef struct pts_comp_evidence_t pts_comp_evidence_t; +typedef enum pts_pcr_transform_t pts_pcr_transform_t; +typedef enum pts_comp_evid_validation_t pts_comp_evid_validation_t; + +#include "pts/pts_meas_algo.h" +#include "pts/components/pts_comp_func_name.h" + +#include <library.h> + +/** + * PTS PCR Transformations + */ +enum pts_pcr_transform_t { + /** No Transformation */ + PTS_PCR_TRANSFORM_NO = 0, + /** Hash Value matched PCR size */ + PTS_PCR_TRANSFORM_MATCH = 1, + /** Hash value shorter than PCR size */ + PTS_PCR_TRANSFORM_SHORT = 2, + /** Hash value longer than PCR size */ + PTS_PCR_TRANSFORM_LONG = 3, +}; + +/** + * PTS Component Evidence Validation Result Flags + */ +enum pts_comp_evid_validation_t { + /** No Validation was attempted */ + PTS_COMP_EVID_VALIDATION_NONE = 0x00, + /** Attempted validation, unable to verify */ + PTS_COMP_EVID_VALIDATION_UNABLE = 0x20, + /** Attempted validation, verification failed */ + PTS_COMP_EVID_VALIDATION_FAILED = 0x40, + /** Attempted validation, verification passed */ + PTS_COMP_EVID_VALIDATION_PASSED = 0x60, +}; + +/** + * PTS Functional Component Interface + */ +struct pts_comp_evidence_t { + + /** + * Gets the Component Functional Name and Sub-Component Depth + * + * @param depth Sub-Component Depth + * @result Component Functional Name + */ + pts_comp_func_name_t* (*get_comp_func_name)(pts_comp_evidence_t *this, + u_int32_t *depth); + + /** + * Gets the PCR the measurement was extended into + * + * @result PCR the measurement was extended into + */ + u_int32_t (*get_extended_pcr)(pts_comp_evidence_t *this); + + /** + * Gets the measurement and the algorithms used + * + * @param extended_pcr PCR the measurement was extended into + * @param algo Measurement hash algorithm + * @param transform Transformation used for PCR extension + * @param measurement_time Time the measurement was taken + * @result Measurement hash value + */ + chunk_t (*get_measurement)(pts_comp_evidence_t *this, + u_int32_t *extended_pcr, + pts_meas_algorithms_t *algo, + pts_pcr_transform_t *transform, + time_t *measurement_time); + + /** + * Gets the PCR information if available + * + * @param pcr_before PCR value before extension + * @param pcr_after PCR value after extension + * @result TRUE if PCR information is available + */ + bool (*get_pcr_info)(pts_comp_evidence_t *this, chunk_t *pcr_before, + chunk_t *pcr_after); + + /** + * Sets PCR information if available + * + * @param pcr_before PCR value before extension + * @param pcr_after PCR value after extension + */ + void (*set_pcr_info)(pts_comp_evidence_t *this, chunk_t pcr_before, + chunk_t pcr_after); + + /** + * Gets Validation Result if available + * + * @param uri Verification Policy URI + * @return validation Validation Result + */ + pts_comp_evid_validation_t (*get_validation)(pts_comp_evidence_t *this, + chunk_t *uri); + + /** + * Sets Validation Result if available + * + * @param validation Validation Result + * @param uri Verification Policy URI + */ + void (*set_validation)(pts_comp_evidence_t *this, + pts_comp_evid_validation_t validation, chunk_t uri); + + /** + * Destroys a pts_comp_evidence_t object. + */ + void (*destroy)(pts_comp_evidence_t *this); + +}; + +/** + * Creates a pts_comp_evidence_t object + * + * @param name Component Functional Name + * @param depth Sub-component depth + * @param extended_pcr PCR the measurement was extended into + * @param algo Measurement hash algorithm + * @param transform Transformation used for PCR extension + * @param measurement_time Time the measurement was taken, 0 if unknown + * @param measurement Measurement hash value + */ +pts_comp_evidence_t* pts_comp_evidence_create(pts_comp_func_name_t *name, + u_int32_t depth, + u_int32_t extended_pcr, + pts_meas_algorithms_t algo, + pts_pcr_transform_t transform, + time_t measurement_time, + chunk_t measurement); + +/** + * Determine transform to fit measurement hash into PCR register + * + * @param algo Measurement hash algorithm + * @param pcr_len Length of the PCR registers in bytes + * @return PCR transform type + */ +pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo, + size_t pcr_len); + +#endif /** PTS_COMP_EVIDENCE_H_ @}*/ diff --git a/src/libpts/pts/components/pts_comp_func_name.c b/src/libpts/pts/components/pts_comp_func_name.c new file mode 100644 index 000000000..d98850d78 --- /dev/null +++ b/src/libpts/pts/components/pts_comp_func_name.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * + * HSR 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 "libpts.h" +#include "pts/components/pts_comp_func_name.h" + +#include <debug.h> + +typedef struct private_pts_comp_func_name_t private_pts_comp_func_name_t; + +/** + * Private data of a pts_comp_func_name_t object. + * + */ +struct private_pts_comp_func_name_t { + + /** + * Public pts_comp_func_name_t interface. + */ + pts_comp_func_name_t public; + + /** + * PTS Component Functional Name Vendor ID + */ + u_int32_t vid; + + /** + * PTS Component Functional Name + */ + u_int32_t name; + + /** + * PTS Component Functional Name Qualifier + */ + u_int8_t qualifier; + +}; + +METHOD(pts_comp_func_name_t, get_vendor_id, u_int32_t, + private_pts_comp_func_name_t *this) +{ + return this->vid; +} + +METHOD(pts_comp_func_name_t, get_name, u_int32_t, + private_pts_comp_func_name_t *this) +{ + return this->name; +} + +METHOD(pts_comp_func_name_t, get_qualifier, u_int8_t, + private_pts_comp_func_name_t *this) +{ + return this->qualifier; +} + +static bool equals(private_pts_comp_func_name_t *this, + private_pts_comp_func_name_t *other) +{ + if (this->vid != other->vid || this->name != other->name) + { + return FALSE; + } + if (this->qualifier == PTS_QUALIFIER_UNKNOWN || + other->qualifier == PTS_QUALIFIER_UNKNOWN) + { + return TRUE; + } + /* TODO handle qualifier wildcards */ + + return this->qualifier == other->qualifier; +} + +METHOD(pts_comp_func_name_t, clone_, pts_comp_func_name_t*, + private_pts_comp_func_name_t *this) +{ + private_pts_comp_func_name_t *clone; + + clone = malloc_thing(private_pts_comp_func_name_t); + memcpy(clone, this, sizeof(private_pts_comp_func_name_t)); + + return &clone->public; +} + +METHOD(pts_comp_func_name_t, log_, void, + private_pts_comp_func_name_t *this, char *label) +{ + enum_name_t *names, *types; + char flags[8]; + int type; + + names = pts_components->get_comp_func_names(pts_components, this->vid); + types = pts_components->get_qualifier_type_names(pts_components, this->vid); + type = pts_components->get_qualifier(pts_components, &this->public, flags); + + if (names && types) + { + DBG2(DBG_PTS, "%s%N functional component '%N' [%s] '%N'", + label, pen_names, this->vid, names, this->name, flags, types, type); + } + else + { + DBG2(DBG_PTS, "%s0x%06x functional component 0x%08x 0x%02x", + label, this->vid, this->name, this->qualifier); + } +} + +METHOD(pts_comp_func_name_t, destroy, void, + private_pts_comp_func_name_t *this) +{ + free(this); +} + +/** + * See header + */ +pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name, + u_int8_t qualifier) +{ + private_pts_comp_func_name_t *this; + + INIT(this, + .public = { + .get_vendor_id = _get_vendor_id, + .get_name = _get_name, + .get_qualifier = _get_qualifier, + .equals = (bool(*)(pts_comp_func_name_t*,pts_comp_func_name_t*))equals, + .clone = _clone_, + .log = _log_, + .destroy = _destroy, + }, + .vid = vid, + .name = name, + .qualifier = qualifier, + ); + + return &this->public; +} + diff --git a/src/libpts/pts/components/pts_comp_func_name.h b/src/libpts/pts/components/pts_comp_func_name.h new file mode 100644 index 000000000..2c7a84177 --- /dev/null +++ b/src/libpts/pts/components/pts_comp_func_name.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_comp_func_name pts_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_FUNC_COMP_NAME_H_ +#define PTS_FUNC_COMP_NAME_H_ + +typedef struct pts_comp_func_name_t pts_comp_func_name_t; + +#include <library.h> + +#define PTS_QUALIFIER_UNKNOWN 0x00 +#define PTS_QUALIFIER_WILDCARD 0x3F + +/** + * PTS Component Functional Name object + */ +struct pts_comp_func_name_t { + + /** + * Get the PTS Component Functional Name Vendor ID + * + * @return PTS Component Functional Name Vendor ID + */ + u_int32_t (*get_vendor_id)(pts_comp_func_name_t *this); + + /** + * Get the PTS Component Functional Name + * + * @return PTS Component Functional Name + */ + u_int32_t (*get_name)(pts_comp_func_name_t *this); + + /** + * Get the PTS Component Functional Name Qualifier + * + * @return PTS Component Functional Name Qualifier + */ + u_int8_t (*get_qualifier)(pts_comp_func_name_t *this); + + /** + * Check to PTS Component Functional Names for equality + * + * @param other Other PTS Component Functional Name + * @return TRUE if equal + */ + bool (*equals)(pts_comp_func_name_t *this, pts_comp_func_name_t *other); + + /** + * Clone a PTS Component Functional Name + * + * @return Cloned PTS Component Functional Name + */ + pts_comp_func_name_t* (*clone)(pts_comp_func_name_t *this); + + /** + * Write PTS Component Functional Name information to the standard logfile + * + * @param label Label added to log output + */ + void (*log)(pts_comp_func_name_t *this, char *label); + + /** + * Destroys a pts_component_t object. + */ + void (*destroy)(pts_comp_func_name_t *this); + +}; + +/** + * Create a PTS Component Functional Name object + * + * @param vid PTS Component Functional Name Vendor ID + * @param name PTS Component Functional Name + * @param PTS Component Functional Name Qualifier + */ +pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name, + u_int8_t qualifier); + +#endif /** PTS_FUNC_COMP_NAME_H_ @}*/ diff --git a/src/libpts/pts/components/pts_component.h b/src/libpts/pts/components/pts_component.h new file mode 100644 index 000000000..524ff332d --- /dev/null +++ b/src/libpts/pts/components/pts_component.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 pts_component pts_component + * @{ @ingroup pts + */ + +#ifndef PTS_COMPONENT_H_ +#define PTS_COMPONENT_H_ + +typedef struct pts_component_t pts_component_t; + +#include "pts/pts.h" +#include "pts/pts_database.h" +#include "pts/components/pts_comp_func_name.h" +#include "pts/components/pts_comp_evidence.h" + +#include <library.h> + +/** + * PTS Functional Component Interface + */ +struct pts_component_t { + + /** + * Get the PTS Component Functional Name + * + * @return PTS Component Functional Name + */ + pts_comp_func_name_t* (*get_comp_func_name)(pts_component_t *this); + + /** + * Get the PTS Component Evidence Flags + * + * @return PTS Component Functional Name + */ + u_int8_t (*get_evidence_flags)(pts_component_t *this); + + /** + * Get the PTS Sub-component Depth + * + * @return PTS Sub-component Depth + */ + u_int32_t (*get_depth)(pts_component_t *this); + + /** + * Do evidence measurements on the PTS Functional Component + * + * @param pts PTS interface + * @param evidence returns component evidence measureemt + * @return status return code + */ + status_t (*measure)(pts_component_t *this, pts_t *pts, + pts_comp_evidence_t** evidence); + + /** + * Verify the evidence measurements of the PTS Functional Component + * + * @param pts PTS interface + * @param evidence component evidence measurement to be verified + * @return status return code + */ + status_t (*verify)(pts_component_t *this, pts_t *pts, + pts_comp_evidence_t *evidence); + + + /** + * Tell the PTS Functional Component to finalize pending registrations + * + * @return TRUE if there are pending registrations + */ + bool (*check_off_registrations)(pts_component_t *this); + + /** + * Destroys a pts_component_t object. + */ + void (*destroy)(pts_component_t *this); + +}; + +#endif /** PTS_COMPONENT_H_ @}*/ diff --git a/src/libpts/pts/components/pts_component_manager.c b/src/libpts/pts/components/pts_component_manager.c new file mode 100644 index 000000000..8ac4767bf --- /dev/null +++ b/src/libpts/pts/components/pts_component_manager.c @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * + * HSR 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 "pts/components/pts_component_manager.h" + +#include <utils/linked_list.h> +#include <debug.h> + +typedef struct private_pts_component_manager_t private_pts_component_manager_t; +typedef struct vendor_entry_t vendor_entry_t; +typedef struct component_entry_t component_entry_t; + +#define PTS_QUALIFIER_SIZE 6 + +/** + * Vendor-specific namespace information and list of registered components + */ +struct vendor_entry_t { + + /** + * Vendor ID + */ + pen_t vendor_id; + + /** + * Vendor-specific Component Functional names + */ + enum_name_t *comp_func_names; + + /** + * Vendor-specific Qualifier Type names + */ + enum_name_t *qualifier_type_names; + + /** + * Vendor-specific Qualifier Flag names + */ + char *qualifier_flag_names; + + /** + * Vendor-specific size of Qualfiier Type field + */ + int qualifier_type_size; + + /** + * List of vendor-specific registered Functional Components + */ + linked_list_t *components; +}; + +/** + * Destroy a vendor_entry_t object + */ +static void vendor_entry_destroy(vendor_entry_t *entry) +{ + entry->components->destroy_function(entry->components, free); + free(entry); +} + +/** + * Creation method for a vendor-specific Functional Component + */ +struct component_entry_t { + + /** + * Vendor-Specific Component Functional Name + */ + u_int32_t name; + + /** + * Functional Component creation method + */ + pts_component_create_t create; +}; + +/** + * Private data of a pts_component_manager_t object. + * + */ +struct private_pts_component_manager_t { + + /** + * Public pts_component_manager_t interface. + */ + pts_component_manager_t public; + + /** + * List of vendor-specific namespaces and registered components + */ + linked_list_t *list; +}; + +METHOD(pts_component_manager_t, add_vendor, void, + private_pts_component_manager_t *this, pen_t vendor_id, + enum_name_t *comp_func_names, int qualifier_type_size, + char *qualifier_flag_names, enum_name_t *qualifier_type_names) +{ + vendor_entry_t *entry; + + entry = malloc_thing(vendor_entry_t); + entry->vendor_id = vendor_id; + entry->comp_func_names = comp_func_names; + entry->qualifier_type_size = qualifier_type_size; + entry->qualifier_flag_names = qualifier_flag_names; + entry->qualifier_type_names = qualifier_type_names; + entry->components = linked_list_create(); + + this->list->insert_last(this->list, entry); + DBG2(DBG_PTS, "added %N functional component namespace", + pen_names, vendor_id); +} + +METHOD(pts_component_manager_t, get_comp_func_names, enum_name_t*, + private_pts_component_manager_t *this, pen_t vendor_id) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + enum_name_t *names = NULL; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + names = entry->comp_func_names; + break; + } + } + enumerator->destroy(enumerator); + + return names; +} + +METHOD(pts_component_manager_t, get_qualifier_type_names, enum_name_t*, + private_pts_component_manager_t *this, pen_t vendor_id) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + enum_name_t *names = NULL; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + names = entry->qualifier_type_names; + break; + } + } + enumerator->destroy(enumerator); + + return names; +} + +METHOD(pts_component_manager_t, add_component, void, + private_pts_component_manager_t *this, pen_t vendor_id, u_int32_t name, + pts_component_create_t create) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + component_entry_t *component; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + component = malloc_thing(component_entry_t); + component->name = name; + component->create = create; + + entry->components->insert_last(entry->components, component); + DBG2(DBG_PTS, "added %N functional component '%N'", + pen_names, vendor_id, + get_comp_func_names(this, vendor_id), name); + } + } + enumerator->destroy(enumerator); +} + +METHOD(pts_component_manager_t, remove_vendor, void, + private_pts_component_manager_t *this, pen_t vendor_id) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + this->list->remove_at(this->list, enumerator); + vendor_entry_destroy(entry); + DBG2(DBG_PTS, "removed %N functional component namespace", + pen_names, vendor_id); + } + } + enumerator->destroy(enumerator); +} + +METHOD(pts_component_manager_t, get_qualifier, u_int8_t, + private_pts_component_manager_t *this, pts_comp_func_name_t *name, + char *flags) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + u_int8_t qualifier, size, flag, type = 0; + int i; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == name->get_vendor_id(name)) + { + qualifier = name->get_qualifier(name); + size = entry->qualifier_type_size; + + /* mask qualifier type field */ + type = qualifier & ((1 << size) - 1); + + /* determine flags */ + size = PTS_QUALIFIER_SIZE - size; + flag = (1 << (PTS_QUALIFIER_SIZE - 1)); + if (flags) + { + for (i = 0 ; i < size; i++) + { + flags[i] = (qualifier & flag) ? + entry->qualifier_flag_names[i] : '.'; + flag >>= 1; + } + flags[size] = '\0'; + } + } + } + enumerator->destroy(enumerator); + + return type; +} + +METHOD(pts_component_manager_t, create, pts_component_t*, + private_pts_component_manager_t *this, + pts_comp_func_name_t *name, u_int32_t depth, pts_database_t *pts_db) +{ + enumerator_t *enumerator, *e2; + vendor_entry_t *entry; + component_entry_t *entry2; + pts_component_t *component = NULL; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == name->get_vendor_id(name)) + { + e2 = entry->components->create_enumerator(entry->components); + while (e2->enumerate(e2, &entry2)) + { + if (entry2->name == name->get_name(name) && entry2->create) + { + component = entry2->create(name->get_qualifier(name), + depth, pts_db); + break; + } + } + e2->destroy(e2); + break; + } + } + enumerator->destroy(enumerator); + + return component; +} + +METHOD(pts_component_manager_t, destroy, void, + private_pts_component_manager_t *this) +{ + this->list->destroy_function(this->list, (void *)vendor_entry_destroy); + free(this); +} + +/** + * See header + */ +pts_component_manager_t *pts_component_manager_create(void) +{ + private_pts_component_manager_t *this; + + INIT(this, + .public = { + .add_vendor = _add_vendor, + .add_component = _add_component, + .remove_vendor = _remove_vendor, + .get_comp_func_names = _get_comp_func_names, + .get_qualifier_type_names = _get_qualifier_type_names, + .get_qualifier = _get_qualifier, + .create = _create, + .destroy = _destroy, + }, + .list = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/libpts/pts/components/pts_component_manager.h b/src/libpts/pts/components/pts_component_manager.h new file mode 100644 index 000000000..0079d0e26 --- /dev/null +++ b/src/libpts/pts/components/pts_component_manager.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 pts_component_manager pts_component_manager + * @{ @ingroup pts + */ + +#ifndef PTS_COMPONENT_MANAGER_H_ +#define PTS_COMPONENT_MANAGER_H_ + +typedef struct pts_component_manager_t pts_component_manager_t; + +#include "pts/pts_database.h" +#include "pts/components/pts_component.h" +#include "pts/components/pts_comp_func_name.h" + +#include <library.h> +#include <pen/pen.h> + +typedef pts_component_t* (*pts_component_create_t)(u_int8_t qualifier, + u_int32_t depth, + pts_database_t *pts_db); + +/** + * Manages PTS Functional Components + */ +struct pts_component_manager_t { + + /** + * Add vendor-specific functional component names + * + * @param vendor_id Private Enterprise Number (PEN) + * @param comp_func_names Vendor-specific Component Functional names + * @param qualifier_type_size Vendor-specific Qualifier Type size + * @param qualifier_flag_names Vendor-specific Qualifier Flag names + * @param qualifier_type_names Vendor-specific Qualifier Type names + */ + void (*add_vendor)(pts_component_manager_t *this, pen_t vendor_id, + enum_name_t *comp_func_names, + int qualifier_type_size, + char *qualifier_flag_names, + enum_name_t *qualifier_type_names); + + /** + * Add vendor-specific functional component + * + * @param vendor_id Private Enterprise Number (PEN) + * @param names Component Functional Name + * @param create Functional Component creation method + */ + void (*add_component)(pts_component_manager_t *this, pen_t vendor_id, + u_int32_t name, pts_component_create_t create); + + /** + * Remove vendor-specific components and associated namespace + * + * @param vendor_id Private Enterprise Number (PEN) + */ + void (*remove_vendor)(pts_component_manager_t *this, pen_t vendor_id); + + /** + * Return the Functional Component names for a given vendor ID + * + * @param vendor_id Private Enterprise Number (PEN) + * @return Comp. Func. names if found, NULL else + */ + enum_name_t* (*get_comp_func_names)(pts_component_manager_t *this, + pen_t vendor_id); + + /** + * Return the Functional Component Qualifier Type names for a given vendor ID + * + * @param vendor_id Private Enterprise Number (PEN) + * @return Qualifier Type names if found, NULL else + */ + enum_name_t* (*get_qualifier_type_names)(pts_component_manager_t *this, + pen_t vendor_id); + + /** + * Return the Qualifier Type and Flags + * + * @param name Component Functional Name + * @param flags Qualifier Flags as a string in a char buffer + * @return Qualifier Type + */ + u_int8_t (*get_qualifier)(pts_component_manager_t *this, + pts_comp_func_name_t *name, char *flags); + + /** + * Create a PTS Component object from a Functional Component Name object + * + * @param name Component Functional Name + * @param depth Sub-component Depth + * @param pts_db PTS measurement database + * @return Component object if supported, NULL else + */ + pts_component_t* (*create)(pts_component_manager_t *this, + pts_comp_func_name_t *name, u_int32_t depth, + pts_database_t *pts_db); + + /** + * Destroys a pts_component_manager_t object. + */ + void (*destroy)(pts_component_manager_t *this); +}; + +/** + * Create a PA-TNC attribute manager + */ +pts_component_manager_t* pts_component_manager_create(void); + +#endif /** PTS_COMPONENT_MANAGER_H_ @}*/ diff --git a/src/libpts/pts/components/tcg/tcg_comp_func_name.c b/src/libpts/pts/components/tcg/tcg_comp_func_name.c new file mode 100644 index 000000000..a70c84e48 --- /dev/null +++ b/src/libpts/pts/components/tcg/tcg_comp_func_name.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 "tcg_comp_func_name.h" + +char pts_tcg_qualifier_flag_names[] = { 'K', 'S' }; + +ENUM_BEGIN(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_UNKNOWN, + PTS_TCG_QUALIFIER_TYPE_TNC, + "Unknown", + "Trusted Platform", + "Operating System", + "Graphical User Interface", + "Application", + "Networking", + "Library", + "TNC Defined Component" +); +ENUM_NEXT(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL, + PTS_TCG_QUALIFIER_TYPE_ALL, + PTS_TCG_QUALIFIER_TYPE_TNC, + "All Matching Components" +); +ENUM_END(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL); + +ENUM(pts_tcg_comp_func_names, PTS_TCG_COMP_FUNC_NAME_IGNORE, + PTS_TCG_COMP_FUNC_NAME_OPT_ROMS, + "Ignore", + "CRTM", + "BIOS", + "Platform Extensions", + "Motherboard Firmware", + "Initial Program Loader", + "Option ROMs" +); + diff --git a/src/libpts/pts/components/tcg/tcg_comp_func_name.h b/src/libpts/pts/components/tcg/tcg_comp_func_name.h new file mode 100644 index 000000000..9708ad09d --- /dev/null +++ b/src/libpts/pts/components/tcg/tcg_comp_func_name.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_tcg_comp_func_name pts_tcg_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_TCG_COMP_FUNC_NAME_H_ +#define PTS_TCG_COMP_FUNC_NAME_H_ + +typedef enum pts_tcg_qualifier_type_t pts_tcg_qualifier_type_t; +typedef enum pts_tcg_comp_func_name_t pts_tcp_comp_func_name_t; + +#include <library.h> + +/** + * PTS Component Functional Name Qualifier Flags for the TCG namespace + * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification + * + * 0 1 2 3 4 5 + * +-+-+-+-+-+-+ + * |K|S| Type | + * +-+-+-+-+-+-+ + */ +#define PTS_TCG_QUALIFIER_FLAG_KERNEL (1<<5) +#define PTS_TCG_QUALIFIER_FLAG_SUB (1<<4) + +extern char pts_tcg_qualifier_flag_names[]; + +/** + * Size of the PTS Component Functional Name Qualifier Type field + */ +#define PTS_TCG_QUALIFIER_TYPE_SIZE 4 + +/** + * PTS Component Functional Name Qualifier Types for the TCG namespace + * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_tcg_qualifier_type_t { + /** Unknown */ + PTS_TCG_QUALIFIER_TYPE_UNKNOWN = 0x0, + /** Trusted Platform */ + PTS_TCG_QUALIFIER_TYPE_TRUSTED = 0x1, + /** Operating System */ + PTS_TCG_QUALIFIER_TYPE_OS = 0x2, + /** Graphical User Interface */ + PTS_TCG_QUALIFIER_TYPE_GUI = 0x3, + /** Application */ + PTS_TCG_QUALIFIER_TYPE_APP = 0x4, + /** Networking */ + PTS_TCG_QUALIFIER_TYPE_NET = 0x5, + /** Library */ + PTS_TCG_QUALIFIER_TYPE_LIB = 0x6, + /** TNC Defined Component */ + PTS_TCG_QUALIFIER_TYPE_TNC = 0x7, + /** All matching Components */ + PTS_TCG_QUALIFIER_TYPE_ALL = 0xF, +}; + +extern enum_name_t *pts_tcg_qualifier_type_names; + +/** + * PTS Component Functional Name Binary Enumeration for the TCG namespace + * see section 5.3 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_tcg_comp_func_name_t { + /** Ignore */ + PTS_TCG_COMP_FUNC_NAME_IGNORE = 0x0000, + /** CRTM */ + PTS_TCG_COMP_FUNC_NAME_CRTM = 0x0001, + /** BIOS */ + PTS_TCG_COMP_FUNC_NAME_BIOS = 0x0002, + /** Platform Extensions */ + PTS_TCG_COMP_FUNC_NAME_PLATFORM_EXT = 0x0003, + /** Motherboard Firmware */ + PTS_TCG_COMP_FUNC_NAME_BOARD = 0x0004, + /** Initial Program Loader */ + PTS_TCG_COMP_FUNC_NAME_INIT_LOADER = 0x0005, + /** Option ROMs */ + PTS_TCG_COMP_FUNC_NAME_OPT_ROMS = 0x0006, +}; + +extern enum_name_t *pts_tcg_comp_func_names; + +#endif /** PTS_TCG_COMP_FUNC_NAME_H_ @}*/ diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c index f768b4679..65ae2b2d2 100644 --- a/src/libpts/pts/pts.c +++ b/src/libpts/pts/pts.c @@ -17,6 +17,8 @@ #include <debug.h> #include <crypto/hashers/hasher.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> #include <trousers/tss.h> #include <trousers/trousers.h> @@ -27,6 +29,16 @@ #define PTS_BUF_SIZE 4096 +/** + * Maximum number of PCR's of TPM, TPM Spec 1.2 + */ +#define PCR_MAX_NUM 24 + +/** + * Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2 + */ +#define PCR_LEN 20 + typedef struct private_pts_t private_pts_t; /** @@ -51,11 +63,41 @@ struct private_pts_t { pts_meas_algorithms_t algorithm; /** + * DH Hash Algorithm + */ + pts_meas_algorithms_t dh_hash_algorithm; + + /** + * PTS Diffie-Hellman Secret + */ + diffie_hellman_t *dh; + + /** + * PTS Diffie-Hellman Initiator Nonce + */ + chunk_t initiator_nonce; + + /** + * PTS Diffie-Hellman Responder Nonce + */ + chunk_t responder_nonce; + + /** + * Secret assessment value to be used for TPM Quote as an external data + */ + chunk_t secret; + + /** * Platform and OS Info */ char *platform_info; /** + * TRUE if IMC-PTS, FALSE if IMV-PTS + */ + bool is_imc; + + /** * Do we have an activated TPM */ bool has_tpm; @@ -66,10 +108,40 @@ struct private_pts_t { chunk_t tpm_version_info; /** + * Contains TSS Blob structure for AIK + */ + chunk_t aik_blob; + + /** * Contains a Attestation Identity Key or Certificate */ certificate_t *aik; + /** + * Table of extended PCRs with corresponding values + */ + u_char* pcrs[PCR_MAX_NUM]; + + /** + * Length of PCR registers + */ + size_t pcr_len; + + /** + * Number of extended PCR registers + */ + u_int32_t pcr_count; + + /** + * Highest extended PCR register + */ + u_int32_t pcr_max; + + /** + * Bitmap of extended PCR registers + */ + u_int8_t pcr_select[PCR_MAX_NUM / 8]; + }; METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t, @@ -79,7 +151,7 @@ METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t, } METHOD(pts_t, set_proto_caps, void, - private_pts_t *this, pts_proto_caps_flag_t flags) + private_pts_t *this, pts_proto_caps_flag_t flags) { this->proto_caps = flags; DBG2(DBG_PTS, "supported PTS protocol capabilities: %s%s%s%s%s", @@ -91,25 +163,143 @@ METHOD(pts_t, set_proto_caps, void, } METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t, - private_pts_t *this) + private_pts_t *this) { return this->algorithm; } METHOD(pts_t, set_meas_algorithm, void, - private_pts_t *this, pts_meas_algorithms_t algorithm) + private_pts_t *this, pts_meas_algorithms_t algorithm) { hash_algorithm_t hash_alg; - hash_alg = pts_meas_to_hash_algorithm(algorithm); + hash_alg = pts_meas_algo_to_hash(algorithm); DBG2(DBG_PTS, "selected PTS measurement algorithm is %N", - hash_algorithm_names, hash_alg); + hash_algorithm_names, hash_alg); if (hash_alg != HASH_UNKNOWN) { this->algorithm = algorithm; } } +METHOD(pts_t, get_dh_hash_algorithm, pts_meas_algorithms_t, + private_pts_t *this) +{ + return this->dh_hash_algorithm; +} + +METHOD(pts_t, set_dh_hash_algorithm, void, + private_pts_t *this, pts_meas_algorithms_t algorithm) +{ + hash_algorithm_t hash_alg; + + hash_alg = pts_meas_algo_to_hash(algorithm); + DBG2(DBG_PTS, "selected DH hash algorithm is %N", + hash_algorithm_names, hash_alg); + if (hash_alg != HASH_UNKNOWN) + { + this->dh_hash_algorithm = algorithm; + } +} + + +METHOD(pts_t, create_dh_nonce, bool, + private_pts_t *this, pts_dh_group_t group, int nonce_len) +{ + diffie_hellman_group_t dh_group; + chunk_t *nonce; + rng_t *rng; + + dh_group = pts_dh_group_to_ike(group); + DBG2(DBG_PTS, "selected PTS DH group is %N", + diffie_hellman_group_names, dh_group); + DESTROY_IF(this->dh); + this->dh = lib->crypto->create_dh(lib->crypto, dh_group); + + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + if (!rng) + { + DBG1(DBG_PTS, "no rng available"); + return FALSE; + } + DBG2(DBG_PTS, "nonce length is %d", nonce_len); + nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce; + chunk_free(nonce); + rng->allocate_bytes(rng, nonce_len, nonce); + rng->destroy(rng); + + return TRUE; +} + +METHOD(pts_t, get_my_public_value, void, + private_pts_t *this, chunk_t *value, chunk_t *nonce) +{ + this->dh->get_my_public_value(this->dh, value); + *nonce = this->is_imc ? this->responder_nonce : this->initiator_nonce; +} + +METHOD(pts_t, set_peer_public_value, void, + private_pts_t *this, chunk_t value, chunk_t nonce) +{ + this->dh->set_other_public_value(this->dh, value); + + nonce = chunk_clone(nonce); + if (this->is_imc) + { + this->initiator_nonce = nonce; + } + else + { + this->responder_nonce = nonce; + } +} + +METHOD(pts_t, calculate_secret, bool, + private_pts_t *this) +{ + hasher_t *hasher; + hash_algorithm_t hash_alg; + chunk_t shared_secret; + + /* Check presence of nonces */ + if (!this->initiator_nonce.len || !this->responder_nonce.len) + { + DBG1(DBG_PTS, "initiator and/or responder nonce is not available"); + return FALSE; + } + DBG3(DBG_PTS, "initiator nonce: %B", &this->initiator_nonce); + DBG3(DBG_PTS, "responder nonce: %B", &this->responder_nonce); + + /* Calculate the DH secret */ + if (this->dh->get_shared_secret(this->dh, &shared_secret) != SUCCESS) + { + DBG1(DBG_PTS, "shared DH secret computation failed"); + return FALSE; + } + DBG3(DBG_PTS, "shared DH secret: %B", &shared_secret); + + /* Calculate the secret assessment value */ + hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + + hasher->allocate_hash(hasher, chunk_from_chars('1'), NULL); + hasher->allocate_hash(hasher, this->initiator_nonce, NULL); + hasher->allocate_hash(hasher, this->responder_nonce, NULL); + hasher->allocate_hash(hasher, shared_secret, &this->secret); + hasher->destroy(hasher); + + /* The DH secret must be destroyed */ + chunk_clear(&shared_secret); + + /* + * Truncate the hash to 20 bytes to fit the ExternalData + * argument of the TPM Quote command + */ + this->secret.len = min(this->secret.len, 20); + DBG3(DBG_PTS, "secret assessment value: %B", &this->secret); + return TRUE; +} + /** * Print TPM 1.2 Version Info */ @@ -138,20 +328,20 @@ static void print_tpm_version_info(private_pts_t *this) } METHOD(pts_t, get_platform_info, char*, - private_pts_t *this) + private_pts_t *this) { return this->platform_info; } METHOD(pts_t, set_platform_info, void, - private_pts_t *this, char *info) + private_pts_t *this, char *info) { free(this->platform_info); this->platform_info = strdup(info); } METHOD(pts_t, get_tpm_version_info, bool, - private_pts_t *this, chunk_t *info) + private_pts_t *this, chunk_t *info) { if (!this->has_tpm) { @@ -163,14 +353,62 @@ METHOD(pts_t, get_tpm_version_info, bool, } METHOD(pts_t, set_tpm_version_info, void, - private_pts_t *this, chunk_t info) + private_pts_t *this, chunk_t info) { this->tpm_version_info = chunk_clone(info); print_tpm_version_info(this); } +METHOD(pts_t, get_pcr_len, size_t, + private_pts_t *this) +{ + return this->pcr_len; +} + +/** + * Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute) + */ +static void load_aik_blob(private_pts_t *this) +{ + char *blob_path; + FILE *fp; + u_int32_t aikBlobLen; + + blob_path = lib->settings->get_str(lib->settings, + "libimcv.plugins.imc-attestation.aik_blob", NULL); + + if (blob_path) + { + /* Read aik key blob from a file */ + if ((fp = fopen(blob_path, "r")) == NULL) + { + DBG1(DBG_PTS, "unable to open AIK Blob file: %s", blob_path); + return; + } + + fseek(fp, 0, SEEK_END); + aikBlobLen = ftell(fp); + fseek(fp, 0L, SEEK_SET); + + this->aik_blob = chunk_alloc(aikBlobLen); + if (fread(this->aik_blob.ptr, 1, aikBlobLen, fp)) + { + DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path); + DBG3(DBG_PTS, "AIK Blob: %B", &this->aik_blob); + } + else + { + DBG1(DBG_PTS, "unable to read AIK Blob file '%s'", blob_path); + } + fclose(fp); + return; + } + + DBG1(DBG_PTS, "AIK Blob is not available"); +} + /** - * Load an AIK certificate or public key, + * Load an AIK certificate or public key * the certificate having precedence over the public key if both are present */ static void load_aik(private_pts_t *this) @@ -204,26 +442,52 @@ static void load_aik(private_pts_t *this) return; } } + DBG1(DBG_PTS, "neither AIK certificate nor public key is available"); } METHOD(pts_t, get_aik, certificate_t*, - private_pts_t *this) + private_pts_t *this) { - return this->aik; + return this->aik; } METHOD(pts_t, set_aik, void, - private_pts_t *this, certificate_t *aik) + private_pts_t *this, certificate_t *aik) { DESTROY_IF(this->aik); this->aik = aik->get_ref(aik); } -/** - * Compute a hash over a file - */ -static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash) +METHOD(pts_t, get_aik_keyid, bool, + private_pts_t *this, chunk_t *keyid) +{ + public_key_t *public; + bool success; + + if (!this->aik) + { + DBG1(DBG_PTS, "no AIK certificate available"); + return FALSE; + } + public = this->aik->get_public_key(this->aik); + if (!public) + { + DBG1(DBG_PTS, "no AIK public key available"); + return FALSE; + } + success = public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, keyid); + if (!success) + { + DBG1(DBG_PTS, "no SHA-1 AIK public key info ID available"); + } + public->destroy(public); + + return success; +} + +METHOD(pts_t, hash_file, bool, + private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash) { u_char buffer[PTS_BUF_SIZE]; FILE *file; @@ -270,24 +534,23 @@ static char* get_filename(char *pathname) return filename; } -METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path, - pts_error_code_t *error_code) +METHOD(pts_t, is_path_valid, bool, + private_pts_t *this, char *path, pts_error_code_t *error_code) { - int error; - struct stat sb; - + struct stat st; + *error_code = 0; - error = stat(path, &sb); - if (error == 0) + + if (!stat(path, &st)) { return TRUE; } - else if (error == ENOENT || error == ENOTDIR) + else if (errno == ENOENT || errno == ENOTDIR) { DBG1(DBG_PTS, "file/directory does not exist %s", path); *error_code = TCG_PTS_FILE_NOT_FOUND; } - else if (error == EFAULT) + else if (errno == EFAULT) { DBG1(DBG_PTS, "bad address %s", path); *error_code = TCG_PTS_INVALID_PATH; @@ -295,7 +558,7 @@ METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path, else { DBG1(DBG_PTS, "error: %s occurred while validating path: %s", - strerror(error), path); + strerror(errno), path); return FALSE; } @@ -303,7 +566,7 @@ METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path, } METHOD(pts_t, do_measurements, pts_file_meas_t*, - private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory) + private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory) { hasher_t *hasher; hash_algorithm_t hash_alg; @@ -312,11 +575,11 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*, pts_file_meas_t *measurements; /* Create a hasher */ - hash_alg = pts_meas_to_hash_algorithm(this->algorithm); + hash_alg = pts_meas_algo_to_hash(this->algorithm); hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); if (!hasher) { - DBG1(DBG_PTS, " hasher %N not available", hash_algorithm_names, hash_alg); + DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg); return NULL; } @@ -346,7 +609,7 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*, /* measure regular files only */ if (S_ISREG(st.st_mode) && *rel_name != '.') { - if (!hash_file(hasher, abs_name, hash)) + if (!hash_file(this, hasher, abs_name, hash)) { enumerator->destroy(enumerator); hasher->destroy(hasher); @@ -363,7 +626,7 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*, { char *filename; - if (!hash_file(hasher, pathname, hash)) + if (!hash_file(this, hasher, pathname, hash)) { hasher->destroy(hasher); measurements->destroy(measurements); @@ -378,23 +641,683 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*, return measurements; } +/** + * Obtain statistical information describing a file + */ +static bool file_metadata(char *pathname, pts_file_metadata_t **entry) +{ + struct stat st; + pts_file_metadata_t *this; + + this = malloc_thing(pts_file_metadata_t); + + if (stat(pathname, &st)) + { + DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname); + return FALSE; + } + + if (S_ISREG(st.st_mode)) + { + this->type = PTS_FILE_REGULAR; + } + else if (S_ISDIR(st.st_mode)) + { + this->type = PTS_FILE_DIRECTORY; + } + else if (S_ISCHR(st.st_mode)) + { + this->type = PTS_FILE_CHAR_SPEC; + } + else if (S_ISBLK(st.st_mode)) + { + this->type = PTS_FILE_BLOCK_SPEC; + } + else if (S_ISFIFO(st.st_mode)) + { + this->type = PTS_FILE_FIFO; + } + else if (S_ISLNK(st.st_mode)) + { + this->type = PTS_FILE_SYM_LINK; + } + else if (S_ISSOCK(st.st_mode)) + { + this->type = PTS_FILE_SOCKET; + } + else + { + this->type = PTS_FILE_OTHER; + } + + this->filesize = st.st_size; + this->created = st.st_ctime; + this->modified = st.st_mtime; + this->accessed = st.st_atime; + this->owner = st.st_uid; + this->group = st.st_gid; + + *entry = this; + return TRUE; +} + +METHOD(pts_t, get_metadata, pts_file_meta_t*, + private_pts_t *this, char *pathname, bool is_directory) +{ + pts_file_meta_t *metadata; + pts_file_metadata_t *entry; + + /* Create a metadata object */ + metadata = pts_file_meta_create(); + + if (is_directory) + { + enumerator_t *enumerator; + char *rel_name, *abs_name; + struct stat st; + + enumerator = enumerator_create_directory(pathname); + if (!enumerator) + { + DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname, + strerror(errno)); + metadata->destroy(metadata); + return NULL; + } + while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st)) + { + /* measure regular files only */ + if (S_ISREG(st.st_mode) && *rel_name != '.') + { + if (!file_metadata(abs_name, &entry)) + { + enumerator->destroy(enumerator); + metadata->destroy(metadata); + return NULL; + } + entry->filename = strdup(rel_name); + metadata->add(metadata, entry); + } + } + enumerator->destroy(enumerator); + } + else + { + if (!file_metadata(pathname, &entry)) + { + metadata->destroy(metadata); + return NULL; + } + entry->filename = strdup(get_filename(pathname)); + metadata->add(metadata, entry); + } + + return metadata; +} + +METHOD(pts_t, read_pcr, bool, + private_pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value) +{ + TSS_HCONTEXT hContext; + TSS_HTPM hTPM; + TSS_RESULT result; + chunk_t rgbPcrValue; + + bool success = FALSE; + + result = Tspi_Context_Create(&hContext); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", result); + return FALSE; + } + + result = Tspi_Context_Connect(hContext, NULL); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_Context_GetTpmObject (hContext, &hTPM); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_TPM_PcrRead(hTPM, pcr_num, (UINT32*)&rgbPcrValue.len, &rgbPcrValue.ptr); + if (result != TSS_SUCCESS) + { + goto err; + } + *pcr_value = chunk_clone(rgbPcrValue); + DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, pcr_value); + success = TRUE; + +err: + if (!success) + { + DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + } + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + + return success; +} + +METHOD(pts_t, extend_pcr, bool, + private_pts_t *this, u_int32_t pcr_num, chunk_t input, chunk_t *output) +{ + TSS_HCONTEXT hContext; + TSS_HTPM hTPM; + TSS_RESULT result; + u_int32_t pcr_length; + chunk_t pcr_value; + + result = Tspi_Context_Create(&hContext); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", + result); + return FALSE; + } + result = Tspi_Context_Connect(hContext, NULL); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_Context_GetTpmObject (hContext, &hTPM); + if (result != TSS_SUCCESS) + { + goto err; + } + + pcr_value = chunk_alloc(PCR_LEN); + result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PCR_LEN, input.ptr, + NULL, &pcr_length, &pcr_value.ptr); + if (result != TSS_SUCCESS) + { + goto err; + } + + *output = pcr_value; + *output = chunk_clone(*output); + + DBG3(DBG_PTS, "PCR %d extended with: %B", pcr_num, &input); + DBG3(DBG_PTS, "PCR %d value after extend: %B", pcr_num, output); + + chunk_clear(&pcr_value); + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + + return TRUE; + +err: + DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + + chunk_clear(&pcr_value); + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + + return FALSE; +} + + +static void clear_pcrs(private_pts_t *this) +{ + int i; + + for (i = 0; i <= this->pcr_max; i++) + { + free(this->pcrs[i]); + this->pcrs[i] = NULL; + } + this->pcr_count = 0; + this->pcr_max = 0; + + memset(this->pcr_select, 0x00, sizeof(this->pcr_select)); +} + +METHOD(pts_t, quote_tpm, bool, + private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig) +{ + TSS_HCONTEXT hContext; + TSS_HTPM hTPM; + TSS_HKEY hAIK; + TSS_HKEY hSRK; + TSS_HPOLICY srkUsagePolicy; + TSS_UUID SRK_UUID = TSS_UUID_SRK; + BYTE secret[] = TSS_WELL_KNOWN_SECRET; + TSS_HPCRS hPcrComposite; + TSS_VALIDATION valData; + TSS_RESULT result; + chunk_t quote_info; + BYTE* versionInfo; + u_int32_t versionInfoSize, pcr, i = 0, f = 1; + bool success = FALSE; + + result = Tspi_Context_Create(&hContext); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", + result); + return FALSE; + } + result = Tspi_Context_Connect(hContext, NULL); + if (result != TSS_SUCCESS) + { + goto err1; + } + result = Tspi_Context_GetTpmObject (hContext, &hTPM); + if (result != TSS_SUCCESS) + { + goto err1; + } + + /* Retrieve SRK from TPM and set the authentication to well known secret*/ + result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, + SRK_UUID, &hSRK); + if (result != TSS_SUCCESS) + { + goto err1; + } + + result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy); + if (result != TSS_SUCCESS) + { + goto err1; + } + result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1, + 20, secret); + if (result != TSS_SUCCESS) + { + goto err1; + } + + result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, this->aik_blob.len, + this->aik_blob.ptr, &hAIK); + if (result != TSS_SUCCESS) + { + goto err1; + } + + /* Create PCR composite object */ + result = use_quote2 ? + Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, + TSS_PCRS_STRUCT_INFO_SHORT, &hPcrComposite) : + Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, + 0, &hPcrComposite); + if (result != TSS_SUCCESS) + { + goto err2; + } + + /* Select PCRs */ + for (pcr = 0; pcr <= this->pcr_max ; pcr++) + { + if (f == 256) + { + i++; + f = 1; + } + if (this->pcr_select[i] & f) + { + result = use_quote2 ? + Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr, + TSS_PCRS_DIRECTION_RELEASE) : + Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr); + if (result != TSS_SUCCESS) + { + goto err3; + } + } + f <<= 1; + } + + /* Set the Validation Data */ + valData.ulExternalDataLength = this->secret.len; + valData.rgbExternalData = (BYTE *)this->secret.ptr; + + + /* TPM Quote */ + result = use_quote2 ? + Tspi_TPM_Quote2(hTPM, hAIK, FALSE, hPcrComposite, &valData, + &versionInfoSize, &versionInfo): + Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData); + if (result != TSS_SUCCESS) + { + goto err4; + } + + /* Set output chunks */ + *pcr_comp = chunk_alloc(HASH_SIZE_SHA1); + + if (use_quote2) + { + /* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */ + memcpy(pcr_comp->ptr, valData.rgbData + valData.ulDataLength - HASH_SIZE_SHA1, + HASH_SIZE_SHA1); + } + else + { + /* TPM_Composite_Hash is 8-28th bytes of TPM_Quote_Info structure */ + memcpy(pcr_comp->ptr, valData.rgbData + 8, HASH_SIZE_SHA1); + } + DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp); + + quote_info = chunk_create(valData.rgbData, valData.ulDataLength); + DBG3(DBG_PTS, "TPM Quote Info: %B","e_info); + + *quote_sig = chunk_clone(chunk_create(valData.rgbValidationData, + valData.ulValidationDataLength)); + DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig); + + success = TRUE; + + /* Cleanup */ +err4: + Tspi_Context_FreeMemory(hContext, NULL); + +err3: + Tspi_Context_CloseObject(hContext, hPcrComposite); + +err2: + Tspi_Context_CloseObject(hContext, hAIK); + +err1: + Tspi_Context_Close(hContext); + + if (!success) + { + DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + } + clear_pcrs(this); + + return success; +} + +METHOD(pts_t, select_pcr, bool, + private_pts_t *this, u_int32_t pcr) +{ + u_int32_t i, f; + + if (pcr >= PCR_MAX_NUM) + { + DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u", + pcr, PCR_MAX_NUM-1); + return FALSE; + } + + /* Determine PCR selection flag */ + i = pcr / 8; + f = 1 << (pcr - 8*i); + + /* Has this PCR already been selected? */ + if (!(this->pcr_select[i] & f)) + { + this->pcr_select[i] |= f; + this->pcr_max = max(this->pcr_max, pcr); + this->pcr_count++; + } + + return TRUE; +} + +METHOD(pts_t, add_pcr, bool, + private_pts_t *this, u_int32_t pcr, chunk_t pcr_before, chunk_t pcr_after) +{ + if (pcr >= PCR_MAX_NUM) + { + DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u", + pcr, PCR_MAX_NUM-1); + return FALSE; + } + + /* Is the length of the PCR registers already set? */ + if (this->pcr_len) + { + if (pcr_after.len != this->pcr_len) + { + DBG1(DBG_PTS, "PCR %02u: length is %d bytes but should be %d bytes", + pcr_after.len, this->pcr_len); + return FALSE; + } + } + else + { + this->pcr_len = pcr_after.len; + } + + /* Has the value of the PCR register already been assigned? */ + if (this->pcrs[pcr]) + { + if (!memeq(this->pcrs[pcr], pcr_before.ptr, this->pcr_len)) + { + DBG1(DBG_PTS, "PCR %02u: new pcr_before value does not equal " + "old pcr_after value"); + } + /* remove the old PCR value */ + free(this->pcrs[pcr]); + } + else + { + /* add extended PCR Register */ + this->pcr_select[pcr / 8] |= 1 << (pcr % 8); + this->pcr_max = max(this->pcr_max, pcr); + this->pcr_count++; + } + + /* Duplicate and store current PCR value */ + pcr_after = chunk_clone(pcr_after); + this->pcrs[pcr] = pcr_after.ptr; + + return TRUE; +} + +/** + * TPM_QUOTE_INFO structure: + * 4 bytes of version + * 4 bytes 'Q' 'U' 'O' 'T' + * 20 byte SHA1 of TCPA_PCR_COMPOSITE + * 20 byte nonce + * + * TPM_QUOTE_INFO2 structure: + * 2 bytes Tag 0x0036 TPM_Tag_Quote_info2 + * 4 bytes 'Q' 'U' 'T' '2' + * 20 bytes nonce + * 26 bytes PCR_INFO_SHORT + */ + +METHOD(pts_t, get_quote_info, bool, + private_pts_t *this, bool use_quote2, bool use_ver_info, + pts_meas_algorithms_t comp_hash_algo, + chunk_t *out_pcr_comp, chunk_t *out_quote_info) +{ + u_int8_t size_of_select; + int pcr_comp_len, i; + chunk_t pcr_comp, hash_pcr_comp; + bio_writer_t *writer; + hasher_t *hasher; + + if (this->pcr_count == 0) + { + DBG1(DBG_PTS, "No extended PCR entries available, " + "unable to construct TPM Quote Info"); + return FALSE; + } + if (!this->secret.ptr) + { + DBG1(DBG_PTS, "Secret assessment value unavailable, ", + "unable to construct TPM Quote Info"); + return FALSE; + } + if (use_quote2 && use_ver_info && !this->tpm_version_info.ptr) + { + DBG1(DBG_PTS, "TPM Version Information unavailable, ", + "unable to construct TPM Quote Info2"); + return FALSE; + } + + /** + * A TPM v1.2 has 24 PCR Registers + * so the bitmask field length used by TrouSerS is at least 3 bytes + */ + size_of_select = max(PCR_MAX_NUM / 8, 1 + this->pcr_max / 8); + pcr_comp_len = 2 + size_of_select + 4 + this->pcr_count * this->pcr_len; + + writer = bio_writer_create(pcr_comp_len); + + writer->write_uint16(writer, size_of_select); + for (i = 0; i < size_of_select; i++) + { + writer->write_uint8(writer, this->pcr_select[i]); + } + + writer->write_uint32(writer, this->pcr_count * this->pcr_len); + for (i = 0; i < 8 * size_of_select; i++) + { + if (this->pcrs[i]) + { + writer->write_data(writer, chunk_create(this->pcrs[i], this->pcr_len)); + } + } + pcr_comp = chunk_clone(writer->get_buf(writer)); + DBG3(DBG_PTS, "constructed PCR Composite: %B", &pcr_comp); + + writer->destroy(writer); + + /* Output the TPM_PCR_COMPOSITE expected from IMC */ + if (comp_hash_algo) + { + hash_algorithm_t algo; + + algo = pts_meas_algo_to_hash(comp_hash_algo); + hasher = lib->crypto->create_hasher(lib->crypto, algo); + + /* Hash the PCR Composite Structure */ + hasher->allocate_hash(hasher, pcr_comp, out_pcr_comp); + DBG3(DBG_PTS, "constructed PCR Composite hash: %#B", out_pcr_comp); + hasher->destroy(hasher); + } + else + { + *out_pcr_comp = chunk_clone(pcr_comp); + } + + /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */ + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + hasher->allocate_hash(hasher, pcr_comp, &hash_pcr_comp); + hasher->destroy(hasher); + + /* Construct TPM_QUOTE_INFO/TPM_QUOTE_INFO2 structure */ + writer = bio_writer_create(TPM_QUOTE_INFO_LEN); + + if (use_quote2) + { + /* TPM Structure Tag */ + writer->write_uint16(writer, TPM_TAG_QUOTE_INFO2); + + /* Magic QUT2 value */ + writer->write_data(writer, chunk_create("QUT2", 4)); + + /* Secret assessment value 20 bytes (nonce) */ + writer->write_data(writer, this->secret); + + /* Length of the PCR selection field */ + writer->write_uint16(writer, size_of_select); + + /* PCR selection */ + for (i = 0; i < size_of_select ; i++) + { + writer->write_uint8(writer, this->pcr_select[i]); + } + + /* TPM Locality Selection */ + writer->write_uint8(writer, TPM_LOC_ZERO); + + /* PCR Composite Hash */ + writer->write_data(writer, hash_pcr_comp); + + if (use_ver_info) + { + /* TPM version Info */ + writer->write_data(writer, this->tpm_version_info); + } + } + else + { + /* Version number */ + writer->write_data(writer, chunk_from_chars(1, 1, 0, 0)); + + /* Magic QUOT value */ + writer->write_data(writer, chunk_create("QUOT", 4)); + + /* PCR Composite Hash */ + writer->write_data(writer, hash_pcr_comp); + + /* Secret assessment value 20 bytes (nonce) */ + writer->write_data(writer, this->secret); + } + + /* TPM Quote Info */ + *out_quote_info = chunk_clone(writer->get_buf(writer)); + DBG3(DBG_PTS, "constructed TPM Quote Info: %B", out_quote_info); + + writer->destroy(writer); + free(pcr_comp.ptr); + free(hash_pcr_comp.ptr); + clear_pcrs(this); + + return TRUE; +} + +METHOD(pts_t, verify_quote_signature, bool, + private_pts_t *this, chunk_t data, chunk_t signature) +{ + public_key_t *aik_pub_key; + + aik_pub_key = this->aik->get_public_key(this->aik); + if (!aik_pub_key) + { + DBG1(DBG_PTS, "failed to get public key from AIK certificate"); + return FALSE; + } + + if (!aik_pub_key->verify(aik_pub_key, SIGN_RSA_EMSA_PKCS1_SHA1, + data, signature)) + { + DBG1(DBG_PTS, "signature verification failed for TPM Quote Info"); + DESTROY_IF(aik_pub_key); + return FALSE; + } + + aik_pub_key->destroy(aik_pub_key); + return TRUE; +} + METHOD(pts_t, destroy, void, - private_pts_t *this) + private_pts_t *this) { + clear_pcrs(this); DESTROY_IF(this->aik); + DESTROY_IF(this->dh); + free(this->initiator_nonce.ptr); + free(this->responder_nonce.ptr); + free(this->secret.ptr); free(this->platform_info); + free(this->aik_blob.ptr); free(this->tpm_version_info.ptr); free(this); } +#define RELEASE_LSB 0 +#define RELEASE_DEBIAN 1 + /** * Determine Linux distribution and hardware platform */ static char* extract_platform_info(void) { FILE *file; - char buf[BUF_LEN], *pos, *value = NULL; - int i, len; + char buf[BUF_LEN], *pos = buf, *value = NULL; + int i, len = BUF_LEN - 1; struct utsname uninfo; /* Linux/Unix distribution release info (from http://linuxmafia.com) */ @@ -420,6 +1343,7 @@ static char* extract_platform_info(void) }; const char description[] = "DISTRIB_DESCRIPTION=\""; + const char str_debian[] = "Debian "; for (i = 0; i < countof(releases); i++) { @@ -428,11 +1352,19 @@ static char* extract_platform_info(void) { continue; } + + if (i == RELEASE_DEBIAN) + { + strcpy(buf, str_debian); + pos += strlen(str_debian); + len -= strlen(str_debian); + } + fseek(file, 0, SEEK_END); - len = min(ftell(file), sizeof(buf)-1); + len = min(ftell(file), len); rewind(file); - buf[len] = '\0'; - if (fread(buf, 1, len, file) != len) + pos[len] = '\0'; + if (fread(pos, 1, len, file) != len) { DBG1(DBG_PTS, "failed to read file '%s'", releases[i]); fclose(file); @@ -440,7 +1372,7 @@ static char* extract_platform_info(void) } fclose(file); - if (i == 0) /* LSB release */ + if (i == RELEASE_LSB) { pos = strstr(buf, description); if (!pos) @@ -461,7 +1393,7 @@ static char* extract_platform_info(void) else { value = buf; - pos = strchr(value, '\n'); + pos = strchr(pos, '\n'); if (!pos) { DBG1(DBG_PTS, "failed to find end of release string"); @@ -504,7 +1436,8 @@ static bool has_tpm(private_pts_t *this) result = Tspi_Context_Create(&hContext); if (result != TSS_SUCCESS) { - DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", result); + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", + result); return FALSE; } result = Tspi_Context_Connect(hContext, NULL); @@ -526,10 +1459,14 @@ static bool has_tpm(private_pts_t *this) goto err; } this->tpm_version_info = chunk_clone(this->tpm_version_info); + + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); return TRUE; err: DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + Tspi_Context_FreeMemory(hContext, NULL); Tspi_Context_Close(hContext); return FALSE; } @@ -542,23 +1479,42 @@ pts_t *pts_create(bool is_imc) private_pts_t *this; INIT(this, - .public = { - .get_proto_caps = _get_proto_caps, - .set_proto_caps = _set_proto_caps, - .get_meas_algorithm = _get_meas_algorithm, - .set_meas_algorithm = _set_meas_algorithm, - .get_platform_info = _get_platform_info, - .set_platform_info = _set_platform_info, - .get_tpm_version_info = _get_tpm_version_info, - .set_tpm_version_info = _set_tpm_version_info, - .get_aik = _get_aik, - .set_aik = _set_aik, - .is_path_valid = _is_path_valid, - .do_measurements = _do_measurements, - .destroy = _destroy, - }, - .proto_caps = PTS_PROTO_CAPS_V, - .algorithm = PTS_MEAS_ALGO_SHA256, + .public = { + .get_proto_caps = _get_proto_caps, + .set_proto_caps = _set_proto_caps, + .get_meas_algorithm = _get_meas_algorithm, + .set_meas_algorithm = _set_meas_algorithm, + .get_dh_hash_algorithm = _get_dh_hash_algorithm, + .set_dh_hash_algorithm = _set_dh_hash_algorithm, + .create_dh_nonce = _create_dh_nonce, + .get_my_public_value = _get_my_public_value, + .set_peer_public_value = _set_peer_public_value, + .calculate_secret = _calculate_secret, + .get_platform_info = _get_platform_info, + .set_platform_info = _set_platform_info, + .get_tpm_version_info = _get_tpm_version_info, + .set_tpm_version_info = _set_tpm_version_info, + .get_pcr_len = _get_pcr_len, + .get_aik = _get_aik, + .set_aik = _set_aik, + .get_aik_keyid = _get_aik_keyid, + .is_path_valid = _is_path_valid, + .hash_file = _hash_file, + .do_measurements = _do_measurements, + .get_metadata = _get_metadata, + .read_pcr = _read_pcr, + .extend_pcr = _extend_pcr, + .quote_tpm = _quote_tpm, + .select_pcr = _select_pcr, + .add_pcr = _add_pcr, + .get_quote_info = _get_quote_info, + .verify_quote_signature = _verify_quote_signature, + .destroy = _destroy, + }, + .is_imc = is_imc, + .proto_caps = PTS_PROTO_CAPS_V, + .algorithm = PTS_MEAS_ALGO_SHA256, + .dh_hash_algorithm = PTS_MEAS_ALGO_SHA256, ); if (is_imc) @@ -568,15 +1524,16 @@ pts_t *pts_create(bool is_imc) if (has_tpm(this)) { this->has_tpm = TRUE; - this->proto_caps |= PTS_PROTO_CAPS_T; + this->pcr_len = PCR_LEN; + this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D; load_aik(this); + load_aik_blob(this); } } else { - this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_C; + this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D; } return &this->public; } - diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h index ef408c43f..212acb02a 100644 --- a/src/libpts/pts/pts.h +++ b/src/libpts/pts/pts.h @@ -27,17 +27,59 @@ typedef struct pts_t pts_t; #include "pts_proto_caps.h" #include "pts_meas_algo.h" #include "pts_file_meas.h" +#include "pts_file_meta.h" +#include "pts_dh_group.h" +#include "pts_req_func_comp_evid.h" +#include "pts_simple_evid_final.h" +#include "components/pts_comp_func_name.h" #include <library.h> +#include <utils/linked_list.h> /** * UTF-8 encoding of the character used to delimiter the filename */ -#define SOLIDUS_UTF 0x002F -#define REVERSE_SOLIDUS_UTF 0x005C +#define SOLIDUS_UTF 0x2F +#define REVERSE_SOLIDUS_UTF 0x5C /** - * Class implementing the TCG Platform Trust System (PTS) + * PCR indices used for measurements of various functional components + */ +#define PCR_BIOS 0 +#define PCR_PLATFORM_EXT 1 +#define PCR_MOTHERBOARD 1 +#define PCR_OPTION_ROMS 2 +#define PCR_IPL 4 + +#define PCR_TBOOT_POLICY 17 +#define PCR_TBOOT_MLE 18 + +#define PCR_TGRUB_MBR_STAGE1 4 +#define PCR_TGRUB_STAGE2_PART1 8 +#define PCR_TGRUB_STAGE2_PART2 9 +#define PCR_TGRUB_CMD_LINE_ARGS 12 +#define PCR_TGRUB_CHECKFILE 13 +#define PCR_TGRUB_LOADED_FILES 14 + +#define PCR_DEBUG 16 + +/** + * Length of the generated nonce used for calculation of shared secret + */ +#define ASSESSMENT_SECRET_LEN 20 + +/** + * Length of the TPM_QUOTE_INFO structure, TPM Spec 1.2 + */ +#define TPM_QUOTE_INFO_LEN 48 + +/** + * Hashing algorithm used by tboot and trustedGRUB + */ +#define TRUSTED_HASH_ALGO PTS_MEAS_ALGO_SHA1 + +/** + * Class implementing the TCG Platform Trust Service (PTS) * */ struct pts_t { @@ -45,96 +87,255 @@ struct pts_t { /** * Get PTS Protocol Capabilities * - * @return protocol capabilities flags + * @return Protocol capabilities flags */ pts_proto_caps_flag_t (*get_proto_caps)(pts_t *this); /** * Set PTS Protocol Capabilities * - * @param flags protocol capabilities flags + * @param flags Protocol capabilities flags */ void (*set_proto_caps)(pts_t *this, pts_proto_caps_flag_t flags); /** * Get PTS Measurement Algorithm * - * @return measurement algorithm + * @return PTS measurement algorithm */ pts_meas_algorithms_t (*get_meas_algorithm)(pts_t *this); /** * Set PTS Measurement Algorithm * - * @param algorithm measurement algorithm + * @param algorithm PTS measurement algorithm */ void (*set_meas_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm); /** + * Get DH Hash Algorithm + * + * @return DH hash algorithm + */ + pts_meas_algorithms_t (*get_dh_hash_algorithm)(pts_t *this); + + /** + * Set DH Hash Algorithm + * + * @param algorithm DH hash algorithm + */ + void (*set_dh_hash_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm); + + /** + * Create PTS Diffie-Hellman object and nonce + * + * @param group PTS DH group + * @param nonce_len Nonce length + * @return TRUE if creation was successful + * + */ + bool (*create_dh_nonce)(pts_t *this, pts_dh_group_t group, int nonce_len); + + /** + * Get my Diffie-Hellman public value + * + * @param value My public DH value + * @param nonce My DH nonce + */ + void (*get_my_public_value)(pts_t *this, chunk_t *value, chunk_t *nonce); + + /** + * Set peer Diffie.Hellman public value + * + * @param value Peer public DH value + * @param nonce Peer DH nonce + */ + void (*set_peer_public_value) (pts_t *this, chunk_t value, chunk_t nonce); + + /** + * Calculates assessment secret to be used for TPM Quote as ExternalData + * + * @return TRUE unless both DH public values + * and nonces are set + */ + bool (*calculate_secret) (pts_t *this); + + /** * Get Platform and OS Info * - * @return platform and OS info + * @return Platform and OS info */ char* (*get_platform_info)(pts_t *this); /** * Set Platform and OS Info * - * @param info platform and OS info + * @param info Platform and OS info */ void (*set_platform_info)(pts_t *this, char *info); /** * Get TPM 1.2 Version Info * - * @param info chunk containing a TPM_CAP_VERSION_INFO struct - * @return TRUE if TPM Version Info available + * @param info chunk containing a TPM_CAP_VERSION_INFO struct + * @return TRUE if TPM Version Info available */ bool (*get_tpm_version_info)(pts_t *this, chunk_t *info); /** * Set TPM 1.2 Version Info * - * @param info chunk containing a TPM_CAP_VERSION_INFO struct + * @param info chunk containing a TPM_CAP_VERSION_INFO struct */ void (*set_tpm_version_info)(pts_t *this, chunk_t info); - + + /** + * Get the length of the TPM PCR registers + * + * @return Length of PCR registers in bytes, 0 if undefined + */ + size_t (*get_pcr_len)(pts_t *this); + /** * Get Attestation Identity Certificate or Public Key * - * @return AIK Certificate or Public Key + * @return AIK Certificate or Public Key */ certificate_t* (*get_aik)(pts_t *this); - + /** * Set Attestation Identity Certificate or Public Key * - * @param aik AIK Certificate or Public Key + * @param aik AIK Certificate or Public Key */ void (*set_aik)(pts_t *this, certificate_t *aik); /** + * Get SHA-1 Attestation Identity Public Key Info ID + * + * @param keyid AIK ID + * @return TRUE if AIK ID exists + */ + bool (*get_aik_keyid)(pts_t *this, chunk_t *keyid); + + /** * Check whether path is valid file/directory on filesystem * - * @param path Absolute path - * @param error_code Output variable for PTS error code - * @return TRUE if path is valid or file/directory doesn't exist - * or path is invalid + * @param path Absolute path + * @param error_code Output variable for PTS error code + * @return TRUE if path is valid or file/directory + * doesn't exist or path is invalid * FALSE if local error occurred within stat function */ bool (*is_path_valid)(pts_t *this, char *path, pts_error_code_t *error_code); /** + * Compute a hash over a file + * @param hasher Hasher to be used + * @param pathname Absolute path of a file + * @param hash Buffer to keep hash output + * @return TRUE if path is valid and hashing succeeded + */ + bool (*hash_file)(pts_t *this, hasher_t *hasher, char *pathname, u_char *hash); + + /** * Do PTS File Measurements * - * @param request_id ID of PTS File Measurement Request - * @param pathname Absolute pathname of file to be measured - * @param is_directory if TRUE directory contents are measured - * @return PTS File Measurements of NULL if FAILED + * @param request_id ID of PTS File Measurement Request + * @param pathname Absolute pathname of file to be measured + * @param is_directory TRUE if directory contents are measured + * @return PTS File Measurements of NULL if FAILED */ pts_file_meas_t* (*do_measurements)(pts_t *this, u_int16_t request_id, char *pathname, bool is_directory); - + + /** + * Obtain file metadata + * + * @param pathname Absolute pathname of file/directory + * @param is_directory TRUE if directory contents are requested + * @return PTS File Metadata or NULL if FAILED + */ + pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, + bool is_directory); + + /** + * Reads given PCR value and returns it + * Expects owner secret to be WELL_KNOWN_SECRET + * + * @param pcr_num Number of PCR to read + * @param pcr_value Chunk to save pcr read output + * @return NULL in case of TSS error, PCR value otherwise + */ + bool (*read_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value); + + /** + * Extends given PCR with given value + * Expects owner secret to be WELL_KNOWN_SECRET + * + * @param pcr_num Number of PCR to extend + * @param input Value to extend + * @param output Chunk to save PCR value after extension + * @return FALSE in case of TSS error, TRUE otherwise + */ + bool (*extend_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t input, + chunk_t *output); + + /** + * Quote over PCR's + * Expects owner and SRK secret to be WELL_KNOWN_SECRET and no password set for AIK + * + * @param use_quote2 Version of the Quote function to be used + * @param pcr_comp Chunk to save PCR composite structure + * @param quote_sig Chunk to save quote operation output + * without external data (anti-replay protection) + * @return FALSE in case of TSS error, TRUE otherwise + */ + bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp, + chunk_t *quote_sig); + + /** + * Mark an extended PCR as selected + * + * @param pcr Number of the extended PCR + * @return TRUE if PCR number is valid + */ + bool (*select_pcr)(pts_t *this, u_int32_t pcr); + + /** + * Add an extended PCR with its corresponding value + * + * @param pcr Number of the extended PCR + * @param pcr_before PCR value before extension + * @param pcr_after PCR value after extension + * @return TRUE if PCR number and register length is valid + */ + bool (*add_pcr)(pts_t *this, u_int32_t pcr, chunk_t pcr_before, + chunk_t pcr_after); + + /** + * Constructs and returns TPM Quote Info structure expected from IMC + * + * @param use_quote2 Version of the TPM_QUOTE_INFO to be constructed + * @param use_ver_info Version info is concatenated to TPM_QUOTE_INFO2 + * @param comp_hash_algo Composite Hash Algorithm + * @param pcr_comp Output variable to store PCR Composite + * @param quote_info Output variable to store TPM Quote Info + * @return FALSE in case of any error, TRUE otherwise + */ + bool (*get_quote_info)(pts_t *this, bool use_quote2, bool ver_info_included, + pts_meas_algorithms_t comp_hash_algo, + chunk_t *pcr_comp, chunk_t *quote_info); + + /** + * Constructs and returns PCR Quote Digest structure expected from IMC + * + * @param data Calculated TPM Quote Digest + * @param signature TPM Quote Signature received from IMC + * @return FALSE if signature is not verified + */ + bool (*verify_quote_signature)(pts_t *this, chunk_t data, chunk_t signature); + /** * Destroys a pts_t object. */ diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c index 2706173ab..282755c0a 100644 --- a/src/libpts/pts/pts_database.c +++ b/src/libpts/pts/pts_database.c @@ -39,7 +39,7 @@ struct private_pts_database_t { }; -METHOD(pts_database_t, create_file_enumerator, enumerator_t*, +METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*, private_pts_database_t *this, char *product) { enumerator_t *e; @@ -49,12 +49,27 @@ METHOD(pts_database_t, create_file_enumerator, enumerator_t*, "SELECT f.id, f.type, f.path FROM files AS f " "JOIN product_file AS pf ON f.id = pf.file " "JOIN products AS p ON p.id = pf.product " - "WHERE p.name = ?", + "WHERE p.name = ? AND pf.measurement = 1", DB_TEXT, product, DB_INT, DB_INT, DB_TEXT); return e; } -METHOD(pts_database_t, create_hash_enumerator, enumerator_t*, +METHOD(pts_database_t, create_file_meta_enumerator, enumerator_t*, + private_pts_database_t *this, char *product) +{ + enumerator_t *e; + + /* look for all entries belonging to a product in the files table */ + e = this->db->query(this->db, + "SELECT f.type, f.path FROM files AS f " + "JOIN product_file AS pf ON f.id = pf.file " + "JOIN products AS p ON p.id = pf.product " + "WHERE p.name = ? AND pf.metadata = 1", + DB_TEXT, product, DB_INT, DB_TEXT); + return e; +} + +METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, int id, bool is_dir) { @@ -82,6 +97,178 @@ METHOD(pts_database_t, create_hash_enumerator, enumerator_t*, return e; } +METHOD(pts_database_t, check_aik_keyid, status_t, + private_pts_database_t *this, chunk_t keyid, int *kid) +{ + enumerator_t *e; + + /* If the AIK is registered get the primary key */ + e = this->db->query(this->db, + "SELECT id FROM keys WHERE keyid = ?", DB_BLOB, keyid, DB_INT); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FAILED; + } + if (!e->enumerate(e, kid)) + { + DBG1(DBG_PTS, "AIK %#B is not registered in database", &keyid); + e->destroy(e); + return FAILED; + } + e->destroy(e); + + return SUCCESS; +} + +METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*, + private_pts_database_t *this, int kid) +{ + enumerator_t *e; + + /* look for all entries belonging to an AIK in the components table */ + e = this->db->query(this->db, + "SELECT c.vendor_id, c.name, c.qualifier, kc.depth " + "FROM components AS c " + "JOIN key_component AS kc ON c.id = kc.component " + "WHERE kc.key = ? ORDER BY kc.seq_no", + DB_INT, kid, DB_INT, DB_INT, DB_INT, DB_INT); + return e; +} + +METHOD(pts_database_t, check_comp_measurement, status_t, + private_pts_database_t *this, chunk_t measurement, int cid, int kid, + int seq_no, int pcr, pts_meas_algorithms_t algo) +{ + enumerator_t *e; + chunk_t hash; + status_t status = NOT_FOUND; + + e = this->db->query(this->db, + "SELECT hash FROM component_hashes " + "WHERE component = ? AND key = ? " + "AND seq_no = ? AND pcr = ? AND algo = ? ", + DB_INT, cid, DB_INT, kid, DB_INT, seq_no, + DB_INT, pcr, DB_INT, algo, DB_BLOB); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FAILED; + } + + while (e->enumerate(e, &hash)) + { + if (chunk_equals(hash, measurement)) + { + status = SUCCESS; + break; + } + else + { + DBG1(DBG_PTS, "PCR %2d no matching component measurement #%d " + "found in database", pcr, seq_no); + DBG1(DBG_PTS, " expected: %#B", &hash); + DBG1(DBG_PTS, " received: %#B", &measurement); + status = FAILED; + break; + } + } + e->destroy(e); + + if (status == NOT_FOUND) + { + DBG1(DBG_PTS, "PCR %2d no measurement #%d " + "found in database", pcr, seq_no); + } + + return status; +} + +METHOD(pts_database_t, insert_comp_measurement, status_t, + private_pts_database_t *this, chunk_t measurement, int cid, int kid, + int seq_no, int pcr, pts_meas_algorithms_t algo) +{ + int id; + + if (this->db->execute(this->db, &id, + "INSERT INTO component_hashes " + "(component, key, seq_no, pcr, algo, hash) " + "VALUES (?, ?, ?, ?, ?, ?)", + DB_INT, cid, DB_INT, kid, DB_INT, seq_no, DB_INT, pcr, + DB_INT, algo, DB_BLOB, measurement) == 1) + { + return SUCCESS; + } + + DBG1(DBG_PTS, "could not insert component measurement into database"); + return FAILED; +} + +METHOD(pts_database_t, delete_comp_measurements, int, + private_pts_database_t *this, int cid, int kid) +{ + return this->db->execute(this->db, NULL, + "DELETE FROM component_hashes " + "WHERE component = ? AND key = ?", + DB_INT, cid, DB_INT, kid); +} + +METHOD(pts_database_t, get_comp_measurement_count, status_t, + private_pts_database_t *this, pts_comp_func_name_t *comp_name, + chunk_t keyid, pts_meas_algorithms_t algo, int *cid, int *kid, int *count) +{ + enumerator_t *e; + status_t status = SUCCESS; + + /* Initialize count */ + *count = 0; + + if (_check_aik_keyid(this, keyid, kid) != SUCCESS) + { + return FAILED; + } + + /* Get the primary key of the Component Functional Name */ + e = this->db->query(this->db, + "SELECT id FROM components " + " WHERE vendor_id = ? AND name = ? AND qualifier = ?", + DB_INT, comp_name->get_vendor_id(comp_name), + DB_INT, comp_name->get_name(comp_name), + DB_INT, comp_name->get_qualifier(comp_name), + DB_INT); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FAILED; + } + if (!e->enumerate(e, cid)) + { + DBG1(DBG_PTS, "component functional name not found in database"); + e->destroy(e); + return FAILED; + } + e->destroy(e); + + /* Get the number of stored measurements for a given AIK and component */ + e = this->db->query(this->db, + "SELECT COUNT(*) FROM component_hashes AS ch " + "WHERE component = ? AND key = ? AND algo = ?", + DB_INT, *cid, DB_INT, *kid, DB_INT, algo, DB_INT); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FAILED; + } + if (!e->enumerate(e, count)) + { + DBG1(DBG_PTS, "no component measurement count returned from database"); + status = FAILED; + } + e->destroy(e); + + return status; +} + METHOD(pts_database_t, destroy, void, private_pts_database_t *this) { @@ -98,8 +285,15 @@ pts_database_t *pts_database_create(char *uri) INIT(this, .public = { - .create_file_enumerator = _create_file_enumerator, - .create_hash_enumerator = _create_hash_enumerator, + .create_file_meas_enumerator = _create_file_meas_enumerator, + .create_file_meta_enumerator = _create_file_meta_enumerator, + .create_comp_evid_enumerator = _create_comp_evid_enumerator, + .create_file_hash_enumerator = _create_file_hash_enumerator, + .check_aik_keyid = _check_aik_keyid, + .check_comp_measurement = _check_comp_measurement, + .insert_comp_measurement = _insert_comp_measurement, + .delete_comp_measurements = _delete_comp_measurements, + .get_comp_measurement_count = _get_comp_measurement_count, .destroy = _destroy, }, .db = lib->db->create(lib->db, uri), @@ -107,8 +301,8 @@ pts_database_t *pts_database_create(char *uri) if (!this->db) { - DBG1(DBG_PTS, "failed to connect to PTS file measurement database '%s'", - uri); + DBG1(DBG_PTS, + "failed to connect to PTS file measurement database '%s'", uri); free(this); return NULL; } diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h index f2a6854a5..a9a68ac76 100644 --- a/src/libpts/pts/pts_database.h +++ b/src/libpts/pts/pts_database.h @@ -24,6 +24,7 @@ typedef struct pts_database_t pts_database_t; #include "pts_meas_algo.h" +#include "components/pts_comp_func_name.h" #include <library.h> /** @@ -33,25 +34,107 @@ typedef struct pts_database_t pts_database_t; struct pts_database_t { /** - * Get files to be measured by PTS + * Get files/directories to be measured by PTS * - * @param product software product (os, vpn client, etc.) - * @return enumerator over all matching files + * @param product Software product (os, vpn client, etc.) + * @return Enumerator over all matching files/directories */ - enumerator_t* (*create_file_enumerator)(pts_database_t *this, char *product); + enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this, + char *product); + + /** + * Get files/directories to request metadata of + * + * @param product Software product (os, vpn client, etc.) + * @return Enumerator over all matching files/directories + */ + enumerator_t* (*create_file_meta_enumerator)(pts_database_t *this, + char *product); /** * Get stored measurement hash for single file or directory entries * - * @param product software product (os, vpn client, etc.) - * @param algo hash algorithm used for measurement - * @param id primary key of measured file/directory + * @param product Software product (os, vpn client, etc.) + * @param algo Hash algorithm used for measurement + * @param id Primary key of measured file/directory * @param is_dir TRUE if directory was measured - * @return enumerator over all matching measurement hashes + * @return Enumerator over all matching measurement hashes + */ + enumerator_t* (*create_file_hash_enumerator)(pts_database_t *this, + char *product, pts_meas_algorithms_t algo, + int id, bool is_dir); + + /** + * Check if an AIK given by its keyid is registered in the database + * + * @param keyid AIK keyid (SHA-1 hash of the AIK public key info) + * @param kid Primary key of AIK entry in keys table + * @return SUCCESS if AIK is present, FAILED otherwise + */ + status_t (*check_aik_keyid)(pts_database_t *this, chunk_t keyid, int *kid); + + /** + * Get functional components to request evidence of + * + * @param kid Primary key of AIK entry in keys table + * @return Enumerator over all matching components + */ + enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, int kid); + + /** + * Check a functional component measurement against value stored in database + * + * @param measurement measurement hash + * @param cid Primary key of Component Functional Name entry + * @param kid Primary key of AIK entry in keys table + * @param seq_no Measurement sequence number + * @param prc Number of the PCR the measurement was extended into + * @param algo Hash algorithm used for measurement + * @return SUCCESS if check was successful + */ + status_t (*check_comp_measurement)(pts_database_t *this, chunk_t measurement, + int cid, int kid, int seq_no, int pcr, + pts_meas_algorithms_t algo); + + /** + * Insert a functional component measurement into the database + * + * @param measurement Measurement hash + * @param cid Primary key of Component Functional Name entry + * @param kid Primary key of AIK entry in keys table + * @param seq_no Measurement sequence number + * @param prc Number of the PCR the measurement was extended into + * @param algo Hash algorithm used for measurement + * @return SUCCESS if INSERT was successful + */ + status_t (*insert_comp_measurement)(pts_database_t *this, chunk_t measurement, + int cid, int kid, int seq_no, int pcr, + pts_meas_algorithms_t algo); + + /** + * Delete functional component measurements from the database + * + * @param cid Primary key of Component Functional Name entry + * @param kid Primary key of AIK entry in keys table + * @return number of deleted measurement entries + */ + int (*delete_comp_measurements)(pts_database_t *this, int cid, int kid); + + /** + * Get the number of measurements for a functional component and AIK + * + * @param comp_name Component Functional Name + * @param keyid SHA-1 hash of AIK public key info + * @param algo Hash algorithm used for measurement + * @param cid Primary key of Component Functional Name entry + * @param kid Primary key of AIK entry in keys table + * @param count measurement count + * @return SUCCESS if COUNT was successful */ - enumerator_t* (*create_hash_enumerator)(pts_database_t *this, char *product, - pts_meas_algorithms_t algo, - int id, bool is_dir); + status_t (*get_comp_measurement_count)(pts_database_t *this, + pts_comp_func_name_t *comp_name, chunk_t keyid, + pts_meas_algorithms_t algo, int *cid, int *kid, + int *count); /** * Destroys a pts_database_t object. diff --git a/src/libpts/pts/pts_dh_group.c b/src/libpts/pts/pts_dh_group.c new file mode 100644 index 000000000..fb141327f --- /dev/null +++ b/src/libpts/pts/pts_dh_group.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "pts_dh_group.h" + +#include <debug.h> + +/** + * Described in header. + */ +bool pts_dh_group_probe(pts_dh_group_t *dh_groups) +{ + enumerator_t *enumerator; + diffie_hellman_group_t dh_group; + const char *plugin_name; + char format1[] = " %s PTS DH group %N[%s] available"; + char format2[] = " %s PTS DH group %N not available"; + + *dh_groups = PTS_DH_GROUP_NONE; + + enumerator = lib->crypto->create_dh_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &dh_group, &plugin_name)) + { + if (dh_group == MODP_1024_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE2; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == MODP_1536_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE5; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == MODP_2048_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE14; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == ECP_256_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE19; + DBG2(DBG_PTS, format1, "mandatory", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == ECP_384_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE20; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + } + enumerator->destroy(enumerator); + + if (*dh_groups & PTS_DH_GROUP_IKE19) + { + return TRUE; + } + else + { + DBG1(DBG_PTS, format2, "mandatory", diffie_hellman_group_names, + ECP_256_BIT); + } + return FALSE; +} + +/** + * Described in header. + */ +bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups) +{ + if (strcaseeq(dh_group, "ecp384")) + { + /* nothing to update, all groups are supported */ + return TRUE; + } + if (strcaseeq(dh_group, "ecp256")) + { + /* remove DH group 20 */ + *dh_groups &= ~PTS_DH_GROUP_IKE20; + return TRUE; + } + if (strcaseeq(dh_group, "modp2048")) + { + /* remove DH groups 19 and 20 */ + *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19); + return TRUE; + } + if (strcaseeq(dh_group, "modp1536")) + { + /* remove DH groups 14, 19 and 20 */ + *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 | + PTS_DH_GROUP_IKE14); + return TRUE; + } + if (strcaseeq(dh_group, "modp1024")) + { + /* remove DH groups 5, 14, 19 and 20 */ + *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 | + PTS_DH_GROUP_IKE14 | PTS_DH_GROUP_IKE5); + return TRUE; + } + DBG1(DBG_PTS, "unknown DH group '%s' configured", dh_group); + return FALSE; +} + +/** + * Described in header. + */ +pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_dh_groups, + pts_dh_group_t offered_dh_groups) +{ + if ((supported_dh_groups & PTS_DH_GROUP_IKE20) && + (offered_dh_groups & PTS_DH_GROUP_IKE20)) + { + return PTS_DH_GROUP_IKE20; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE19) && + (offered_dh_groups & PTS_DH_GROUP_IKE19)) + { + return PTS_DH_GROUP_IKE19; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE14) && + (offered_dh_groups & PTS_DH_GROUP_IKE14)) + { + return PTS_DH_GROUP_IKE14; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE5) && + (offered_dh_groups & PTS_DH_GROUP_IKE5)) + { + return PTS_DH_GROUP_IKE5; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE2) && + (offered_dh_groups & PTS_DH_GROUP_IKE2)) + { + return PTS_DH_GROUP_IKE2; + } + return PTS_DH_GROUP_NONE; +} + +/** + * Described in header. + */ +diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group) +{ + switch (dh_group) + { + case PTS_DH_GROUP_IKE2: + return MODP_1024_BIT; + case PTS_DH_GROUP_IKE5: + return MODP_1536_BIT; + case PTS_DH_GROUP_IKE14: + return MODP_2048_BIT; + case PTS_DH_GROUP_IKE19: + return ECP_256_BIT; + case PTS_DH_GROUP_IKE20: + return ECP_384_BIT; + default: + return MODP_NONE; + } +} diff --git a/src/libpts/pts/pts_dh_group.h b/src/libpts/pts/pts_dh_group.h new file mode 100644 index 000000000..8664a4b84 --- /dev/null +++ b/src/libpts/pts/pts_dh_group.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_dh_group pts_dh_group + * @{ @ingroup pts + */ + +#ifndef PTS_DH_GROUP_H_ +#define PTS_DH_GROUP_H_ + +#include <library.h> +#include <crypto/diffie_hellman.h> + +typedef enum pts_dh_group_t pts_dh_group_t; + +/** + * PTS Diffie Hellman Group Values + */ +enum pts_dh_group_t { + /** No DH Group */ + PTS_DH_GROUP_NONE = 0, + /** IKE Group 2 */ + PTS_DH_GROUP_IKE2 = (1<<15), + /** IKE Group 5 */ + PTS_DH_GROUP_IKE5 = (1<<14), + /** IKE Group 14 */ + PTS_DH_GROUP_IKE14 = (1<<13), + /** IKE Group 19 */ + PTS_DH_GROUP_IKE19 = (1<<12), + /** IKE Group 20 */ + PTS_DH_GROUP_IKE20 = (1<<11), +}; + +/** + * Diffie-Hellman Group Values + * see section 3.8.6 of PTS Protocol: Binding to TNC IF-M Specification + * + * 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1|2|3|4|5|R|R|R|R|R|R|R|R|R|R|R| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +/** + * Probe available PTS Diffie-Hellman groups + * + * @param dh_groups returns set of available DH groups + * @return TRUE if mandatory DH groups are available + */ +bool pts_dh_group_probe(pts_dh_group_t *dh_groups); + +/** + * Update supported Diffie-Hellman groups according to configuration + * + * modp1024: PTS_DH_GROUP_IKE2 + * modp1536: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 + * modp2048: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 + * ecp256: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 | + * PTS_DH_GROUP_IKE19 + * ecp384: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 | + * PTS_DH_GROUP_IKE19 | PTS_DH_GROUP_IKE20 + * + * The PTS-IMC is expected to select the strongest supported group + * + * @param dh_group configured DH group + * @param dh_groups returns set of available DH groups + */ +bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups); + +/** + * Select the strongest supported Diffie-Hellman group + * among a set of offered DH groups + * + * @param supported_groups set of supported DH groups + * @param offered_groups set of offered DH groups + * @return selected DH group + */ +pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_dh_groups, + pts_dh_group_t offered_dh_groups); + +/** + * Convert pts_dh_group_t to diffie_hellman_group_t + * + * @param dh_group PTS DH group type + * @return IKE DH group type + */ +diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group); + +#endif /** PTS_DH_GROUP_H_ @}*/ diff --git a/src/libpts/pts/pts_error.c b/src/libpts/pts/pts_error.c index ec1e6c014..6e914b2a9 100644 --- a/src/libpts/pts/pts_error.c +++ b/src/libpts/pts/pts_error.c @@ -56,4 +56,44 @@ pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms) writer->destroy(writer); return attr; -}
\ No newline at end of file +} + +/** + * Described in header. + */ +pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups) +{ + bio_writer_t *writer; + chunk_t msg_info; + pa_tnc_attr_t *attr; + + writer = bio_writer_create(4); + writer->write_uint16(writer, 0x0000); + writer->write_uint16(writer, dh_groups); + msg_info = writer->get_buf(writer); + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, TCG_PTS_DH_GRPS_NOT_SUPPORTED, + msg_info); + writer->destroy(writer); + + return attr; +} + +/** + * Described in header. + */ +pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len) +{ + bio_writer_t *writer; + chunk_t msg_info; + pa_tnc_attr_t *attr; + + writer = bio_writer_create(4); + writer->write_uint16(writer, min_nonce_len); + writer->write_uint16(writer, max_nonce_len); + msg_info = writer->get_buf(writer); + attr = ietf_attr_pa_tnc_error_create(PEN_TCG, TCG_PTS_BAD_NONCE_LENGTH, + msg_info); + writer->destroy(writer); + + return attr; +} diff --git a/src/libpts/pts/pts_error.h b/src/libpts/pts/pts_error.h index 6eeab0792..9a53abd98 100644 --- a/src/libpts/pts/pts_error.h +++ b/src/libpts/pts/pts_error.h @@ -24,32 +24,36 @@ typedef enum pts_error_code_t pts_error_code_t; #include "pts_meas_algo.h" +#include "pts_dh_group.h" #include "pa_tnc/pa_tnc_attr.h" #include <library.h> +#define PTS_MIN_NONCE_LEN 17 +#define PTS_MAX_NONCE_LEN 0xffff + /** * PTS Attestation Error Codes * see section 3.14.2 of PTS Protocol: Binding to TNC IF-M Specification */ enum pts_error_code_t { - TCG_PTS_RESERVED_ERROR = 0, + TCG_PTS_RESERVED_ERROR = 0, TCG_PTS_HASH_ALG_NOT_SUPPORTED = 1, - TCG_PTS_INVALID_PATH = 2, - TCG_PTS_FILE_NOT_FOUND = 3, - TCG_PTS_REG_NOT_SUPPORTED = 4, - TCG_PTS_REG_KEY_NOT_FOUND = 5, - TCG_PTS_DH_GRPS_NOT_SUPPORTED = 6, - TCG_PTS_BAD_NONCE_LENGTH = 7, - TCG_PTS_INVALID_NAME_FAM = 8, + TCG_PTS_INVALID_PATH = 2, + TCG_PTS_FILE_NOT_FOUND = 3, + TCG_PTS_REG_NOT_SUPPORTED = 4, + TCG_PTS_REG_KEY_NOT_FOUND = 5, + TCG_PTS_DH_GRPS_NOT_SUPPORTED = 6, + TCG_PTS_BAD_NONCE_LENGTH = 7, + TCG_PTS_INVALID_NAME_FAM = 8, TCG_PTS_TPM_VERS_NOT_SUPPORTED = 9, - TCG_PTS_INVALID_DELIMITER = 10, + TCG_PTS_INVALID_DELIMITER = 10, TCG_PTS_OPERATION_NOT_SUPPORTED = 11, - TCG_PTS_RM_ERROR = 12, - TCG_PTS_UNABLE_LOCAL_VAL = 13, - TCG_PTS_UNABLE_CUR_EVID = 14, - TCG_PTS_UNABLE_DET_TTC = 15, - TCG_PTS_UNABLE_DET_PCR = 16, + TCG_PTS_RM_ERROR = 12, + TCG_PTS_UNABLE_LOCAL_VAL = 13, + TCG_PTS_UNABLE_CUR_EVID = 14, + TCG_PTS_UNABLE_DET_TTC = 15, + TCG_PTS_UNABLE_DET_PCR = 16, }; /** @@ -61,8 +65,25 @@ extern enum_name_t *pts_error_code_names; * Creates a PTS Hash Algorithm Not Supported Error Attribute * see section 4.2.2 of PTS Protocol: Binding to TNC IF-M Specification * - * @param algorithms supported measurement hash algorithms + * @param algorithms supported measurement hash algorithms */ pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms); +/** + * Creates a PTS DH Group Not Supported Error Attribute + * see section 4.2.4 of PTS Protocol: Binding to TNC IF-M Specification + * + * @param dh_groups supported DH groups + */ +pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups); + +/** + * Creates a PTS DH PN Nonce Not Supported Error Attribute + * see section 4.2.5 of PTS Protocol: Binding to TNC IF-M Specification + * + * @param min_nonce_len minimum nonce length + * @param max_nonce_len maximum nonce length + */ +pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len); + #endif /** PTS_ERROR_H_ @}*/ diff --git a/src/libpts/pts/pts_file_meta.c b/src/libpts/pts/pts_file_meta.c index 0924b3b25..6ed1c01b4 100644 --- a/src/libpts/pts/pts_file_meta.c +++ b/src/libpts/pts/pts_file_meta.c @@ -56,54 +56,15 @@ METHOD(pts_file_meta_t, get_file_count, int, } METHOD(pts_file_meta_t, add, void, - private_pts_file_meta_t *this, char *filename, pts_file_type_t type, - u_int64_t filesize, time_t create_time, time_t last_modify_time, time_t last_access_time, - u_int64_t owner_id, u_int64_t group_id) + private_pts_file_meta_t *this, pts_file_metadata_t *metadata) { - pts_file_metadata_t *entry; - - entry = malloc_thing(pts_file_metadata_t); - - entry->filename = strdup(filename); - entry->meta_length = PTS_FILE_METADATA_SIZE + strlen(entry->filename); - entry->type = type; - entry->filesize = filesize; - entry->create_time = create_time; - entry->last_modify_time = last_modify_time; - entry->last_access_time = last_access_time; - entry->owner_id = owner_id; - entry->group_id = group_id; - - this->list->insert_last(this->list, entry); -} - -/** - * Enumerate file metadata entries - */ -static bool entry_filter(void *null, pts_file_metadata_t **entry, - char **filename, void *i2, u_int16_t *meta_length, void *i3, - pts_file_type_t *type, void *i4, u_int64_t *filesize, void *i5, - time_t *create_time, void *i6, time_t *last_modify_time, void *i7, - time_t *last_access_time, void *i8, u_int64_t *owner_id, void *i9, - u_int64_t *group_id) -{ - *filename = (*entry)->filename; - *meta_length = (*entry)->meta_length; - *type = (*entry)->type; - *filesize = (*entry)->filesize; - *create_time = (*entry)->create_time; - *last_modify_time = (*entry)->last_modify_time; - *last_access_time = (*entry)->last_access_time; - *owner_id = (*entry)->owner_id; - *group_id = (*entry)->group_id; - return TRUE; + this->list->insert_last(this->list, metadata); } METHOD(pts_file_meta_t, create_enumerator, enumerator_t*, private_pts_file_meta_t *this) { - return enumerator_create_filter(this->list->create_enumerator(this->list), - (void*)entry_filter, NULL, NULL); + return this->list->create_enumerator(this->list); } METHOD(pts_file_meta_t, destroy, void, diff --git a/src/libpts/pts/pts_file_meta.h b/src/libpts/pts/pts_file_meta.h index 36a4b6294..3f1813306 100644 --- a/src/libpts/pts/pts_file_meta.h +++ b/src/libpts/pts/pts_file_meta.h @@ -29,22 +29,18 @@ typedef struct pts_file_meta_t pts_file_meta_t; typedef struct pts_file_metadata_t pts_file_metadata_t; -/* Without filename field included */ -#define PTS_FILE_METADATA_SIZE 52 - /** * Structure holding file metadata */ struct pts_file_metadata_t { - u_int16_t meta_length; - pts_file_type_t type; - u_int64_t filesize; - time_t create_time; - time_t last_modify_time; - time_t last_access_time; - u_int64_t owner_id; - u_int64_t group_id; - char *filename; + pts_file_type_t type; + u_int64_t filesize; + u_int64_t created; + u_int64_t modified; + u_int64_t accessed; + u_int64_t owner; + u_int64_t group; + char *filename; }; /** @@ -60,14 +56,12 @@ struct pts_file_meta_t { int (*get_file_count)(pts_file_meta_t *this); /** - * Add a PTS File Metadata + * Add PTS File Metadata * * @param filename Name of measured file or directory * @param metadata File metadata */ - void (*add)(pts_file_meta_t *this, char *filename, pts_file_type_t type, - u_int64_t filesize, time_t create_time, time_t last_modfy_time, time_t last_access_time, - u_int64_t owner_id, u_int64_t group_id); + void (*add)(pts_file_meta_t *this, pts_file_metadata_t *metadata); /** * Create a PTS File Metadata enumerator diff --git a/src/libpts/pts/pts_file_type.c b/src/libpts/pts/pts_file_type.c new file mode 100644 index 000000000..fe849dea4 --- /dev/null +++ b/src/libpts/pts/pts_file_type.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR 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 "pts_file_type.h" + +ENUM(pts_file_type_names, PTS_FILE_OTHER, PTS_FILE_SOCKET, + "Other", + "FIFO", + "Character-Special", + "Reserved-3", + "Directory", + "Reserved-5", + "Block-Special", + "Reserved-7", + "Regular", + "Reserved-9", + "Symbolic-Link", + "Reserved-11", + "Socket" +); + diff --git a/src/libpts/pts/pts_file_type.h b/src/libpts/pts/pts_file_type.h index f3c5b94dd..c1d236888 100644 --- a/src/libpts/pts/pts_file_type.h +++ b/src/libpts/pts/pts_file_type.h @@ -21,6 +21,8 @@ #ifndef PTS_FILE_TYPE_H_ #define PTS_FILE_TYPE_H_ +#include <library.h> + typedef enum pts_file_type_t pts_file_type_t; /** @@ -28,22 +30,34 @@ typedef enum pts_file_type_t pts_file_type_t; * see section 3.17.3 of PTS Protocol: Binding to TNC IF-M Specification */ enum pts_file_type_t { - /** Ignore */ + /** Either unknown or different from standardized types */ PTS_FILE_OTHER = 0x0000, - /** CRTM */ + /** Pipe communication file */ PTS_FILE_FIFO = 0x0001, - /** BIOS */ + /** Character special file */ PTS_FILE_CHAR_SPEC = 0x0002, - /** Platform Extensions */ + /** Reserved */ + PTS_FILE_RESERVED_3 = 0x0003, + /** Directory */ PTS_FILE_DIRECTORY = 0x0004, - /** Motherboard firmware */ + /** Reserved */ + PTS_FILE_RESERVED_5 = 0x0005, + /** Block special file */ PTS_FILE_BLOCK_SPEC = 0x0006, - /** Initial Program Loader */ + /** Reserved */ + PTS_FILE_RESERVED_7 = 0x0007, + /** Regular file */ PTS_FILE_REGULAR = 0x0008, - /** Option ROMs */ + /** Reserved */ + PTS_FILE_RESERVED_9 = 0x0009, + /** Symbolic link */ PTS_FILE_SYM_LINK = 0x000A, - /** Option ROMs */ + /** Reserved */ + PTS_FILE_RESERVED_11 = 0x000B, + /** Socket communication special file */ PTS_FILE_SOCKET = 0x000C, }; +extern enum_name_t *pts_file_type_names; + #endif /** PTS_FILE_TYPE_H_ @}*/ diff --git a/src/libpts/pts/pts_funct_comp_name.h b/src/libpts/pts/pts_funct_comp_name.h deleted file mode 100644 index 0926a2bc7..000000000 --- a/src/libpts/pts/pts_funct_comp_name.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2011 Sansar Choinyambuu - * HSR 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 pts_funct_comp_name pts_funct_comp_name - * @{ @ingroup pts - */ - -#ifndef PTS_FUNCT_COMP_NAME_H_ -#define PTS_FUNCT_COMP_NAME_H_ - -typedef enum pts_funct_comp_type_t pts_funct_comp_type_t; -typedef enum pts_funct_comp_name_t pts_funct_comp_name_t; -typedef struct pts_qualifier_t pts_qualifier_t; - -/** - * PTS Component Functional Type for Qualifier field - */ -enum pts_funct_comp_type_t { - /** Unknown */ - PTS_FUNC_COMP_TYPE_UNKNOWN = 0x0, - /** Trusted Platform */ - PTS_FUNC_COMP_TYPE_TRUSTED = 0x1, - /** Operating System */ - PTS_FUNC_COMP_TYPE_OS = 0x2, - /** Graphical User Interface */ - PTS_FUNC_COMP_TYPE_GUI = 0x3, - /** Application */ - PTS_FUNC_COMP_TYPE_APP = 0x4, - /** Networking */ - PTS_FUNC_COMP_TYPE_NET = 0x5, - /** Library */ - PTS_FUNC_COMP_TYPE_LIB = 0x6, - /** TNC Defined Component */ - PTS_FUNC_COMP_TYPE_TNC = 0x7, - /** All matching Components */ - PTS_FUNC_COMP_TYPE_ALL = 0xF, -}; - -/** - * PTS Component Functional Name Binary Enumeration - */ -enum pts_funct_comp_name_t { - /** Ignore */ - PTS_FUNC_COMP_NAME_IGNORE = 0x0000, - /** CRTM */ - PTS_FUNC_COMP_NAME_CRTM = 0x0001, - /** BIOS */ - PTS_FUNC_COMP_NAME_BIOS = 0x0002, - /** Platform Extensions */ - PTS_FUNC_COMP_NAME_PLATFORM_EXT = 0x0003, - /** Motherboard firmware */ - PTS_FUNC_COMP_NAME_BOARD = 0x0004, - /** Initial Program Loader */ - PTS_FUNC_COMP_NAME_INIT_LOADER = 0x0005, - /** Option ROMs */ - PTS_FUNC_COMP_NAME_OPT_ROMS = 0x0006, -}; - -/** - * Qualifier for Functional Component - */ -struct pts_qualifier_t { - bool kernel; - bool sub_component; - pts_funct_comp_type_t type; -}; - -#endif /** PTS_FUNCT_COMP_NAME_H_ @}*/ diff --git a/src/libpts/pts/pts_meas_algo.c b/src/libpts/pts/pts_meas_algo.c index 260c844d8..865857d3c 100644 --- a/src/libpts/pts/pts_meas_algo.c +++ b/src/libpts/pts/pts_meas_algo.c @@ -17,10 +17,17 @@ #include <debug.h> +ENUM(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_SHA384, + "None", + "SHA1", + "SHA256", + "SHA384" +); + /** * Described in header. */ -bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms) +bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms) { enumerator_t *enumerator; hash_algorithm_t hash_alg; @@ -77,7 +84,57 @@ bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms) /** * Described in header. */ -hash_algorithm_t pts_meas_to_hash_algorithm(pts_meas_algorithms_t algorithm) +bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms) +{ + if (strcaseeq(hash_alg, "sha384") || strcaseeq(hash_alg, "sha2_384")) + { + /* nothing to update, all algorithms are supported */ + return TRUE; + } + if (strcaseeq(hash_alg, "sha256") || strcaseeq(hash_alg, "sha2_256")) + { + /* remove SHA384algorithm */ + *algorithms &= ~PTS_MEAS_ALGO_SHA384; + return TRUE; + } + if (strcaseeq(hash_alg, "sha1")) + { + /* remove SHA384 and SHA256 algorithms */ + *algorithms &= ~(PTS_MEAS_ALGO_SHA384 | PTS_MEAS_ALGO_SHA256); + return TRUE; + } + DBG1(DBG_PTS, "unknown hash algorithm '%s' configured", hash_alg); + return FALSE; +} + +/** + * Described in header. + */ +pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos, + pts_meas_algorithms_t offered_algos) +{ + if ((supported_algos & PTS_MEAS_ALGO_SHA384) && + (offered_algos & PTS_MEAS_ALGO_SHA384)) + { + return PTS_MEAS_ALGO_SHA384; + } + if ((supported_algos & PTS_MEAS_ALGO_SHA256) && + (offered_algos & PTS_MEAS_ALGO_SHA256)) + { + return PTS_MEAS_ALGO_SHA256; + } + if ((supported_algos & PTS_MEAS_ALGO_SHA1) && + (offered_algos & PTS_MEAS_ALGO_SHA1)) + { + return PTS_MEAS_ALGO_SHA1; + } + return PTS_MEAS_ALGO_NONE; +} + +/** + * Described in header. + */ +hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm) { switch (algorithm) { @@ -91,3 +148,23 @@ hash_algorithm_t pts_meas_to_hash_algorithm(pts_meas_algorithms_t algorithm) return HASH_UNKNOWN; } } + +/** + * Described in header. + */ +size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm) +{ + switch (algorithm) + { + case PTS_MEAS_ALGO_SHA1: + return HASH_SIZE_SHA1; + case PTS_MEAS_ALGO_SHA256: + return HASH_SIZE_SHA256; + case PTS_MEAS_ALGO_SHA384: + return HASH_SIZE_SHA384; + case PTS_MEAS_ALGO_NONE: + default: + return 0; + } +} + diff --git a/src/libpts/pts/pts_meas_algo.h b/src/libpts/pts/pts_meas_algo.h index 6aa0ce695..1d96a4946 100644 --- a/src/libpts/pts/pts_meas_algo.h +++ b/src/libpts/pts/pts_meas_algo.h @@ -30,12 +30,18 @@ typedef enum pts_meas_algorithms_t pts_meas_algorithms_t; * PTS Measurement Algorithms */ enum pts_meas_algorithms_t { - PTS_MEAS_ALGO_SHA1 = (1<<15), - PTS_MEAS_ALGO_SHA256 = (1<<14), - PTS_MEAS_ALGO_SHA384 = (1<<13), + PTS_MEAS_ALGO_NONE = 0, + PTS_MEAS_ALGO_SHA1 = (1<<15), + PTS_MEAS_ALGO_SHA256 = (1<<14), + PTS_MEAS_ALGO_SHA384 = (1<<13), }; /** + * enum name for pts_meas_algorithms_t. + */ +extern enum_name_t *pts_meas_algorithm_names; + +/** * Diffie-Hellman Hash Algorithm Values * see section 3.8.5 of PTS Protocol: Binding to TNC IF-M Specification * @@ -53,7 +59,32 @@ enum pts_meas_algorithms_t { * @param algorithms set of available algorithms * @return TRUE if mandatory algorithms are available */ -bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms); +bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms); + +/** + * Update supported PTS measurement algorithms according to configuration + * + * sha1 : PTS_MEAS_ALGO_SHA1 + * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 + * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384 + * + * The PTS-IMC is expected to select the strongest supported algorithm + * + * @param hash_alg configured hash algorithm + * @param algorithms returns set of available PTS measurement algorithms + */ +bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms); + +/** + * Select the strongest PTS measurement algorithm + * among a set of offered PTS measurement algorithms + * + * @param supported_algos set of supported PTS measurement algorithms + * @param offered_algos set of offered PTS measurements algorithms + * @return selected algorithm + */ +pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos, + pts_meas_algorithms_t offered_algos); /** * Convert pts_meas_algorithms_t to hash_algorithm_t @@ -61,6 +92,14 @@ bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms); * @param algorithm PTS measurement algorithm type * @return libstrongswan hash algorithm type */ -hash_algorithm_t pts_meas_to_hash_algorithm(pts_meas_algorithms_t algorithm); +hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm); + +/** + * Return the hash size of a pts_meas_algorithm + * + * @param algorithm PTS measurement algorithm type + * @return hash size in bytes + */ +size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm); #endif /** PTS_MEAS_ALGO_H_ @}*/ diff --git a/src/libpts/pts/pts_req_func_comp_evid.h b/src/libpts/pts/pts_req_func_comp_evid.h new file mode 100644 index 000000000..bbf5bbf5b --- /dev/null +++ b/src/libpts/pts/pts_req_func_comp_evid.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_req_func_comp_evid pts_req_func_comp_evid + * @{ @ingroup pts + */ + +#ifndef PTS_REQ_FUNC_COMP_EVID_H_ +#define PTS_REQ_FUNC_COMP_EVID_H_ + +typedef enum pts_req_func_comp_evid_t pts_req_func_comp_evid_t; + +#include <library.h> + +/** + * PTS Request Functional Component Evidence Flags + */ +enum pts_req_func_comp_evid_t { + /** Transitive Trust Chain flag */ + PTS_REQ_FUNC_COMP_EVID_TTC = (1<<7), + /** Verify Component flag */ + PTS_REQ_FUNC_COMP_EVID_VER = (1<<6), + /** Current Evidence flag */ + PTS_REQ_FUNC_COMP_EVID_CURR = (1<<5), + /** PCR Information flag */ + PTS_REQ_FUNC_COMP_EVID_PCR = (1<<4), +}; + +#endif /** PTS_FUNCT_COMP_EVID_REQ_H_ @}*/ diff --git a/src/libpts/pts/pts_simple_evid_final.h b/src/libpts/pts/pts_simple_evid_final.h new file mode 100644 index 000000000..0c8dea0cc --- /dev/null +++ b/src/libpts/pts/pts_simple_evid_final.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 pts_simple_evid_final pts_rsimple_evid_final + * @{ @ingroup pts + */ + +#ifndef PTS_SIMPLE_EVID_FINAL_H_ +#define PTS_SIMPLE_EVID_FINAL_H_ + +typedef enum pts_simple_evid_final_flag_t pts_simple_evid_final_flag_t; + +#include <library.h> + +/** + * PTS Simple Evidence Final Flags + */ +enum pts_simple_evid_final_flag_t { + /** TPM PCR Composite and TPM Quote Signature not included */ + PTS_SIMPLE_EVID_FINAL_NO = 0x00, + /** TPM PCR Composite and TPM Quote Signature included + * using TPM_QUOTE_INFO */ + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO = 0x40, + /** TPM PCR Composite and TPM Quote Signature included + * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO not appended */ + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 = 0x80, + /** TPM PCR Composite and TPM Quote Signature included + * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO appended */ + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER = 0xC0, + /** Evidence Signature included */ + PTS_SIMPLE_EVID_FINAL_EVID_SIG = 0x20, +}; + +#endif /** PTS_SIMPLE_EVID_FINAL_H_ @}*/ diff --git a/src/libpts/tcg/tcg_attr.c b/src/libpts/tcg/tcg_attr.c index 51acb6792..656791a8f 100644 --- a/src/libpts/tcg/tcg_attr.c +++ b/src/libpts/tcg/tcg_attr.c @@ -14,24 +14,29 @@ #include "tcg_attr.h" #include "tcg/tcg_pts_attr_proto_caps.h" +#include "tcg/tcg_pts_attr_dh_nonce_params_req.h" +#include "tcg/tcg_pts_attr_dh_nonce_params_resp.h" +#include "tcg/tcg_pts_attr_dh_nonce_finish.h" #include "tcg/tcg_pts_attr_meas_algo.h" #include "tcg/tcg_pts_attr_get_tpm_version_info.h" #include "tcg/tcg_pts_attr_tpm_version_info.h" #include "tcg/tcg_pts_attr_get_aik.h" #include "tcg/tcg_pts_attr_aik.h" -#include "tcg/tcg_pts_attr_req_funct_comp_evid.h" +#include "tcg/tcg_pts_attr_req_func_comp_evid.h" #include "tcg/tcg_pts_attr_gen_attest_evid.h" #include "tcg/tcg_pts_attr_simple_comp_evid.h" #include "tcg/tcg_pts_attr_simple_evid_final.h" #include "tcg/tcg_pts_attr_req_file_meas.h" #include "tcg/tcg_pts_attr_file_meas.h" +#include "tcg/tcg_pts_attr_req_file_meta.h" +#include "tcg/tcg_pts_attr_unix_file_meta.h" -ENUM_BEGIN(tcg_attr_names, TCG_PTS_REQ_FUNCT_COMP_EVID, - TCG_PTS_REQ_FUNCT_COMP_EVID, +ENUM_BEGIN(tcg_attr_names, TCG_PTS_REQ_FUNC_COMP_EVID, + TCG_PTS_REQ_FUNC_COMP_EVID, "Request Functional Component Evidence"); ENUM_NEXT(tcg_attr_names, TCG_PTS_GEN_ATTEST_EVID, TCG_PTS_GEN_ATTEST_EVID, - TCG_PTS_REQ_FUNCT_COMP_EVID, + TCG_PTS_REQ_FUNC_COMP_EVID, "Generate Attestation Evidence"); ENUM_NEXT(tcg_attr_names, TCG_PTS_SIMPLE_COMP_EVID, TCG_PTS_SIMPLE_COMP_EVID, @@ -154,6 +159,12 @@ pa_tnc_attr_t* tcg_attr_create_from_data(u_int32_t type, chunk_t value) return tcg_pts_attr_proto_caps_create_from_data(value, TRUE); case TCG_PTS_PROTO_CAPS: return tcg_pts_attr_proto_caps_create_from_data(value, FALSE); + case TCG_PTS_DH_NONCE_PARAMS_REQ: + return tcg_pts_attr_dh_nonce_params_req_create_from_data(value); + case TCG_PTS_DH_NONCE_PARAMS_RESP: + return tcg_pts_attr_dh_nonce_params_resp_create_from_data(value); + case TCG_PTS_DH_NONCE_FINISH: + return tcg_pts_attr_dh_nonce_finish_create_from_data(value); case TCG_PTS_MEAS_ALGO: return tcg_pts_attr_meas_algo_create_from_data(value, FALSE); case TCG_PTS_MEAS_ALGO_SELECTION: @@ -166,8 +177,8 @@ pa_tnc_attr_t* tcg_attr_create_from_data(u_int32_t type, chunk_t value) return tcg_pts_attr_get_aik_create_from_data(value); case TCG_PTS_AIK: return tcg_pts_attr_aik_create_from_data(value); - case TCG_PTS_REQ_FUNCT_COMP_EVID: - return tcg_pts_attr_req_funct_comp_evid_create_from_data(value); + case TCG_PTS_REQ_FUNC_COMP_EVID: + return tcg_pts_attr_req_func_comp_evid_create_from_data(value); case TCG_PTS_GEN_ATTEST_EVID: return tcg_pts_attr_gen_attest_evid_create_from_data(value); case TCG_PTS_SIMPLE_COMP_EVID: @@ -178,17 +189,16 @@ pa_tnc_attr_t* tcg_attr_create_from_data(u_int32_t type, chunk_t value) return tcg_pts_attr_req_file_meas_create_from_data(value); case TCG_PTS_FILE_MEAS: return tcg_pts_attr_file_meas_create_from_data(value); - case TCG_PTS_DH_NONCE_PARAMS_REQ: - case TCG_PTS_DH_NONCE_PARAMS_RESP: - case TCG_PTS_DH_NONCE_FINISH: + case TCG_PTS_REQ_FILE_META: + return tcg_pts_attr_req_file_meta_create_from_data(value); + case TCG_PTS_UNIX_FILE_META: + return tcg_pts_attr_unix_file_meta_create_from_data(value); case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META: case TCG_PTS_TEMPL_REF_MANI_SET_META: case TCG_PTS_UPDATE_TEMPL_REF_MANI: case TCG_PTS_VERIFICATION_RESULT: case TCG_PTS_INTEG_REPORT: - case TCG_PTS_REQ_FILE_META: case TCG_PTS_WIN_FILE_META: - case TCG_PTS_UNIX_FILE_META: case TCG_PTS_REQ_REGISTRY_VALUE: case TCG_PTS_REGISTRY_VALUE: case TCG_PTS_REQ_INTEG_MEAS_LOG: diff --git a/src/libpts/tcg/tcg_attr.h b/src/libpts/tcg/tcg_attr.h index 71ecc1e0a..b45e1488f 100644 --- a/src/libpts/tcg/tcg_attr.h +++ b/src/libpts/tcg/tcg_attr.h @@ -48,7 +48,7 @@ enum tcg_attr_t { TCG_PTS_AIK = 0x0E000000, /* PTS-based Attestation Evidence */ - TCG_PTS_REQ_FUNCT_COMP_EVID = 0x00100000, + TCG_PTS_REQ_FUNC_COMP_EVID = 0x00100000, TCG_PTS_GEN_ATTEST_EVID = 0x00200000, TCG_PTS_SIMPLE_COMP_EVID = 0x00300000, TCG_PTS_SIMPLE_EVID_FINAL = 0x00400000, diff --git a/src/libpts/tcg/tcg_pts_attr_aik.c b/src/libpts/tcg/tcg_pts_attr_aik.c index ffef15f29..9be3794b6 100644 --- a/src/libpts/tcg/tcg_pts_attr_aik.c +++ b/src/libpts/tcg/tcg_pts_attr_aik.c @@ -72,6 +72,11 @@ struct private_tcg_pts_attr_aik_t { * AIK Certificate or Public Key */ certificate_t *aik; + + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -126,6 +131,7 @@ METHOD(pa_tnc_attr_t, build, void, writer->write_uint8(writer, flags); writer->write_data (writer, aik_blob); this->value = chunk_clone(writer->get_buf(writer)); + free(aik_blob.ptr); writer->destroy(writer); } @@ -162,12 +168,22 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_aik_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_aik_t *this) { - DESTROY_IF(this->aik); - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + DESTROY_IF(this->aik); + free(this->value.ptr); + free(this); + } } METHOD(tcg_pts_attr_aik_t, get_aik, certificate_t*, @@ -193,6 +209,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create(certificate_t *aik) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_aik = _get_aik, @@ -200,6 +217,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create(certificate_t *aik) .vendor_id = PEN_TCG, .type = TCG_PTS_AIK, .aik = aik->get_ref(aik), + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -223,6 +241,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_aik = _get_aik, @@ -230,6 +249,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create_from_data(chunk_t data) .vendor_id = PEN_TCG, .type = TCG_PTS_AIK, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c new file mode 100644 index 000000000..dce98e87d --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "tcg_pts_attr_dh_nonce_finish.h" + +#include <pa_tnc/pa_tnc_msg.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> +#include <debug.h> + +typedef struct private_tcg_pts_attr_dh_nonce_finish_t + private_tcg_pts_attr_dh_nonce_finish_t; + +/** + * PTS DH Nonce Finish + * see section 3.8.3 of PTS Protocol: Binding to TNC IF-M Specification + * + * 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 | Nonce Len | Selected Hash Algorithm | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | D-H Initiator Public Value ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | D-H Initiator Nonce ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +#define PTS_DH_NONCE_FINISH_SIZE 12 +#define PTS_DH_NONCE_FINISH_RESERVED 0x00 + +/** + * Private data of an tcg_pts_attr_dh_nonce_finish_t object. + */ +struct private_tcg_pts_attr_dh_nonce_finish_t { + + /** + * Public members of tcg_pts_attr_dh_nonce_finish_t + */ + tcg_pts_attr_dh_nonce_finish_t public; + + /** + * Attribute vendor ID + */ + pen_t vendor_id; + + /** + * Attribute type + */ + u_int32_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Selected Hashing Algorithm + */ + pts_meas_algorithms_t hash_algo; + + /** + * DH Initiator Public Value + */ + chunk_t initiator_value; + + /** + * DH Initiator Nonce + */ + chunk_t initiator_nonce; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + return this->vendor_id; +} + +METHOD(pa_tnc_attr_t, get_type, u_int32_t, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_tcg_pts_attr_dh_nonce_finish_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + bio_writer_t *writer; + + writer = bio_writer_create(PTS_DH_NONCE_FINISH_SIZE); + writer->write_uint8 (writer, PTS_DH_NONCE_FINISH_RESERVED); + writer->write_uint8 (writer, this->initiator_nonce.len); + writer->write_uint16(writer, this->hash_algo); + writer->write_data (writer, this->initiator_value); + writer->write_data (writer, this->initiator_nonce); + + this->value = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_tcg_pts_attr_dh_nonce_finish_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + u_int8_t reserved, nonce_len; + u_int16_t hash_algo; + + if (this->value.len < PTS_DH_NONCE_FINISH_SIZE) + { + DBG1(DBG_TNC, "insufficient data for PTS DH Nonce Finish"); + *offset = 0; + return FAILED; + } + reader = bio_reader_create(this->value); + reader->read_uint8 (reader, &reserved); + reader->read_uint8 (reader, &nonce_len); + reader->read_uint16(reader, &hash_algo); + reader->read_data(reader, reader->remaining(reader) - nonce_len, + &this->initiator_value); + reader->read_data(reader, nonce_len, &this->initiator_nonce); + this->hash_algo = hash_algo; + this->initiator_value = chunk_clone(this->initiator_value); + this->initiator_nonce = chunk_clone(this->initiator_nonce); + reader->destroy(reader); + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this->initiator_value.ptr); + free(this->initiator_nonce.ptr); + free(this); + } +} + +METHOD(tcg_pts_attr_dh_nonce_finish_t, get_hash_algo, pts_meas_algorithms_t, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + return this->hash_algo; +} + +METHOD(tcg_pts_attr_dh_nonce_finish_t, get_initiator_value, chunk_t, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + return this->initiator_value; +} + +METHOD(tcg_pts_attr_dh_nonce_finish_t, get_initiator_nonce, chunk_t, + private_tcg_pts_attr_dh_nonce_finish_t *this) +{ + return this->initiator_nonce; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create( + pts_meas_algorithms_t hash_algo, + chunk_t initiator_value, + chunk_t initiator_nonce) +{ + private_tcg_pts_attr_dh_nonce_finish_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_hash_algo = _get_hash_algo, + .get_initiator_nonce = _get_initiator_nonce, + .get_initiator_value = _get_initiator_value, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_DH_NONCE_FINISH, + .hash_algo = hash_algo, + .initiator_value = initiator_value, + .initiator_nonce = chunk_clone(initiator_nonce), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create_from_data(chunk_t value) +{ + private_tcg_pts_attr_dh_nonce_finish_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_hash_algo = _get_hash_algo, + .get_initiator_nonce = _get_initiator_nonce, + .get_initiator_value = _get_initiator_value, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_DH_NONCE_FINISH, + .value = chunk_clone(value), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.h b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.h new file mode 100644 index 000000000..7148065c5 --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 tcg_pts_attr_dh_nonce_finish tcg_pts_attr_dh_nonce_finish + * @{ @ingroup tcg_pts_attr_dh_nonce_finish + */ + +#ifndef TCG_PTS_ATTR_DH_NONCE_FINISH_H_ +#define TCG_PTS_ATTR_DH_NONCE_FINISH_H_ + +typedef struct tcg_pts_attr_dh_nonce_finish_t tcg_pts_attr_dh_nonce_finish_t; + +#include "tcg_attr.h" +#include "pa_tnc/pa_tnc_attr.h" +#include "pts/pts_meas_algo.h" + +/** + * Class implementing the TCG PTS DH Nonce Finish Attribute + */ +struct tcg_pts_attr_dh_nonce_finish_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get nonce length + * + * @return Length of nonce + */ + u_int8_t (*get_nonce_len)(tcg_pts_attr_dh_nonce_finish_t *this); + + /** + * Get selected hash algorithm + * + * @return Selected hash algorithm + */ + pts_meas_algorithms_t (*get_hash_algo)(tcg_pts_attr_dh_nonce_finish_t *this); + + /** + * Get DH Initiator Public Value + * + * @return DH Initiator Public Value + */ + chunk_t (*get_initiator_value)(tcg_pts_attr_dh_nonce_finish_t *this); + + /** + * Get DH Initiator Nonce + * + * @return DH Initiator Nonce + */ + chunk_t (*get_initiator_nonce)(tcg_pts_attr_dh_nonce_finish_t *this); + +}; + +/** + * Creates an tcg_pts_attr_dh_nonce_finish_t object + * + * @param hash_algo Selected hash algorithm + * @param initiator_value DH Initiator Public Value + * @param initiator_nonce DH Initiator Nonce + */ +pa_tnc_attr_t* tcg_pts_attr_dh_nonce_finish_create( + pts_meas_algorithms_t hash_algo, + chunk_t initiator_value, + chunk_t initiator_nonce); + +/** + * Creates an tcg_pts_attr_dh_nonce_finish_t object from received data + * + * @param value unparsed attribute value + */ +pa_tnc_attr_t* tcg_pts_attr_dh_nonce_finish_create_from_data(chunk_t value); + +#endif /** TCG_PTS_ATTR_DH_NONCE_FINISH_H_ @}*/ diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c new file mode 100644 index 000000000..36266fe12 --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "tcg_pts_attr_dh_nonce_params_req.h" + +#include <pa_tnc/pa_tnc_msg.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> +#include <debug.h> + +typedef struct private_tcg_pts_attr_dh_nonce_params_req_t + private_tcg_pts_attr_dh_nonce_params_req_t; + +/** + * PTS DH Nonce Parameters Request + * see section 3.8.1 of PTS Protocol: Binding to TNC IF-M Specification + * + * 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 | Min. Nonce Len | D-H Group Set | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +#define PTS_DH_NONCE_PARAMS_REQ_SIZE 4 +#define PTS_DH_NONCE_PARAMS_REQ_RESERVED 0x00 + +/** + * Private data of an tcg_pts_attr_dh_nonce_params_req_t object. + */ +struct private_tcg_pts_attr_dh_nonce_params_req_t { + + /** + * Public members of tcg_pts_attr_dh_nonce_params_req_t + */ + tcg_pts_attr_dh_nonce_params_req_t public; + + /** + * Attribute vendor ID + */ + pen_t vendor_id; + + /** + * Attribute type + */ + u_int32_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Minimum acceptable length of nonce + */ + u_int8_t min_nonce_len; + + /** + * Diffie Hellman group set + */ + pts_dh_group_t dh_groups; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + return this->vendor_id; +} + +METHOD(pa_tnc_attr_t, get_type, u_int32_t, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_tcg_pts_attr_dh_nonce_params_req_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + bio_writer_t *writer; + + writer = bio_writer_create(PTS_DH_NONCE_PARAMS_REQ_SIZE); + writer->write_uint8 (writer, PTS_DH_NONCE_PARAMS_REQ_RESERVED); + writer->write_uint8 (writer, this->min_nonce_len); + writer->write_uint16(writer, this->dh_groups); + + this->value = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_tcg_pts_attr_dh_nonce_params_req_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + u_int8_t reserved; + u_int16_t dh_groups; + + if (this->value.len < PTS_DH_NONCE_PARAMS_REQ_SIZE) + { + DBG1(DBG_TNC, "insufficient data for PTS DH Nonce Parameters Request"); + *offset = 0; + return FAILED; + } + reader = bio_reader_create(this->value); + reader->read_uint8(reader, &reserved); + reader->read_uint8(reader, &this->min_nonce_len); + reader->read_uint16(reader, &dh_groups); + this->dh_groups = dh_groups; + reader->destroy(reader); + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } +} + +METHOD(tcg_pts_attr_dh_nonce_params_req_t, get_min_nonce_len, u_int8_t, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + return this->min_nonce_len; +} + +METHOD(tcg_pts_attr_dh_nonce_params_req_t, get_dh_groups, pts_dh_group_t, + private_tcg_pts_attr_dh_nonce_params_req_t *this) +{ + return this->dh_groups; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create(u_int8_t min_nonce_len, + pts_dh_group_t dh_groups) +{ + private_tcg_pts_attr_dh_nonce_params_req_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_min_nonce_len = _get_min_nonce_len, + .get_dh_groups = _get_dh_groups, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_DH_NONCE_PARAMS_REQ, + .min_nonce_len = min_nonce_len, + .dh_groups = dh_groups, + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create_from_data(chunk_t value) +{ + private_tcg_pts_attr_dh_nonce_params_req_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_min_nonce_len = _get_min_nonce_len, + .get_dh_groups = _get_dh_groups, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_DH_NONCE_PARAMS_REQ, + .value = chunk_clone(value), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.h b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.h new file mode 100644 index 000000000..170077156 --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 tcg_pts_attr_dh_nonce_params_req tcg_pts_attr_dh_nonce_params_req + * @{ @ingroup tcg_pts_attr_dh_nonce_params_req + */ + +#ifndef TCG_PTS_ATTR_DH_NONCE_PARAMS_REQ_H_ +#define TCG_PTS_ATTR_DH_NONCE_PARAMS_REQ_H_ + +typedef struct tcg_pts_attr_dh_nonce_params_req_t + tcg_pts_attr_dh_nonce_params_req_t; + +#include "tcg_attr.h" +#include "pa_tnc/pa_tnc_attr.h" +#include "pts/pts_dh_group.h" + +/** + * Class implementing the TCG PTS DH Nonce Parameters Request Attribute + */ +struct tcg_pts_attr_dh_nonce_params_req_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get Minimum nonce length + * + * @return Minimum acceptable length of nonce + */ + u_int8_t (*get_min_nonce_len)(tcg_pts_attr_dh_nonce_params_req_t *this); + + /** + * Get supported Diffie Hellman Groups + * + * @return Supported Diffie Hellman Groups + */ + pts_dh_group_t (*get_dh_groups)(tcg_pts_attr_dh_nonce_params_req_t *this); +}; + +/** + * Creates an tcg_pts_attr_dh_nonce_params_req_t object + * + * @param min_nonce_len Minimum acceptable length of nonce + * @param dh_groups Initiator's supported DH groups + */ +pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_req_create(u_int8_t min_nonce_len, + pts_dh_group_t dh_groups); + +/** + * Creates an tcg_pts_attr_dh_nonce_params_req_t object from received data + * + * @param value unparsed attribute value + */ +pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_req_create_from_data(chunk_t value); + +#endif /** TCG_PTS_ATTR_DH_NONCE_PARAMS_REQ_H_ @}*/ diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c new file mode 100644 index 000000000..09bfa3aac --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "tcg_pts_attr_dh_nonce_params_resp.h" + +#include <pa_tnc/pa_tnc_msg.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> +#include <debug.h> + +typedef struct private_tcg_pts_attr_dh_nonce_params_resp_t + private_tcg_pts_attr_dh_nonce_params_resp_t; + +/** + * PTS DH Nonce Parameters Response + * see section 3.8.2 of PTS Protocol: Binding to TNC IF-M Specification + * + * 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 | Nonce Len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Selected D-H Group | Hash Algorithm Set | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | D-H Responder Nonce ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | D-H Responder Public Value ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +#define PTS_DH_NONCE_PARAMS_RESP_SIZE 16 +#define PTS_DH_NONCE_PARAMS_RESP_RESERVED 0x0000 + +/** + * Private data of an tcg_pts_attr_dh_nonce_params_resp_t object. + */ +struct private_tcg_pts_attr_dh_nonce_params_resp_t { + + /** + * Public members of tcg_pts_attr_dh_nonce_params_resp_t + */ + tcg_pts_attr_dh_nonce_params_resp_t public; + + /** + * Attribute vendor ID + */ + pen_t vendor_id; + + /** + * Attribute type + */ + u_int32_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Selected Diffie Hellman group + */ + pts_dh_group_t dh_group; + + /** + * Supported Hashing Algorithms + */ + pts_meas_algorithms_t hash_algo_set; + + /** + * DH Responder Nonce + */ + chunk_t responder_nonce; + + /** + * DH Responder Public Value + */ + chunk_t responder_value; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->vendor_id; +} + +METHOD(pa_tnc_attr_t, get_type, u_int32_t, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_tcg_pts_attr_dh_nonce_params_resp_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + bio_writer_t *writer; + + writer = bio_writer_create(PTS_DH_NONCE_PARAMS_RESP_SIZE); + writer->write_uint24(writer, PTS_DH_NONCE_PARAMS_RESP_RESERVED); + writer->write_uint8 (writer, this->responder_nonce.len); + writer->write_uint16(writer, this->dh_group); + writer->write_uint16(writer, this->hash_algo_set); + writer->write_data (writer, this->responder_nonce); + writer->write_data (writer, this->responder_value); + + this->value = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_tcg_pts_attr_dh_nonce_params_resp_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + u_int32_t reserved; + u_int8_t nonce_len; + u_int16_t dh_group, hash_algo_set; + + if (this->value.len < PTS_DH_NONCE_PARAMS_RESP_SIZE) + { + DBG1(DBG_TNC, "insufficient data for PTS DH Nonce Parameters Response"); + *offset = 0; + return FAILED; + } + reader = bio_reader_create(this->value); + reader->read_uint24(reader, &reserved); + reader->read_uint8 (reader, &nonce_len); + reader->read_uint16(reader, &dh_group); + reader->read_uint16(reader, &hash_algo_set); + reader->read_data(reader, nonce_len, &this->responder_nonce); + reader->read_data(reader, reader->remaining(reader), &this->responder_value); + this->dh_group = dh_group; + this->hash_algo_set = hash_algo_set; + this->responder_nonce = chunk_clone(this->responder_nonce); + this->responder_value = chunk_clone(this->responder_value); + reader->destroy(reader); + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this->responder_nonce.ptr); + free(this->responder_value.ptr); + free(this); + } +} + +METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_dh_group, pts_dh_group_t, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->dh_group; +} + +METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_hash_algo_set, + pts_meas_algorithms_t, private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->hash_algo_set; +} + +METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_responder_nonce, chunk_t, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->responder_nonce; +} + +METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_responder_value, chunk_t, + private_tcg_pts_attr_dh_nonce_params_resp_t *this) +{ + return this->responder_value; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create(pts_dh_group_t dh_group, + pts_meas_algorithms_t hash_algo_set, + chunk_t responder_nonce, + chunk_t responder_value) +{ + private_tcg_pts_attr_dh_nonce_params_resp_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_dh_group = _get_dh_group, + .get_hash_algo_set = _get_hash_algo_set, + .get_responder_nonce = _get_responder_nonce, + .get_responder_value = _get_responder_value, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_DH_NONCE_PARAMS_RESP, + .dh_group = dh_group, + .hash_algo_set = hash_algo_set, + .responder_nonce = chunk_clone(responder_nonce), + .responder_value = responder_value, + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create_from_data(chunk_t value) +{ + private_tcg_pts_attr_dh_nonce_params_resp_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_dh_group = _get_dh_group, + .get_hash_algo_set = _get_hash_algo_set, + .get_responder_nonce = _get_responder_nonce, + .get_responder_value = _get_responder_value, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_DH_NONCE_PARAMS_RESP, + .value = chunk_clone(value), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.h b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.h new file mode 100644 index 000000000..d2141f8b9 --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 tcg_pts_attr_dh_nonce_params_resp tcg_pts_attr_dh_nonce_params_resp + * @{ @ingroup tcg_pts_attr_dh_nonce_params_resp + */ + +#ifndef TCG_PTS_ATTR_DH_NONCE_PARAMS_RESP_H_ +#define TCG_PTS_ATTR_DH_NONCE_PARAMS_RESP_H_ + +typedef struct tcg_pts_attr_dh_nonce_params_resp_t + tcg_pts_attr_dh_nonce_params_resp_t; + +#include "tcg_attr.h" +#include "pa_tnc/pa_tnc_attr.h" +#include "pts/pts_dh_group.h" +#include "pts/pts_meas_algo.h" + +/** + * Class implementing the TCG PTS DH Nonce Parameters Response Attribute + */ +struct tcg_pts_attr_dh_nonce_params_resp_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get selected Diffie Hellman Group + * + * @return Selected Diffie Hellman Group + */ + pts_dh_group_t (*get_dh_group)(tcg_pts_attr_dh_nonce_params_resp_t *this); + + /** + * Get supported hash algorithms + * + * @return Hash algorithm set + */ + pts_meas_algorithms_t (*get_hash_algo_set)( + tcg_pts_attr_dh_nonce_params_resp_t *this); + + /** + * Get DH Responder Nonce + * + * @return DH Responder Nonce + */ + chunk_t (*get_responder_nonce)(tcg_pts_attr_dh_nonce_params_resp_t *this); + + /** + * Get DH Responder Public Value + * + * @return DH Responder Public Value + */ + chunk_t (*get_responder_value)(tcg_pts_attr_dh_nonce_params_resp_t *this); + +}; + +/** + * Creates an tcg_pts_attr_dh_nonce_params_resp_t object + * + * @param dh_group Selected DH group + * @param hash_algo_set Set of supported hash algorithms + * @param responder_nonce DH Responder Nonce + * @param responder_pub_val DH Responder Public value + */ +pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_resp_create(pts_dh_group_t dh_group, + pts_meas_algorithms_t hash_algo_set, + chunk_t responder_nonce, + chunk_t responder_value); + +/** + * Creates an tcg_pts_attr_dh_nonce_params_resp_t object from received data + * + * @param value unparsed attribute value + */ +pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_resp_create_from_data(chunk_t value); + +#endif /** TCG_PTS_ATTR_DH_NONCE_PARAMS_RESP_H_ @}*/ diff --git a/src/libpts/tcg/tcg_pts_attr_file_meas.c b/src/libpts/tcg/tcg_pts_attr_file_meas.c index fe559d004..737da65c1 100644 --- a/src/libpts/tcg/tcg_pts_attr_file_meas.c +++ b/src/libpts/tcg/tcg_pts_attr_file_meas.c @@ -88,6 +88,10 @@ struct private_tcg_pts_attr_file_meas_t { */ pts_file_meas_t *measurements; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -133,11 +137,9 @@ METHOD(pa_tnc_attr_t, build, void, number_of_files = this->measurements->get_file_count(this->measurements); request_id = this->measurements->get_request_id(this->measurements); - writer = bio_writer_create(PTS_FILE_MEAS_SIZE); - /* Write the 64 bit integer as two 32 bit parts */ - writer->write_uint32(writer, number_of_files >> 32); - writer->write_uint32(writer, number_of_files & 0xffffffff); + writer = bio_writer_create(PTS_FILE_MEAS_SIZE); + writer->write_uint64(writer, number_of_files); writer->write_uint16(writer, request_id); enumerator = this->measurements->create_enumerator(this->measurements); @@ -168,8 +170,7 @@ METHOD(pa_tnc_attr_t, process, status_t, private_tcg_pts_attr_file_meas_t *this, u_int32_t *offset) { bio_reader_t *reader; - int count; - u_int32_t number_of_files; + u_int64_t number_of_files; u_int16_t request_id, meas_len, filename_len; size_t len; chunk_t measurement, filename; @@ -182,18 +183,15 @@ METHOD(pa_tnc_attr_t, process, status_t, *offset = 0; return FAILED; } - reader = bio_reader_create(this->value); - reader->read_uint32(reader, &number_of_files); - count = (sizeof(count) > 4) ? number_of_files << 32 : 0; - reader->read_uint32(reader, &number_of_files); - count += number_of_files; + reader = bio_reader_create(this->value); + reader->read_uint64(reader, &number_of_files); reader->read_uint16(reader, &request_id); reader->read_uint16(reader, &meas_len); this->measurements = pts_file_meas_create(request_id); - while (count--) + while (number_of_files--) { if (!reader->read_data(reader, meas_len, &measurement)) { @@ -223,12 +221,21 @@ end: return status; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_file_meas_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_file_meas_t *this) { - this->measurements->destroy(this->measurements); - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + this->measurements->destroy(this->measurements); + free(this->value.ptr); + free(this); + } } METHOD(tcg_pts_attr_file_meas_t, get_measurements, pts_file_meas_t*, @@ -254,6 +261,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create(pts_file_meas_t *measurements) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_measurements = _get_measurements, @@ -261,6 +269,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create(pts_file_meas_t *measurements) .vendor_id = PEN_TCG, .type = TCG_PTS_FILE_MEAS, .measurements = measurements, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -284,6 +293,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_measurements = _get_measurements, @@ -291,6 +301,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create_from_data(chunk_t data) .vendor_id = PEN_TCG, .type = TCG_PTS_FILE_MEAS, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c b/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c index 4d8aa7bee..054285c4e 100644 --- a/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c +++ b/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c @@ -20,7 +20,8 @@ #include <bio/bio_reader.h> #include <debug.h> -typedef struct private_tcg_pts_attr_gen_attest_evid_t private_tcg_pts_attr_gen_attest_evid_t; +typedef struct private_tcg_pts_attr_gen_attest_evid_t + private_tcg_pts_attr_gen_attest_evid_t; /** * Generate Attestation Evidence @@ -67,6 +68,11 @@ struct private_tcg_pts_attr_gen_attest_evid_t { * Noskip flag */ bool noskip_flag; + + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -130,11 +136,21 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_gen_attest_evid_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_gen_attest_evid_t *this) { - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } } /** @@ -154,11 +170,13 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create() .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, }, .vendor_id = PEN_TCG, .type = TCG_PTS_GEN_ATTEST_EVID, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -182,12 +200,14 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, }, .vendor_id = PEN_TCG, .type = TCG_PTS_GEN_ATTEST_EVID, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_get_aik.c b/src/libpts/tcg/tcg_pts_attr_get_aik.c index 727c7a211..1875375a4 100644 --- a/src/libpts/tcg/tcg_pts_attr_get_aik.c +++ b/src/libpts/tcg/tcg_pts_attr_get_aik.c @@ -65,6 +65,11 @@ struct private_tcg_pts_attr_get_aik_t { * Noskip flag */ bool noskip_flag; + + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -128,11 +133,21 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_get_aik_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_get_aik_t *this) { - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } } /** @@ -152,11 +167,13 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create() .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, }, .vendor_id = PEN_TCG, .type = TCG_PTS_GET_AIK, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -180,12 +197,14 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, }, .vendor_id = PEN_TCG, .type = TCG_PTS_GET_AIK, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c index 51cb99a8e..cb6834ca5 100644 --- a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c +++ b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c @@ -20,7 +20,8 @@ #include <bio/bio_reader.h> #include <debug.h> -typedef struct private_tcg_pts_attr_get_tpm_version_info_t private_tcg_pts_attr_get_tpm_version_info_t; +typedef struct private_tcg_pts_attr_get_tpm_version_info_t + private_tcg_pts_attr_get_tpm_version_info_t; /** * Get TPM Version Information @@ -67,6 +68,11 @@ struct private_tcg_pts_attr_get_tpm_version_info_t { * Noskip flag */ bool noskip_flag; + + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -130,11 +136,21 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_get_tpm_version_info_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_get_tpm_version_info_t *this) { - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } } /** @@ -154,11 +170,13 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create() .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, }, .vendor_id = PEN_TCG, .type = TCG_PTS_GET_TPM_VERSION_INFO, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -182,12 +200,14 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, }, .vendor_id = PEN_TCG, .type = TCG_PTS_GET_TPM_VERSION_INFO, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h index 255efaafa..1b693402a 100644 --- a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h +++ b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h @@ -21,7 +21,8 @@ #ifndef TCG_PTS_ATTR_GET_TPM_VERSION_INFO_H_ #define TCG_PTS_ATTR_GET_TPM_VERSION_INFO_H_ -typedef struct tcg_pts_attr_get_tpm_version_info_t tcg_pts_attr_get_tpm_version_info_t; +typedef struct tcg_pts_attr_get_tpm_version_info_t + tcg_pts_attr_get_tpm_version_info_t; #include "tcg_attr.h" #include "pa_tnc/pa_tnc_attr.h" diff --git a/src/libpts/tcg/tcg_pts_attr_meas_algo.c b/src/libpts/tcg/tcg_pts_attr_meas_algo.c index dffc15320..ed520e3cd 100644 --- a/src/libpts/tcg/tcg_pts_attr_meas_algo.c +++ b/src/libpts/tcg/tcg_pts_attr_meas_algo.c @@ -72,6 +72,10 @@ struct private_tcg_pts_attr_meas_algo_t { */ pts_meas_algorithms_t algorithms; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -140,8 +144,18 @@ METHOD(pa_tnc_attr_t, process, status_t, METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_meas_algo_t *this) { - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_meas_algo_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; } METHOD(tcg_pts_attr_meas_algo_t, get_algorithms, pts_meas_algorithms_t, @@ -168,6 +182,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create(pts_meas_algorithms_t algorithms, .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_algorithms = _get_algorithms, @@ -175,6 +190,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create(pts_meas_algorithms_t algorithms, .vendor_id = PEN_TCG, .type = selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO, .algorithms = algorithms, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -199,6 +215,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create_from_data(chunk_t data, .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_algorithms = _get_algorithms, @@ -206,6 +223,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create_from_data(chunk_t data, .vendor_id = PEN_TCG, .type = selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_proto_caps.c b/src/libpts/tcg/tcg_pts_attr_proto_caps.c index 6d078905d..055c750ff 100644 --- a/src/libpts/tcg/tcg_pts_attr_proto_caps.c +++ b/src/libpts/tcg/tcg_pts_attr_proto_caps.c @@ -72,6 +72,10 @@ struct private_tcg_pts_attr_proto_caps_t { */ pts_proto_caps_flag_t flags; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -141,8 +145,18 @@ METHOD(pa_tnc_attr_t, process, status_t, METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_proto_caps_t *this) { - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_proto_caps_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; } METHOD(tcg_pts_attr_proto_caps_t, get_flags, pts_proto_caps_flag_t, @@ -169,6 +183,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create(pts_proto_caps_flag_t flags, .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_flags = _get_flags, @@ -176,6 +191,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create(pts_proto_caps_flag_t flags, .vendor_id = PEN_TCG, .type = request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS, .flags = flags, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -199,6 +215,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create_from_data(chunk_t data, .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_flags = _get_flags, @@ -206,6 +223,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create_from_data(chunk_t data, .vendor_id = PEN_TCG, .type = request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_req_file_meas.c b/src/libpts/tcg/tcg_pts_attr_req_file_meas.c index 68ecfa8f1..17781f745 100644 --- a/src/libpts/tcg/tcg_pts_attr_req_file_meas.c +++ b/src/libpts/tcg/tcg_pts_attr_req_file_meas.c @@ -93,6 +93,10 @@ struct private_tcg_pts_attr_req_file_meas_t { */ char *pathname; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -181,12 +185,22 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_req_file_meas_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_req_file_meas_t *this) { - free(this->pathname); - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->pathname); + free(this->value.ptr); + free(this); + } } METHOD(tcg_pts_attr_req_file_meas_t, get_directory_flag, bool, @@ -233,6 +247,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_directory_flag = _get_directory_flag, @@ -246,6 +261,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, .request_id = request_id, .delimiter = delimiter, .pathname = strdup(pathname), + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -269,6 +285,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_directory_flag = _get_directory_flag, @@ -279,6 +296,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data) .vendor_id = PEN_TCG, .type = TCG_PTS_REQ_FILE_MEAS, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_req_file_meta.c b/src/libpts/tcg/tcg_pts_attr_req_file_meta.c index f42903e03..bef6b5db6 100644 --- a/src/libpts/tcg/tcg_pts_attr_req_file_meta.c +++ b/src/libpts/tcg/tcg_pts_attr_req_file_meta.c @@ -86,6 +86,10 @@ struct private_tcg_pts_attr_req_file_meta_t { */ char *pathname; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -177,9 +181,19 @@ METHOD(pa_tnc_attr_t, process, status_t, METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_req_file_meta_t *this) { - free(this->pathname); - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->pathname); + free(this->value.ptr); + free(this); + } +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_req_file_meta_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; } METHOD(tcg_pts_attr_req_file_meta_t, get_directory_flag, bool, @@ -188,7 +202,7 @@ METHOD(tcg_pts_attr_req_file_meta_t, get_directory_flag, bool, return this->directory_flag; } -METHOD(tcg_pts_attr_req_file_meta_t, get_delimiter, u_int32_t, +METHOD(tcg_pts_attr_req_file_meta_t, get_delimiter, u_int8_t, private_tcg_pts_attr_req_file_meta_t *this) { return this->delimiter; @@ -203,7 +217,7 @@ METHOD(tcg_pts_attr_req_file_meta_t, get_pathname, char*, /** * Described in header. */ -pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, +pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create(bool directory_flag, u_int8_t delimiter, char *pathname) { @@ -219,6 +233,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_directory_flag = _get_directory_flag, @@ -230,6 +245,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, .directory_flag = directory_flag, .delimiter = delimiter, .pathname = strdup(pathname), + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -239,7 +255,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, /** * Described in header. */ -pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data) +pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create_from_data(chunk_t data) { private_tcg_pts_attr_req_file_meta_t *this; @@ -253,6 +269,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_directory_flag = _get_directory_flag, @@ -262,6 +279,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data) .vendor_id = PEN_TCG, .type = TCG_PTS_REQ_FILE_META, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c new file mode 100644 index 000000000..bfd108b9f --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 "tcg_pts_attr_req_func_comp_evid.h" + +#include <pa_tnc/pa_tnc_msg.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> +#include <utils/linked_list.h> +#include <debug.h> + +typedef struct private_tcg_pts_attr_req_func_comp_evid_t private_tcg_pts_attr_req_func_comp_evid_t; + +/** + * Request Functional Component Evidence + * see section 3.14.1 of PTS Protocol: Binding to TNC IF-M Specification + * + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Flags | Sub-component Depth (for Component #1) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Component Functional Name #1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Component Functional Name #1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ........ | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Flags | Sub-component Depth (for Component #N) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Component Functional Name #N | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Component Functional Name #N | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +/** + * Component Functional Name Structure + * (see section 5.1 of PTS Protocol: Binding to TNC IF-M Specification) + * + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Component Functional Name Vendor ID |Fam| Qualifier | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Component Functional Name | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#define PTS_REQ_FUNC_COMP_EVID_SIZE 12 +#define PTS_REQ_FUNC_COMP_FAMILY_MASK 0xC0 + +/** + * Private data of an tcg_pts_attr_req_func_comp_evid_t object. + */ +struct private_tcg_pts_attr_req_func_comp_evid_t { + + /** + * Public members of tcg_pts_attr_req_func_comp_evid_t + */ + tcg_pts_attr_req_func_comp_evid_t public; + + /** + * Attribute vendor ID + */ + pen_t vendor_id; + + /** + * Attribute type + */ + u_int32_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * List of Functional Components + */ + linked_list_t *list; + + /** + * Reference count + */ + refcount_t ref; +}; + +typedef struct entry_t entry_t; + +/** + * Functional component entry + */ +struct entry_t { + u_int8_t flags; + u_int32_t depth; + pts_comp_func_name_t *name; +}; + +/** + * Enumerate functional component entries + */ +static bool entry_filter(void *null, entry_t **entry, u_int8_t *flags, + void *i2, u_int32_t *depth, void *i3, + pts_comp_func_name_t **name) +{ + *flags = (*entry)->flags; + *depth = (*entry)->depth; + *name = (*entry)->name; + + return TRUE; +} + +/** + * Free an entry_t object + */ +static void free_entry(entry_t *this) +{ + if (this) + { + this->name->destroy(this->name); + free(this); + } +} + +METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + return this->vendor_id; +} + +METHOD(pa_tnc_attr_t, get_type, u_int32_t, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_tcg_pts_attr_req_func_comp_evid_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + bio_writer_t *writer; + enumerator_t *enumerator; + entry_t *entry; + + writer = bio_writer_create(PTS_REQ_FUNC_COMP_EVID_SIZE); + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + writer->write_uint8 (writer, entry->flags); + writer->write_uint24(writer, entry->depth); + writer->write_uint24(writer, entry->name->get_vendor_id(entry->name)); + writer->write_uint8 (writer, entry->name->get_qualifier(entry->name)); + writer->write_uint32(writer, entry->name->get_name(entry->name)); + } + enumerator->destroy(enumerator); + + this->value = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_tcg_pts_attr_req_func_comp_evid_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + u_int32_t depth, vendor_id, name; + u_int8_t flags, fam_and_qualifier, qualifier; + status_t status = FAILED; + entry_t *entry = NULL; + + if (this->value.len < PTS_REQ_FUNC_COMP_EVID_SIZE) + { + DBG1(DBG_TNC, "insufficient data for Request Functional " + "Component Evidence"); + *offset = 0; + return FAILED; + } + reader = bio_reader_create(this->value); + + while (reader->remaining(reader)) + { + if (!reader->read_uint8(reader, &flags)) + { + DBG1(DBG_TNC, "insufficient data for PTS Request Functional " + "Component Evidence Flags"); + goto end; + } + if (!reader->read_uint24(reader, &depth)) + { + DBG1(DBG_TNC, "insufficient data for PTS Request Functional " + "Component Evidence Sub Component Depth"); + goto end; + } + if (!reader->read_uint24(reader, &vendor_id)) + { + DBG1(DBG_TNC, "insufficient data for PTS Request Functional " + "Component Evidence Component Name Vendor ID"); + goto end; + } + if (!reader->read_uint8(reader, &fam_and_qualifier)) + { + DBG1(DBG_TNC, "insufficient data for PTS Request Functional " + "Component Evidence Family and Qualifier"); + goto end; + } + if (fam_and_qualifier & PTS_REQ_FUNC_COMP_FAMILY_MASK) + { + DBG1(DBG_TNC, "the Functional Name Encoding Family " + "is not Binary Enumeration"); + goto end; + } + if (!reader->read_uint32(reader, &name)) + { + DBG1(DBG_TNC, "insufficient data for PTS Request Functional " + "Component Evidence Component Functional Name"); + goto end; + } + qualifier = fam_and_qualifier & ~PTS_REQ_FUNC_COMP_FAMILY_MASK; + + entry = malloc_thing(entry_t); + entry->flags = flags; + entry->depth = depth; + entry->name = pts_comp_func_name_create(vendor_id, name, qualifier); + + this->list->insert_last(this->list, entry); + } + status = SUCCESS; + +end: + reader->destroy(reader); + return status; +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + if (ref_put(&this->ref)) + { + this->list->destroy_function(this->list, (void *)free_entry); + free(this->value.ptr); + free(this); + } +} + +METHOD(tcg_pts_attr_req_func_comp_evid_t, add_component, void, + private_tcg_pts_attr_req_func_comp_evid_t *this, u_int8_t flags, + u_int32_t depth, pts_comp_func_name_t *name) +{ + entry_t *entry; + + entry = malloc_thing(entry_t); + entry->flags = flags; + entry->depth = depth; + entry->name = name; + this->list->insert_last(this->list, entry); +} + +METHOD(tcg_pts_attr_req_func_comp_evid_t, get_count, int, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + return this->list->get_count(this->list); +} + +METHOD(tcg_pts_attr_req_func_comp_evid_t, create_enumerator, enumerator_t*, + private_tcg_pts_attr_req_func_comp_evid_t *this) +{ + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)entry_filter, NULL, NULL); +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create(void) +{ + private_tcg_pts_attr_req_func_comp_evid_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .add_component = _add_component, + .get_count = _get_count, + .create_enumerator = _create_enumerator, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_REQ_FUNC_COMP_EVID, + .list = linked_list_create(), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create_from_data(chunk_t data) +{ + private_tcg_pts_attr_req_func_comp_evid_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .add_component = _add_component, + .get_count = _get_count, + .create_enumerator = _create_enumerator, + }, + .vendor_id = PEN_TCG, + .type = TCG_PTS_REQ_FUNC_COMP_EVID, + .list = linked_list_create(), + .value = chunk_clone(data), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} diff --git a/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.h b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.h new file mode 100644 index 000000000..031955aca --- /dev/null +++ b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR 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 tcg_pts_attr_req_func_comp_evid tcg_pts_attr_req_func_comp_evid + * @{ @ingroup tcg_pts_attr_req_func_comp_evid + */ + +#ifndef TCG_PTS_ATTR_REQ_FUNC_COMP_EVID_H_ +#define TCG_PTS_ATTR_REQ_FUNC_COMP_EVID_H_ + +typedef struct tcg_pts_attr_req_func_comp_evid_t tcg_pts_attr_req_func_comp_evid_t; + +#include "tcg_attr.h" +#include "pts/components/pts_comp_func_name.h" +#include "pa_tnc/pa_tnc_attr.h" + +/** + * Class implementing the TCG PTS Request Functional Component Evidence attribute + * + */ +struct tcg_pts_attr_req_func_comp_evid_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Add a component to the Functional Component Evidence Request + * + * @param flags Component Evidence Request Flags + * @param depth Sub-component Depth + * @param name Functional Component Name + */ + void (*add_component)(tcg_pts_attr_req_func_comp_evid_t *this, + u_int8_t flags, u_int32_t depth, + pts_comp_func_name_t *name); + + /** + * Returns the number of Functional Component entries + * + * @return Number of entries + */ + int (*get_count)(tcg_pts_attr_req_func_comp_evid_t *this); + + /** + * Enumerator over Functional Component entries + * + * @return Entry enumerator + */ + enumerator_t* (*create_enumerator)(tcg_pts_attr_req_func_comp_evid_t *this); + +}; + +/** + * Creates a tcg_pts_attr_req_func_comp_evid_t object + */ +pa_tnc_attr_t* tcg_pts_attr_req_func_comp_evid_create(void); + +/** + * Creates a tcg_pts_attr_req_func_comp_evid_t object from received data + * + * @param value Unparsed attribute value + */ +pa_tnc_attr_t* tcg_pts_attr_req_func_comp_evid_create_from_data(chunk_t value); + +#endif /** TCG_PTS_ATTR_REQ_FUNC_COMP_EVID_H_ @}*/ diff --git a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.c deleted file mode 100644 index 0f460580b..000000000 --- a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (C) 2011 Sansar Choinyambuu - * HSR 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 "tcg_pts_attr_req_funct_comp_evid.h" - -#include <pa_tnc/pa_tnc_msg.h> -#include <bio/bio_writer.h> -#include <bio/bio_reader.h> -#include <debug.h> - -typedef struct private_tcg_pts_attr_req_funct_comp_evid_t private_tcg_pts_attr_req_funct_comp_evid_t; - -/** - * Request Functional Component Evidence - * see section 3.14.1 of PTS Protocol: Binding to TNC IF-M Specification - * - * 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 - * - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Flags | Sub-component Depth | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Component Functional Name | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ - -/** - * Component Functional Name Structure (see section 5.1 of PTS Protocol: Binding to TNC IF-M Specification) - * - * 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 - * - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Component Functional Name Vendor ID |Fam| Qualifier | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Component Functional Name | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ - -/** - * Qualifier for Functional Component - * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification - * - * - * 0 1 2 3 4 5 - * +-+-+-+-+-+-+ - * |K|S| Type | - * +-+-+-+-+-+-+ - */ - -#define PTS_REQ_FUNCT_COMP_EVID_SIZE 12 -#define PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM 0x00 - -/** - * Private data of an tcg_pts_attr_req_funct_comp_evid_t object. - */ -struct private_tcg_pts_attr_req_funct_comp_evid_t { - - /** - * Public members of tcg_pts_attr_req_funct_comp_evid_t - */ - tcg_pts_attr_req_funct_comp_evid_t public; - - /** - * Attribute vendor ID - */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; - - /** - * Attribute value - */ - chunk_t value; - - /** - * Noskip flag - */ - bool noskip_flag; - - /** - * Set of flags for Request Functional Component - */ - pts_attr_req_funct_comp_evid_flag_t flags; - - /** - * Sub-component Depth - */ - u_int32_t depth; - - /** - * Component Functional Name Vendor ID - */ - u_int32_t comp_vendor_id; - - /** - * Functional Name Encoding Family - */ - u_int8_t family; - - /** - * Functional Name Category Qualifier - */ - pts_qualifier_t qualifier; - - /** - * Component Functional Name - */ - pts_funct_comp_name_t name; -}; - -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->type; -} - -METHOD(pa_tnc_attr_t, get_value, chunk_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->value; -} - -METHOD(pa_tnc_attr_t, get_noskip_flag, bool, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->noskip_flag; -} - -METHOD(pa_tnc_attr_t, set_noskip_flag,void, - private_tcg_pts_attr_req_funct_comp_evid_t *this, bool noskip) -{ - this->noskip_flag = noskip; -} - -METHOD(pa_tnc_attr_t, build, void, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - bio_writer_t *writer; - u_int8_t flags = 0; - u_int8_t qualifier = 0; - - writer = bio_writer_create(PTS_REQ_FUNCT_COMP_EVID_SIZE); - - /* Determine the flags to set*/ - if (this->flags & PTS_REQ_FUNC_COMP_FLAG_PCR) - { - flags += 128; - } - if (this->flags & PTS_REQ_FUNC_COMP_FLAG_CURR) - { - flags += 64; - } - if (this->flags & PTS_REQ_FUNC_COMP_FLAG_VER) - { - flags += 32; - } - if (this->flags & PTS_REQ_FUNC_COMP_FLAG_TTC) - { - flags += 16; - } - writer->write_uint8(writer, flags); - - writer->write_uint24 (writer, this->depth); - writer->write_uint24 (writer, this->comp_vendor_id); - - if (this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM) - { - DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00"); - } - - qualifier += this->qualifier.type; - if (this->qualifier.kernel) - { - qualifier += 16; - } - if (this->qualifier.sub_component) - { - qualifier += 32; - } - writer->write_uint8 (writer, qualifier); - writer->write_uint32 (writer, this->name); - - this->value = chunk_clone(writer->get_buf(writer)); - writer->destroy(writer); -} - -METHOD(pa_tnc_attr_t, process, status_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this, u_int32_t *offset) -{ - bio_reader_t *reader; - u_int8_t flags; - u_int8_t fam_and_qualifier; - - if (this->value.len < PTS_REQ_FUNCT_COMP_EVID_SIZE) - { - DBG1(DBG_TNC, "insufficient data for Request Functional Component Evidence"); - *offset = 0; - return FAILED; - } - reader = bio_reader_create(this->value); - - reader->read_uint8(reader, &flags); - if ((flags >> 4) & 1) - { - this->flags |= PTS_REQ_FUNC_COMP_FLAG_PCR; - } - if ((flags >> 5) & 1) - { - this->flags |= PTS_REQ_FUNC_COMP_FLAG_CURR; - } - if ((flags >> 6) & 1) - { - this->flags |= PTS_REQ_FUNC_COMP_FLAG_VER; - } - if ((flags >> 7) & 1) - { - this->flags |= PTS_REQ_FUNC_COMP_FLAG_TTC; - } - - reader->read_uint24(reader, &this->depth); - reader->read_uint24(reader, &this->comp_vendor_id); - reader->read_uint8(reader, &fam_and_qualifier); - - if (((fam_and_qualifier >> 6) & 1) ) - { - this->family += 1; - } - if (((fam_and_qualifier >> 7) & 1) ) - { - this->family += 2; - } - - /* TODO: Generate an IF-M error attribute indicating */ - /* TCG_PTS_INVALID_NAME_FAM */ - //if (&this->comp_vendor_id==PEN_TCG && this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM) - //{ - // DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00"); - //} - - if (((fam_and_qualifier >> 5) & 1) ) - { - this->qualifier.kernel = true; - } - if (((fam_and_qualifier >> 4) & 1) ) - { - this->qualifier.sub_component = true; - } - this->qualifier.type = ( fam_and_qualifier & 0xF ); - /* TODO: Check the type is defined in pts_attr_req_funct_comp_type_t */ - - reader->read_uint32(reader, &this->name); - /* TODO: Check the name is defined in pts_funct_comp_name_t */ - - reader->destroy(reader); - return SUCCESS; -} - -METHOD(pa_tnc_attr_t, destroy, void, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - free(this->value.ptr); - free(this); -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_flags, pts_attr_req_funct_comp_evid_flag_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->flags; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, set_flags, void, - private_tcg_pts_attr_req_funct_comp_evid_t *this, pts_attr_req_funct_comp_evid_flag_t flags) -{ - this->flags = flags; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_sub_component_depth, u_int32_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->depth; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_comp_funct_name_vendor_id, u_int32_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->comp_vendor_id; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_family, u_int8_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->family; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_qualifier, pts_qualifier_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->qualifier; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, set_qualifier, void, - private_tcg_pts_attr_req_funct_comp_evid_t *this, pts_qualifier_t qualifier) -{ - this->qualifier = qualifier; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_comp_funct_name, pts_funct_comp_name_t, - private_tcg_pts_attr_req_funct_comp_evid_t *this) -{ - return this->name; -} - -METHOD(tcg_pts_attr_req_funct_comp_evid_t, set_comp_funct_name, void, - private_tcg_pts_attr_req_funct_comp_evid_t *this, pts_funct_comp_name_t name) -{ - this->name = name; -} - -/** - * Described in header. - */ -pa_tnc_attr_t *tcg_pts_attr_req_funct_comp_evid_create( - pts_attr_req_funct_comp_evid_flag_t flags, - u_int32_t depth, u_int32_t vendor_id, - pts_qualifier_t qualifier, - pts_funct_comp_name_t name) -{ - private_tcg_pts_attr_req_funct_comp_evid_t *this; - - INIT(this, - .public = { - .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, - .get_type = _get_type, - .get_value = _get_value, - .get_noskip_flag = _get_noskip_flag, - .set_noskip_flag = _set_noskip_flag, - .build = _build, - .process = _process, - .destroy = _destroy, - }, - .get_flags= _get_flags, - .set_flags= _set_flags, - .get_sub_component_depth = _get_sub_component_depth, - .get_comp_funct_name_vendor_id = _get_comp_funct_name_vendor_id, - .get_family = _get_family, - .get_qualifier = _get_qualifier, - .set_qualifier = _set_qualifier, - .get_comp_funct_name = _get_comp_funct_name, - .set_comp_funct_name = _set_comp_funct_name, - }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FUNCT_COMP_EVID, - .flags = flags, - .depth = depth, - .comp_vendor_id = vendor_id, - .family = PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM, - .qualifier = qualifier, - .name = name, - ); - - return &this->public.pa_tnc_attribute; -} - - -/** - * Described in header. - */ -pa_tnc_attr_t *tcg_pts_attr_req_funct_comp_evid_create_from_data(chunk_t data) -{ - private_tcg_pts_attr_req_funct_comp_evid_t *this; - - INIT(this, - .public = { - .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, - .get_type = _get_type, - .get_value = _get_value, - .get_noskip_flag = _get_noskip_flag, - .set_noskip_flag = _set_noskip_flag, - .build = _build, - .process = _process, - .destroy = _destroy, - }, - .get_flags= _get_flags, - .set_flags= _set_flags, - .get_sub_component_depth = _get_sub_component_depth, - .get_comp_funct_name_vendor_id = _get_comp_funct_name_vendor_id, - .get_family = _get_family, - .get_qualifier = _get_qualifier, - .set_qualifier = _set_qualifier, - .get_comp_funct_name = _get_comp_funct_name, - .set_comp_funct_name = _set_comp_funct_name, - }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FUNCT_COMP_EVID, - .value = chunk_clone(data), - ); - - return &this->public.pa_tnc_attribute; -} diff --git a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.h b/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.h deleted file mode 100644 index 215ce6408..000000000 --- a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2011 Sansar Choinyambuu - * HSR 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 tcg_pts_attr_req_funct_comp_evid tcg_pts_attr_req_funct_comp_evid - * @{ @ingroup tcg_pts_attr_req_funct_comp_evid - */ - -#ifndef TCG_PTS_ATTR_REQ_FUNCT_COMP_EVID_H_ -#define TCG_PTS_ATTR_REQ_FUNCT_COMP_EVID_H_ - -typedef struct tcg_pts_attr_req_funct_comp_evid_t tcg_pts_attr_req_funct_comp_evid_t; -typedef enum pts_attr_req_funct_comp_evid_flag_t pts_attr_req_funct_comp_evid_flag_t; - -#include "tcg_attr.h" -#include "pts/pts_funct_comp_name.h" -#include "pa_tnc/pa_tnc_attr.h" - -/** - * PTS Request Functional Component Evidence Flags - */ -enum pts_attr_req_funct_comp_evid_flag_t { - /** Transitive Trust Chain flag */ - PTS_REQ_FUNC_COMP_FLAG_TTC = (1<<7), - /** Verify Component flag */ - PTS_REQ_FUNC_COMP_FLAG_VER = (1<<6), - /** Current Evidence flag */ - PTS_REQ_FUNC_COMP_FLAG_CURR = (1<<5), - /** PCR Information flag */ - PTS_REQ_FUNC_COMP_FLAG_PCR = (1<<4), -}; - -/** - * Class implementing the TCG PTS Request Functional Component Evidence attribute - * - */ -struct tcg_pts_attr_req_funct_comp_evid_t { - - /** - * Public PA-TNC attribute interface - */ - pa_tnc_attr_t pa_tnc_attribute; - - /** - * Get flags for PTS Request Functional Component Evidence - * - * @return Set of flags - */ - pts_attr_req_funct_comp_evid_flag_t (*get_flags)(tcg_pts_attr_req_funct_comp_evid_t *this); - - /** - * Set flags for PTS Request Functional Component Evidence - * - * @param flags Set of flags - */ - void (*set_flags)(tcg_pts_attr_req_funct_comp_evid_t *this, - pts_attr_req_funct_comp_evid_flag_t flags); - - /** - * Get Sub-component Depth - * - * @return Sub-component Depth - */ - u_int32_t (*get_sub_component_depth)(tcg_pts_attr_req_funct_comp_evid_t *this); - - /** - * Get Component Functional Name Vendor ID - * - * @return Component Functional Name Vendor ID - */ - u_int32_t (*get_comp_funct_name_vendor_id)(tcg_pts_attr_req_funct_comp_evid_t *this); - - /** - * Get Family - * - * @return Functional Name Family - */ - u_int8_t (*get_family)(tcg_pts_attr_req_funct_comp_evid_t *this); - - /** - * Get Qualifier - * - * @return Functional Name Category Qualifier - */ - pts_qualifier_t (*get_qualifier)(tcg_pts_attr_req_funct_comp_evid_t *this); - - /** - * Set qualifier for Component Functional Name - * - * @param qualifier Functional Name Category Qualifier - */ - void (*set_qualifier)(tcg_pts_attr_req_funct_comp_evid_t *this, - pts_qualifier_t qualifier); - - /** - * Get Component Functional Name - * - * @return Component Functional Name - */ - pts_funct_comp_name_t (*get_comp_funct_name)(tcg_pts_attr_req_funct_comp_evid_t *this); - - - /** - * Set Component Functional Name - * - * @param name Component Functional Name - */ - void (*set_comp_funct_name)(tcg_pts_attr_req_funct_comp_evid_t *this, - pts_funct_comp_name_t name); - - -}; - -/** - * Creates an tcg_pts_attr_req_funct_comp_evid_t object - * - * @param flags Set of flags - * @param depth Sub-component Depth - * @param vendor_id Component Functional Name Vendor ID - * @param qualifier Functional Name Category Qualifier - * @param name Component Functional Name - */ -pa_tnc_attr_t* tcg_pts_attr_req_funct_comp_evid_create(pts_attr_req_funct_comp_evid_flag_t flags, - u_int32_t depth, u_int32_t vendor_id, - pts_qualifier_t qualifier, - pts_funct_comp_name_t name); - -/** - * Creates an tcg_pts_attr_req_funct_comp_evid_t object from received data - * - * @param value Unparsed attribute value - */ -pa_tnc_attr_t* tcg_pts_attr_req_funct_comp_evid_create_from_data(chunk_t value); - -#endif /** TCG_PTS_ATTR_REQ_FUNCT_COMP_EVID_H_ @}*/ diff --git a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c index 84b31724e..d2c197ac4 100644 --- a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c +++ b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c @@ -20,6 +20,8 @@ #include <bio/bio_reader.h> #include <debug.h> +#include <time.h> + typedef struct private_tcg_pts_attr_simple_comp_evid_t private_tcg_pts_attr_simple_comp_evid_t; /** @@ -29,37 +31,37 @@ typedef struct private_tcg_pts_attr_simple_comp_evid_t private_tcg_pts_attr_simp * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Flags | Sub-Component Depth | + * | Flags | Sub-Component Depth | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Specific Functional Component | + * | Specific Functional Component | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Specific Functional Component | + * | Specific Functional Component | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Measure. Type | Extended into PCR | + * | Measure. Type | Extended into PCR | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Hash Algorithm | PCR Transform | Reserved | + * | Hash Algorithm | PCR Transform | Reserved | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Measurement Date/Time | + * | Measurement Date/Time | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Measurement Date/Time | + * | Measurement Date/Time | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Measurement Date/Time | + * | Measurement Date/Time | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Measurement Date/Time | + * | Measurement Date/Time | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Measurement Date/Time | + * | Measurement Date/Time | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Optional Policy URI Length | Opt. Verification Policy URI ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Optional Verification Policy URI ~ + * ~ Optional Verification Policy URI ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Optional PCR Length | Optional PCR Before Value ~ + * | Optional PCR Length | Optional PCR Before Value ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Optional PCR Before Value (Variable Length) ~ + * ~ Optional PCR Before Value (Variable Length) ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Optional PCR After Value (Variable Length) ~ + * ~ Optional PCR After Value (Variable Length) ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Component Measurement (Variable Length) ~ + * ~ Component Measurement (Variable Length) ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ @@ -70,30 +72,22 @@ typedef struct private_tcg_pts_attr_simple_comp_evid_t private_tcg_pts_attr_simp * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Component Functional Name Vendor ID |Fam| Qualifier | + * | Component Functional Name Vendor ID |Fam| Qualifier | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Component Functional Name | + * | Component Functional Name | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ -/** - * Qualifier for Functional Component - * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification - * - * - * 0 1 2 3 4 5 - * +-+-+-+-+-+-+ - * |K|S| Type | - * +-+-+-+-+-+-+ - */ - - - #define PTS_SIMPLE_COMP_EVID_SIZE 40 -#define PTS_SIMPLE_COMP_EVID_MEASUREMENT_TIME_SIZE 20 +#define PTS_SIMPLE_COMP_EVID_MEAS_TIME_SIZE 20 #define PTS_SIMPLE_COMP_EVID_RESERVED 0x00 -#define PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM 0x00 +#define PTS_SIMPLE_COMP_EVID_FAMILY_MASK 0xC0 +#define PTS_SIMPLE_COMP_EVID_VALIDATION_MASK 0x60 +#define PTS_SIMPLE_COMP_EVID_MEAS_TYPE (1<<7) +#define PTS_SIMPLE_COMP_EVID_FLAG_PCR (1<<7) + +static char *utc_undefined_time_str = "0000-00-00T00:00:00Z"; /** * Private data of an tcg_pts_attr_simple_comp_evid_t object. @@ -126,80 +120,14 @@ struct private_tcg_pts_attr_simple_comp_evid_t { bool noskip_flag; /** - * Set of flags for Simple Component Evidence + * PTS Component Evidence */ - pts_attr_simple_comp_evid_flag_t flags; + pts_comp_evidence_t *evidence; /** - * Sub-component Depth - */ - u_int32_t depth; - - /** - * Component Functional Name Vendor ID - */ - u_int32_t comp_vendor_id; - - /** - * Functional Name Encoding Family - */ - u_int8_t family; - - /** - * Functional Name Category Qualifier - */ - pts_qualifier_t qualifier; - - /** - * Component Functional Name - */ - pts_funct_comp_name_t name; - - /** - * Measurement type - */ - u_int8_t measurement_type; - - /** - * Which PCR the functional component is extended into - */ - u_int32_t extended_pcr; - - /** - * Hash Algorithm + * Reference count */ - pts_meas_algorithms_t hash_algorithm; - - /** - * Transformation type for PCR - */ - pts_pcr_transform_t transformation; - - /** - * Measurement time - */ - chunk_t measurement_time; - - /** - * Optional Policy URI - */ - chunk_t policy_uri; - - /** - * Optional PCR before value - */ - chunk_t pcr_before; - - /** - * Optional PCR after value - */ - chunk_t pcr_after; - - /** - * Component Measurement - */ - chunk_t measurement; - + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -232,101 +160,157 @@ METHOD(pa_tnc_attr_t, set_noskip_flag,void, this->noskip_flag = noskip; } -METHOD(pa_tnc_attr_t, build, void, - private_tcg_pts_attr_simple_comp_evid_t *this) +/** + * Convert time_t to Simple Component Evidence UTS string format + */ +void measurement_time_to_utc(time_t measurement_time, chunk_t *utc_time) { - bio_writer_t *writer; - u_int8_t flags = 0; - u_int8_t qualifier = 0; - - writer = bio_writer_create(PTS_SIMPLE_COMP_EVID_SIZE); - - /* Determine the flags to set*/ - if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR) - { - flags += 128; - } - if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_NO_VER) - { - flags += 32; - } - else if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL) + struct tm t; + + if (measurement_time == UNDEFINED_TIME) { - flags += 64; + utc_time->ptr = utc_undefined_time_str; } - else if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS) + else { - flags += 96; + gmtime_r(&measurement_time, &t); + sprintf(utc_time->ptr, "%04d-%02d-%02dT%02d:%02d:%02dZ", + t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, + t.tm_hour, t.tm_min, t.tm_sec); } +} + +METHOD(pa_tnc_attr_t, build, void, + private_tcg_pts_attr_simple_comp_evid_t *this) +{ + bio_writer_t *writer; + bool has_pcr_info; + char utc_time_buf[25]; + u_int8_t flags; + u_int32_t depth, extended_pcr; + pts_comp_func_name_t *name; + pts_meas_algorithms_t hash_algorithm; + pts_pcr_transform_t transform; + pts_comp_evid_validation_t validation; + time_t measurement_time; + chunk_t measurement, utc_time, pcr_before, pcr_after, policy_uri; + + /* Extract parameters from comp_evidence_t object */ + name = this->evidence->get_comp_func_name(this->evidence, + &depth); + measurement = this->evidence->get_measurement(this->evidence, + &extended_pcr, &hash_algorithm, &transform, + &measurement_time); + has_pcr_info = this->evidence->get_pcr_info(this->evidence, + &pcr_before, &pcr_after); + validation = this->evidence->get_validation(this->evidence, + &policy_uri); - writer->write_uint8(writer, flags); - - writer->write_uint24 (writer, this->depth); - writer->write_uint24 (writer, this->comp_vendor_id); - - if (this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM) + /* Determine the flags to set*/ + flags = validation; + if (has_pcr_info) { - DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00"); + flags |= PTS_SIMPLE_COMP_EVID_FLAG_PCR; } + + utc_time = chunk_create(utc_time_buf, PTS_SIMPLE_COMP_EVID_MEAS_TIME_SIZE); + measurement_time_to_utc(measurement_time, &utc_time); + + writer = bio_writer_create(PTS_SIMPLE_COMP_EVID_SIZE); + + writer->write_uint8 (writer, flags); + writer->write_uint24(writer, depth); + writer->write_uint24(writer, name->get_vendor_id(name)); + writer->write_uint8 (writer, name->get_qualifier(name)); + writer->write_uint32(writer, name->get_name(name)); + writer->write_uint8 (writer, PTS_SIMPLE_COMP_EVID_MEAS_TYPE); + writer->write_uint24(writer, extended_pcr); + writer->write_uint16(writer, hash_algorithm); + writer->write_uint8 (writer, transform); + writer->write_uint8 (writer, PTS_SIMPLE_COMP_EVID_RESERVED); + writer->write_data (writer, utc_time); - qualifier += this->qualifier.type; - if (this->qualifier.kernel) + /* Optional fields */ + if (validation == PTS_COMP_EVID_VALIDATION_FAILED || + validation == PTS_COMP_EVID_VALIDATION_PASSED) { - qualifier += 16; + writer->write_uint16(writer, policy_uri.len); + writer->write_data (writer, policy_uri); } - if (this->qualifier.sub_component) + if (has_pcr_info) { - qualifier += 32; + writer->write_uint16(writer, pcr_before.len); + writer->write_data (writer, pcr_before); + writer->write_data (writer, pcr_after); } + + writer->write_data(writer, measurement); - /* Unknown or Wildcard should not be used for Qualification*/ - if (!qualifier || qualifier == 63) + this->value = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; +static const int tm_leap_1970 = 477; + +/** + * Convert Simple Component Evidence UTS string format to time_t + */ +bool measurement_time_from_utc(time_t *measurement_time, chunk_t utc_time) +{ + int tm_year, tm_mon, tm_day, tm_days, tm_hour, tm_min, tm_sec, tm_secs; + int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap; + + if (memeq(utc_undefined_time_str, utc_time.ptr, utc_time.len)) { - DBG1(DBG_TNC, "Unknown or Wildcard should not be used for" - " Functional Name Qualifier"); + *measurement_time = 0; + return TRUE; } - - writer->write_uint8 (writer, qualifier); - writer->write_uint32(writer, this->name); - - writer->write_uint8 (writer, (this->measurement_type << 7)); - writer->write_uint24(writer, this->extended_pcr); - writer->write_uint16(writer, this->hash_algorithm); - writer->write_uint8 (writer, this->transformation); - writer->write_data (writer, this->measurement_time); - - /* Optional fields */ - if (this->policy_uri.ptr && this->policy_uri.len > 0) + if (sscanf(utc_time.ptr, "%4d-%2d-%2dT%2d:%2d:%2dZ", + &tm_year, &tm_mon, &tm_day, &tm_hour, &tm_min, &tm_sec) != 6) { - writer->write_uint16(writer, this->policy_uri.len); - writer->write_data (writer, this->policy_uri); + return FALSE; } - if (this->pcr_before.ptr && this->pcr_after.ptr && - this->pcr_before.len == this->pcr_after.len && - this->pcr_before.len > 0 && this->pcr_after.len > 0) + + /* representation of months as 0..11 */ + tm_mon--; + + /* representation of days as 0..30 */ + tm_day--; + + /* number of leap years between last year and 1970? */ + tm_leap_4 = (tm_year - 1) / 4; + tm_leap_100 = tm_leap_4 / 25; + tm_leap_400 = tm_leap_100 / 4; + tm_leap = tm_leap_4 - tm_leap_100 + tm_leap_400 - tm_leap_1970; + + /* if date later then February, is the current year a leap year? */ + if (tm_mon > 1 && (tm_year % 4 == 0) && + (tm_year % 100 != 0 || tm_year % 400 == 0)) { - writer->write_uint16(writer, this->pcr_before.len); - writer->write_data (writer, this->pcr_before); - writer->write_data (writer, this->pcr_after); + tm_leap++; } - - writer->write_data (writer, this->measurement); - - this->value = chunk_clone(writer->get_buf(writer)); - writer->destroy(writer); + tm_days = 365 * (tm_year - 1970) + days[tm_mon] + tm_day + tm_leap; + tm_secs = 60 * (60 * (24 * tm_days + tm_hour) + tm_min) + tm_sec; + + *measurement_time = tm_secs; + return TRUE; } METHOD(pa_tnc_attr_t, process, status_t, private_tcg_pts_attr_simple_comp_evid_t *this, u_int32_t *offset) { bio_reader_t *reader; - u_int8_t flags; - u_int8_t fam_and_qualifier; - u_int8_t measurement_type; - u_int16_t algorithm; - u_int8_t transformation; - u_int32_t measurement_len; - + pts_comp_func_name_t *name; + u_int8_t flags, fam_and_qualifier, qualifier, reserved; + u_int8_t measurement_type, transform, validation; + u_int16_t hash_algorithm, len; + u_int32_t depth, vendor_id, comp_name, extended_pcr; + chunk_t measurement, utc_time, policy_uri, pcr_before, pcr_after; + time_t measurement_time; + bool has_pcr_info = FALSE, has_validation = FALSE; + status_t status = FAILED; + if (this->value.len < PTS_SIMPLE_COMP_EVID_SIZE) { DBG1(DBG_TNC, "insufficient data for Simple Component Evidence"); @@ -335,315 +319,144 @@ METHOD(pa_tnc_attr_t, process, status_t, } reader = bio_reader_create(this->value); - reader->read_uint8(reader, &flags); - - /* Determine the flags to set*/ - if ((flags >> 7) & 1) - { - this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_PCR; - } - if (!((flags >> 6) & 1) && !((flags >> 5) & 1)) - { - this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID; - } - else if (!((flags >> 6) & 1) && ((flags >> 5) & 1)) - { - this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_NO_VER; - } - else if (((flags >> 6) & 1) && !((flags >> 5) & 1)) - { - this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL; - } - else if (((flags >> 6) & 1) && ((flags >> 5) & 1)) - { - this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS; - } - - reader->read_uint24(reader, &this->depth); - reader->read_uint24(reader, &this->comp_vendor_id); - reader->read_uint8(reader, &fam_and_qualifier); - - if (((fam_and_qualifier >> 6) & 1) ) - { - this->family += 1; - } - if (((fam_and_qualifier >> 7) & 1) ) + reader->read_uint8 (reader, &flags); + reader->read_uint24(reader, &depth); + reader->read_uint24(reader, &vendor_id); + reader->read_uint8 (reader, &fam_and_qualifier); + reader->read_uint32(reader, &comp_name); + reader->read_uint8 (reader, &measurement_type); + reader->read_uint24(reader, &extended_pcr); + reader->read_uint16(reader, &hash_algorithm); + reader->read_uint8 (reader, &transform); + reader->read_uint8 (reader, &reserved); + reader->read_data (reader, PTS_SIMPLE_COMP_EVID_MEAS_TIME_SIZE, &utc_time); + + if (measurement_type != PTS_SIMPLE_COMP_EVID_MEAS_TYPE) { - this->family += 2; - } - - /* TODO: Generate an IF-M error attribute indicating */ - /* TCG_PTS_INVALID_NAME_FAM */ - //if (&this->comp_vendor_id==PEN_TCG && this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM) - //{ - // DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00"); - //} - - if (((fam_and_qualifier >> 5) & 1) ) - { - this->qualifier.kernel = true; + DBG1(DBG_TNC, "unsupported Measurement Type in " + "Simple Component Evidence"); + *offset = 12; + reader->destroy(reader); + return FAILED; } - if (((fam_and_qualifier >> 4) & 1) ) + if (!measurement_time_from_utc(&measurement_time, utc_time)) { - this->qualifier.sub_component = true; + DBG1(DBG_TNC, "invalid Measurement Time field in " + "Simple Component Evidence"); + *offset = 20; + reader->destroy(reader); + return FAILED; } - this->qualifier.type = ( fam_and_qualifier & 0xF ); - /* TODO: Check the type is defined in pts_attr_req_funct_comp_type_t */ + validation = flags & PTS_SIMPLE_COMP_EVID_VALIDATION_MASK; + qualifier = fam_and_qualifier & ~PTS_SIMPLE_COMP_EVID_FAMILY_MASK; - /* Unknown or Wildcard should not be used for Qualification*/ - if (!(fam_and_qualifier & 0x3F) || (fam_and_qualifier & 0x3F) == 0x3F) + /* Is optional Policy URI field included? */ + if (validation == PTS_COMP_EVID_VALIDATION_FAILED || + validation == PTS_COMP_EVID_VALIDATION_PASSED) { - DBG1(DBG_TNC, "Unknown or Wildcard should not be used for" - " Functional Name Qualifier"); + if (!reader->read_uint16(reader, &len)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence " + "Verification Policy URI Length"); + goto end; + } + if (!reader->read_data(reader, len, &policy_uri)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence " + "Verification Policy URI"); + goto end; + } + has_validation = TRUE; } - reader->read_uint32(reader, &this->name); - /* TODO: Check the name is defined in pts_funct_comp_name_t */ - - reader->read_uint8(reader, &measurement_type); - this->measurement_type = (measurement_type >> 7 ) & 1; - - reader->read_uint24(reader, &this->extended_pcr); - reader->read_uint16(reader, &algorithm); - this->hash_algorithm = algorithm; - - reader->read_uint8(reader, &transformation); - this->transformation = transformation; - /* TODO: Check the transformation is defined in pts_pcr_transform_t */ - - reader->read_data(reader, PTS_SIMPLE_COMP_EVID_MEASUREMENT_TIME_SIZE, - &this->measurement_time); - this->measurement_time = chunk_clone(this->measurement_time); - - /* Optional Policy URI field is included */ - if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL || - this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS) - { - u_int16_t policy_uri_len; - reader->read_uint16(reader, &policy_uri_len); - reader->read_data(reader, policy_uri_len, &this->policy_uri); - this->policy_uri = chunk_clone(this->policy_uri); - } - - /* Optional PCR value fields are included */ - if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR) + /* Are optional PCR value fields included? */ + if (flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR) { - u_int16_t pcr_value_len; - reader->read_uint16(reader, &pcr_value_len); - reader->read_data(reader, pcr_value_len, &this->pcr_before); - this->pcr_before = chunk_clone(this->pcr_before); - reader->read_data(reader, pcr_value_len, &this->pcr_after); - this->pcr_after = chunk_clone(this->pcr_after); + if (!reader->read_uint16(reader, &len)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence " + "PCR Value length"); + goto end; + } + if (!reader->read_data(reader, len, &pcr_before)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence " + "PCR Before Value"); + goto end; + } + if (!reader->read_data(reader, len, &pcr_after)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence " + "PCR After Value"); + goto end; + } + has_pcr_info = TRUE; } - - measurement_len = reader->remaining(reader); - reader->read_data(reader, measurement_len, &this->measurement); - this->measurement = chunk_clone(this->measurement); + /* Measurement field comes at the very end */ + reader->read_data(reader,reader->remaining(reader), &measurement); reader->destroy(reader); - return SUCCESS; -} - -METHOD(pa_tnc_attr_t, destroy, void, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - free(this->value.ptr); - free(this->measurement_time.ptr); - free(this->policy_uri.ptr); - free(this->pcr_before.ptr); - free(this->pcr_after.ptr); - free(this->measurement.ptr); - free(this); -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_flags, pts_attr_simple_comp_evid_flag_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->flags; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_flags, void, - private_tcg_pts_attr_simple_comp_evid_t *this, pts_attr_simple_comp_evid_flag_t flags) -{ - this->flags = flags; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_sub_component_depth, u_int32_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->depth; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_spec_comp_funct_name_vendor_id, u_int32_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->comp_vendor_id; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_family, u_int8_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->family; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_qualifier, pts_qualifier_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->qualifier; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_qualifier, void, - private_tcg_pts_attr_simple_comp_evid_t *this, - pts_qualifier_t qualifier) -{ - this->qualifier = qualifier; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_comp_funct_name, pts_funct_comp_name_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->name; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_comp_funct_name, void, - private_tcg_pts_attr_simple_comp_evid_t *this, pts_funct_comp_name_t name) -{ - this->name = name; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_measurement_type, u_int8_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->measurement_type; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_extended_pcr, u_int32_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->extended_pcr; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_extended_pcr, void, - private_tcg_pts_attr_simple_comp_evid_t *this, u_int32_t extended_pcr) -{ - this->extended_pcr = extended_pcr; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_hash_algorithm, pts_meas_algorithms_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->hash_algorithm; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_hash_algorithm, void, - private_tcg_pts_attr_simple_comp_evid_t *this, - pts_meas_algorithms_t hash_algorithm) -{ - this->hash_algorithm = hash_algorithm; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_trans, pts_pcr_transform_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->transformation; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_pcr_trans, void, - private_tcg_pts_attr_simple_comp_evid_t *this, pts_pcr_transform_t transformation) -{ - this->transformation = transformation; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, get_measurement_time, chunk_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->measurement_time; -} -METHOD(tcg_pts_attr_simple_comp_evid_t, set_measurement_time, void, - private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t measurement_time) -{ - this->measurement_time = measurement_time; -} + /* Create Component Functional Name object */ + name = pts_comp_func_name_create(vendor_id, comp_name, qualifier); -METHOD(tcg_pts_attr_simple_comp_evid_t, get_policy_uri, chunk_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->policy_uri; -} + /* Create Component Evidence object */ + measurement = chunk_clone(measurement); + this->evidence = pts_comp_evidence_create(name, depth, extended_pcr, + hash_algorithm, transform, + measurement_time, measurement); -METHOD(tcg_pts_attr_simple_comp_evid_t, set_policy_uri, void, - private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t policy_uri) -{ - this->policy_uri = policy_uri; -} + /* Add options */ + if (has_validation) + { + policy_uri = chunk_clone(policy_uri); + this->evidence->set_validation(this->evidence, validation, policy_uri); + } + if (has_pcr_info) + { + pcr_before = chunk_clone(pcr_before); + pcr_after = chunk_clone(pcr_after); + this->evidence->set_pcr_info(this->evidence, pcr_before, pcr_after); + } -METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_before_value, chunk_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->pcr_before; -} + return SUCCESS; -METHOD(tcg_pts_attr_simple_comp_evid_t, set_pcr_before_value, void, - private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t pcr_before) -{ - this->pcr_before = pcr_before; +end: + reader->destroy(reader); + return status; } -METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_after_value, chunk_t, +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, private_tcg_pts_attr_simple_comp_evid_t *this) { - return this->pcr_after; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_pcr_after_value, void, - private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t pcr_after) -{ - this->pcr_after = pcr_after; + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; } -METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_len, u_int16_t, +METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_simple_comp_evid_t *this) { - if (this->pcr_before.ptr && this->pcr_after.ptr && - this->pcr_before.len == this->pcr_after.len && - this->pcr_before.len > 0 && this->pcr_after.len > 0) + if (ref_put(&this->ref)) { - return this->pcr_before.len; + this->evidence->destroy(this->evidence); + free(this->value.ptr); + free(this); } - return 0; } -METHOD(tcg_pts_attr_simple_comp_evid_t, get_comp_measurement, chunk_t, +METHOD(tcg_pts_attr_simple_comp_evid_t, get_comp_evidence, pts_comp_evidence_t*, private_tcg_pts_attr_simple_comp_evid_t *this) { - return this->measurement; -} - -METHOD(tcg_pts_attr_simple_comp_evid_t, set_comp_measurement, void, - private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t measurement) -{ - this->measurement = measurement; + return this->evidence; } /** * Described in header. */ -pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create( - pts_attr_simple_comp_evid_flag_t flags, - u_int32_t depth, u_int32_t vendor_id, - pts_qualifier_t qualifier, - pts_funct_comp_name_t name, - u_int32_t extended_pcr, - pts_meas_algorithms_t hash_algorithm, - pts_pcr_transform_t transformation, - chunk_t measurement_time, - chunk_t policy_uri, - chunk_t pcr_before, chunk_t pcr_after, - chunk_t measurement) +pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create(pts_comp_evidence_t *evid) { private_tcg_pts_attr_simple_comp_evid_t *this; - + INIT(this, .public = { .pa_tnc_attribute = { @@ -654,52 +467,15 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create( .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, - .get_flags= _get_flags, - .set_flags= _set_flags, - .get_sub_component_depth = _get_sub_component_depth, - .get_spec_comp_funct_name_vendor_id = _get_spec_comp_funct_name_vendor_id, - .get_family = _get_family, - .get_qualifier = _get_qualifier, - .set_qualifier = _set_qualifier, - .get_comp_funct_name = _get_comp_funct_name, - .set_comp_funct_name = _set_comp_funct_name, - .get_measurement_type = _get_measurement_type, - .get_extended_pcr = _get_extended_pcr, - .set_extended_pcr = _set_extended_pcr, - .get_hash_algorithm = _get_hash_algorithm, - .set_hash_algorithm = _set_hash_algorithm, - .get_pcr_trans = _get_pcr_trans, - .set_pcr_trans = _set_pcr_trans, - .get_measurement_time = _get_measurement_time, - .set_measurement_time = _set_measurement_time, - .get_policy_uri = _get_policy_uri, - .set_policy_uri = _set_policy_uri, - .get_pcr_before_value = _get_pcr_before_value, - .set_pcr_before_value = _set_pcr_before_value, - .get_pcr_after_value = _get_pcr_after_value, - .set_pcr_after_value = _set_pcr_after_value, - .get_pcr_len = _get_pcr_len, - .get_comp_measurement = _get_comp_measurement, - .set_comp_measurement = _set_comp_measurement, + .get_comp_evidence = _get_comp_evidence, }, .vendor_id = PEN_TCG, .type = TCG_PTS_SIMPLE_COMP_EVID, - .flags = flags, - .depth = depth, - .comp_vendor_id = vendor_id, - .family = PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM, - .qualifier = qualifier, - .name = name, - .extended_pcr = extended_pcr, - .hash_algorithm = hash_algorithm, - .transformation = transformation, - .measurement_time = measurement_time, - .policy_uri = policy_uri, - .pcr_before = pcr_before, - .pcr_after = pcr_after, - .measurement = measurement, + .evidence = evid, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -723,39 +499,15 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, - .get_flags= _get_flags, - .set_flags= _set_flags, - .get_sub_component_depth = _get_sub_component_depth, - .get_spec_comp_funct_name_vendor_id = _get_spec_comp_funct_name_vendor_id, - .get_family = _get_family, - .get_qualifier = _get_qualifier, - .set_qualifier = _set_qualifier, - .get_comp_funct_name = _get_comp_funct_name, - .set_comp_funct_name = _set_comp_funct_name, - .get_measurement_type = _get_measurement_type, - .get_extended_pcr = _get_extended_pcr, - .set_extended_pcr = _set_extended_pcr, - .get_hash_algorithm = _get_hash_algorithm, - .set_hash_algorithm = _set_hash_algorithm, - .get_pcr_trans = _get_pcr_trans, - .set_pcr_trans = _set_pcr_trans, - .get_measurement_time = _get_measurement_time, - .set_measurement_time = _set_measurement_time, - .get_policy_uri = _get_policy_uri, - .set_policy_uri = _set_policy_uri, - .get_pcr_before_value = _get_pcr_before_value, - .set_pcr_before_value = _set_pcr_before_value, - .get_pcr_after_value = _get_pcr_after_value, - .set_pcr_after_value = _set_pcr_after_value, - .get_pcr_len = _get_pcr_len, - .get_comp_measurement = _get_comp_measurement, - .set_comp_measurement = _set_comp_measurement, + .get_comp_evidence = _get_comp_evidence, }, .vendor_id = PEN_TCG, .type = TCG_PTS_SIMPLE_COMP_EVID, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h index 5da20e96e..3a80904c8 100644 --- a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h +++ b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h @@ -22,45 +22,12 @@ #define TCG_PTS_ATTR_SIMPLE_COMP_EVID_H_ typedef struct tcg_pts_attr_simple_comp_evid_t tcg_pts_attr_simple_comp_evid_t; -typedef enum pts_attr_simple_comp_evid_flag_t pts_attr_simple_comp_evid_flag_t; -typedef enum pts_pcr_transform_t pts_pcr_transform_t; #include "tcg_attr.h" -#include "pts/pts_meas_algo.h" -#include "pts/pts_funct_comp_name.h" +#include "pts/components/pts_comp_evidence.h" #include "pa_tnc/pa_tnc_attr.h" /** - * PTS Simple Component Evidence Flags - */ -enum pts_attr_simple_comp_evid_flag_t { - /** PCR information fields inlcuded */ - PTS_SIMPLE_COMP_EVID_FLAG_PCR = 0, - /** No Validation was attempted */ - PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID = 1, - /** Attempted validation, unable to verify */ - PTS_SIMPLE_COMP_EVID_FLAG_NO_VER = 2, - /** Attempted validation, verification failed */ - PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL = 3, - /** Attempted validation, verification passed */ - PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS = 4, -}; - -/** - * PTS PCR Transformations - */ -enum pts_pcr_transform_t { - /** No Transformation */ - PTS_PCR_TRANSFORM_NO = 0, - /** Hash Value matched PCR size */ - PTS_PCR_TRANSFORM_MATCH = 1, - /** Hash value shorter than PCR size */ - PTS_PCR_TRANSFORM_SHORT = 2, - /** Hash value longer than PCR size */ - PTS_PCR_TRANSFORM_LONG = 3, -}; - -/** * Class implementing the TCG PTS Simple Component Evidence attribute * */ @@ -70,240 +37,22 @@ struct tcg_pts_attr_simple_comp_evid_t { * Public PA-TNC attribute interface */ pa_tnc_attr_t pa_tnc_attribute; - - /** - * Get flags for PTS Simple Component Evidence - * - * @return Set of flags - */ - pts_attr_simple_comp_evid_flag_t (*get_flags)(tcg_pts_attr_simple_comp_evid_t *this); /** - * Set flags for PTS Simple Component Evidence - * - * @param flags Set of flags - */ - void (*set_flags)(tcg_pts_attr_simple_comp_evid_t *this, - pts_attr_simple_comp_evid_flag_t flags); - - /** - * Get Sub-component Depth - * - * @return Sub-component Depth - */ - u_int32_t (*get_sub_component_depth)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Get Specific Component Functional Name Vendor ID - * - * @return Component Functional Name Vendor ID - */ - u_int32_t (*get_spec_comp_funct_name_vendor_id)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Get Family - * - * @return Functional Name Family - */ - u_int8_t (*get_family)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Get Qualifier - * - * @return Functional Name Category Qualifier - */ - pts_qualifier_t (*get_qualifier)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set qualifier for Component Functional Name - * - * @param qualifier Functional Name Category Qualifier - */ - void (*set_qualifier)(tcg_pts_attr_simple_comp_evid_t *this, - pts_qualifier_t qualifier); - - /** - * Get Special Component Functional Name - * - * @return Component Functional Name - */ - pts_funct_comp_name_t (*get_comp_funct_name)(tcg_pts_attr_simple_comp_evid_t *this); - - - /** - * Set Component Functional Name - * - * @param name Component Functional Name - */ - void (*set_comp_funct_name)(tcg_pts_attr_simple_comp_evid_t *this, - pts_funct_comp_name_t name); - - /** - * Get Measurement Type - * - * @return Measurement Type - */ - u_int8_t (*get_measurement_type)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Get which PCR the functional component is extended into - * - * @return Number of PCR - */ - u_int32_t (*get_extended_pcr)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set which PCR the functional component is extended into - * - * @param pcr_number Number of PCR - */ - void (*set_extended_pcr)(tcg_pts_attr_simple_comp_evid_t *this, - u_int32_t extended_pcr); - - /** - * Get Hash Algorithm - * - * @return Hash Algorithm - */ - pts_meas_algorithms_t (*get_hash_algorithm)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set Hash Algorithm - * - * @param hash_algorithm Hash Algorithm - */ - void (*set_hash_algorithm)(tcg_pts_attr_simple_comp_evid_t *this, - pts_meas_algorithms_t hash_algorithm); - - /** - * Get PCR Transformation - * - * @return Transformation type of PCR - */ - pts_pcr_transform_t (*get_pcr_trans)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set PCR Transformation - * - * @param transformation Transformation type of PCR - */ - void (*set_pcr_trans)(tcg_pts_attr_simple_comp_evid_t *this, - pts_pcr_transform_t transformation); - - /** - * Get Measurement Time - * - * @return Measurement time - */ - chunk_t (*get_measurement_time)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set Measurement Time - * - * @param time Measurement time - */ - void (*set_measurement_time)(tcg_pts_attr_simple_comp_evid_t *this, - chunk_t time); - - /** - * Get Optional Policy URI - * - * @return Policy URI - */ - chunk_t (*get_policy_uri)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set Optional Policy URI - * - * @param policy_uri Policy URI - */ - void (*set_policy_uri)(tcg_pts_attr_simple_comp_evid_t *this, - chunk_t policy_uri); - - /** - * Get Optional PCR Length - * - * @return Length of PCR before/after values - */ - u_int16_t (*get_pcr_len)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Get Optional PCR before value - * - * @return PCR before value - */ - chunk_t (*get_pcr_before_value)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set Optional PCR before value - * - * @param pcr_before PCR before value - */ - void (*set_pcr_before_value)(tcg_pts_attr_simple_comp_evid_t *this, - chunk_t pcr_before); - - /** - * Get Optional PCR after value - * - * @return PCR after value - */ - chunk_t (*get_pcr_after_value)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set Optional PCR after value - * - * @param pcr_after PCR after value - */ - void (*set_pcr_after_value)(tcg_pts_attr_simple_comp_evid_t *this, - chunk_t pcr_after); - - /** - * Get Component Measurement - * - * @return Component Measurement Hash - */ - chunk_t (*get_comp_measurement)(tcg_pts_attr_simple_comp_evid_t *this); - - /** - * Set Component Measurement + * Get Component Evidence * - * @param measurement Component Measurement Hash + * @return Component Evidence */ - void (*set_comp_measurement)(tcg_pts_attr_simple_comp_evid_t *this, - chunk_t measurement); + pts_comp_evidence_t* (*get_comp_evidence)(tcg_pts_attr_simple_comp_evid_t *this); }; /** * Creates an tcg_pts_attr_simple_comp_evid_t object * - * @param flags Set of flags - * @param depth Sub-component Depth - * @param vendor_id Component Functional Name Vendor ID - * @param qualifier Functional Name Category Qualifier - * @param name Component Functional Name - * @param extended_pcr Which PCR the functional component is extended into - * @param hash_algorithm Hash Algorithm - * @param transformation Transformation type for PCR - * @param measurement_time Measurement time - * @param policy_uri Optional Policy URI - * @param pcr_before Optional PCR before value - * @param pcr_after Optional PCR after value - * @param measurement Component Measurement + * @param evid Component Evidence */ -pa_tnc_attr_t* tcg_pts_attr_simple_comp_evid_create(pts_attr_simple_comp_evid_flag_t flags, - u_int32_t depth, - u_int32_t vendor_id, - pts_qualifier_t qualifier, - pts_funct_comp_name_t name, - u_int32_t extended_pcr, - pts_meas_algorithms_t hash_algorithm, - pts_pcr_transform_t transformation, - chunk_t measurement_time, - chunk_t policy_uri, - chunk_t pcr_before, - chunk_t pcr_after, - chunk_t measurement); +pa_tnc_attr_t* tcg_pts_attr_simple_comp_evid_create(pts_comp_evidence_t *evid); /** * Creates an tcg_pts_attr_simple_comp_evid_t object from received data diff --git a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c index fa2f6e5c6..27720d509 100644 --- a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c +++ b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c @@ -14,6 +14,7 @@ */ #include "tcg_pts_attr_simple_evid_final.h" +#include "pts/pts_simple_evid_final.h" #include <pa_tnc/pa_tnc_msg.h> #include <bio/bio_writer.h> @@ -29,23 +30,23 @@ typedef struct private_tcg_pts_attr_simple_evid_final_t private_tcg_pts_attr_sim * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Flags | Reserved | Optional Composite Hash Alg | + * | Flags | Reserved | Optional Composite Hash Alg | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Optional TPM PCR Composite Length | + * | Optional TPM PCR Composite Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Optional TPM PCR Composite (Variable Length) ~ + * ~ Optional TPM PCR Composite (Variable Length) ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Optional TPM Quote Signature Length | + * | Optional TPM Quote Signature Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Optional TPM Quote Signature (Variable Length) ~ + * ~ Optional TPM Quote Signature (Variable Length) ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Optional Evidence Signature (Variable Length) ~ + * ~ Optional Evidence Signature (Variable Length) ~ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#define PTS_SIMPLE_EVID_FINAL_SIZE 4 +#define PTS_SIMPLE_EVID_FINAL_SIZE 2 #define PTS_SIMPLE_EVID_FINAL_RESERVED 0x00 - +#define PTS_SIMPLE_EVID_FINAL_FLAG_MASK 0xC0 /** * Private data of an tcg_pts_attr_simple_evid_final_t object. */ @@ -75,11 +76,11 @@ struct private_tcg_pts_attr_simple_evid_final_t { * Noskip flag */ bool noskip_flag; - + /** * Set of flags for Simple Evidence Final */ - pts_simple_evid_final_flag_t flags; + u_int8_t flags; /** * Optional Composite Hash Algorithm @@ -94,13 +95,22 @@ struct private_tcg_pts_attr_simple_evid_final_t { /** * Optional TPM Quote Signature */ - chunk_t tpm_quote_sign; + chunk_t tpm_quote_sig; + + /** + * Is Evidence Signature included? + */ + bool has_evid_sig; /** * Optional Evidence Signature */ - chunk_t evid_sign; + chunk_t evid_sig; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -133,49 +143,62 @@ METHOD(pa_tnc_attr_t, set_noskip_flag,void, this->noskip_flag = noskip; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_simple_evid_final_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_tcg_pts_attr_simple_evid_final_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this->pcr_comp.ptr); + free(this->tpm_quote_sig.ptr); + free(this->evid_sig.ptr); + free(this); + } +} + METHOD(pa_tnc_attr_t, build, void, private_tcg_pts_attr_simple_evid_final_t *this) { bio_writer_t *writer; - u_int8_t flags = 0; - - writer = bio_writer_create(PTS_SIMPLE_EVID_FINAL_SIZE); + u_int8_t flags; - /* Determine the flags to set*/ - if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO) - { - flags += 64; - } - else if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2) - { - flags += 128; - } - else if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2_CAP_VER) - { - flags += 192; - } - if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_EVID) + flags = this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_MASK; + + if (this->has_evid_sig) { - flags += 32; + flags |= PTS_SIMPLE_EVID_FINAL_EVID_SIG; } + + writer = bio_writer_create(PTS_SIMPLE_EVID_FINAL_SIZE); writer->write_uint8 (writer, flags); writer->write_uint8 (writer, PTS_SIMPLE_EVID_FINAL_RESERVED); + + /** Optional Composite Hash Algorithm field is always present + * Field has value of all zeroes if not used. + * Implemented adhering the suggestion of Paul Sangster 28.Oct.2011 + */ writer->write_uint16(writer, this->comp_hash_algorithm); /* Optional fields */ - if (this->pcr_comp.ptr && this->pcr_comp.len > 0) + if (this->flags != PTS_SIMPLE_EVID_FINAL_NO) { writer->write_uint32 (writer, this->pcr_comp.len); writer->write_data (writer, this->pcr_comp); + + writer->write_uint32 (writer, this->tpm_quote_sig.len); + writer->write_data (writer, this->tpm_quote_sig); } - if (this->tpm_quote_sign.ptr && this->tpm_quote_sign.len > 0) - { - writer->write_uint32 (writer, this->tpm_quote_sign.len); - writer->write_data (writer, this->tpm_quote_sign); - } - if (this->evid_sign.ptr && this->evid_sign.len > 0) + + if (this->has_evid_sig) { - writer->write_data (writer, this->evid_sign); + writer->write_data (writer, this->evid_sig); } this->value = chunk_clone(writer->get_buf(writer)); @@ -186,9 +209,10 @@ METHOD(pa_tnc_attr_t, process, status_t, private_tcg_pts_attr_simple_evid_final_t *this, u_int32_t *offset) { bio_reader_t *reader; - u_int8_t flags; - u_int8_t reserved; + u_int8_t flags, reserved; u_int16_t algorithm; + u_int32_t pcr_comp_len, tpm_quote_sig_len, evid_sig_len; + status_t status = FAILED; if (this->value.len < PTS_SIMPLE_EVID_FINAL_SIZE) { @@ -199,157 +223,110 @@ METHOD(pa_tnc_attr_t, process, status_t, reader = bio_reader_create(this->value); reader->read_uint8(reader, &flags); - - /* Determine the flags to set*/ - if (!((flags >> 7) & 1) && !((flags >> 6) & 1)) - { - this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_NO; - } - else if (!((flags >> 7) & 1) && ((flags >> 6) & 1)) - { - this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO; - } - else if (((flags >> 7) & 1) && !((flags >> 6) & 1)) - { - this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2; - } - else if (((flags >> 7) & 1) && ((flags >> 6) & 1)) - { - this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2_CAP_VER; - } - if ((flags >> 5) & 1) - { - this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_EVID; - } - reader->read_uint8(reader, &reserved); + + this->flags = flags & PTS_SIMPLE_EVID_FINAL_FLAG_MASK; + + this->has_evid_sig = (flags & PTS_SIMPLE_EVID_FINAL_EVID_SIG) != 0; + + /** Optional Composite Hash Algorithm field is always present + * Field has value of all zeroes if not used. + * Implemented adhering the suggestion of Paul Sangster 28.Oct.2011 + */ + reader->read_uint16(reader, &algorithm); this->comp_hash_algorithm = algorithm; - /* Optional TPM PCR Composite field is included */ - if (!(this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_NO)) + /* Optional Composite Hash Algorithm and TPM PCR Composite fields */ + if (this->flags != PTS_SIMPLE_EVID_FINAL_NO) { - u_int32_t pcr_comp_len; - u_int32_t tpm_quote_sign_len; - reader->read_uint32(reader, &pcr_comp_len); - reader->read_data(reader, pcr_comp_len, &this->pcr_comp); + if (!reader->read_uint32(reader, &pcr_comp_len)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final " + "PCR Composite Length"); + goto end; + } + if (!reader->read_data(reader, pcr_comp_len, &this->pcr_comp)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final " + "PCR Composite"); + goto end; + } this->pcr_comp = chunk_clone(this->pcr_comp); - reader->read_uint32(reader, &tpm_quote_sign_len); - reader->read_data(reader, tpm_quote_sign_len, &this->tpm_quote_sign); - this->tpm_quote_sign = chunk_clone(this->tpm_quote_sign); + + if (!reader->read_uint32(reader, &tpm_quote_sig_len)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final " + "TPM Quote Singature Length"); + goto end; + } + if (!reader->read_data(reader, tpm_quote_sig_len, &this->tpm_quote_sig)) + { + DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final " + "TPM Quote Singature"); + goto end; + } + this->tpm_quote_sig = chunk_clone(this->tpm_quote_sig); } - /* Optional Evidence Signature field is included */ - if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_EVID) + /* Optional Evidence Signature field */ + if (this->has_evid_sig) { - u_int32_t evid_sign_len = reader->remaining(reader); - reader->read_data(reader, evid_sign_len, &this->evid_sign); - this->evid_sign = chunk_clone(this->evid_sign); + evid_sig_len = reader->remaining(reader); + reader->read_data(reader, evid_sig_len, &this->evid_sig); + this->evid_sig = chunk_clone(this->evid_sig); } reader->destroy(reader); return SUCCESS; -} - -METHOD(pa_tnc_attr_t, destroy, void, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - free(this->value.ptr); - free(this->pcr_comp.ptr); - free(this->tpm_quote_sign.ptr); - free(this->evid_sign.ptr); - free(this); -} - -METHOD(tcg_pts_attr_simple_evid_final_t, get_flags, pts_simple_evid_final_flag_t, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - return this->flags; -} - -METHOD(tcg_pts_attr_simple_evid_final_t, set_flags, void, - private_tcg_pts_attr_simple_evid_final_t *this, pts_simple_evid_final_flag_t flags) -{ - this->flags = flags; -} -METHOD(tcg_pts_attr_simple_evid_final_t, get_comp_hash_algorithm, pts_meas_algorithms_t, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - return this->comp_hash_algorithm; +end: + reader->destroy(reader); + return status; } -METHOD(tcg_pts_attr_simple_evid_final_t, set_comp_hash_algorithm, void, - private_tcg_pts_attr_simple_evid_final_t *this, pts_meas_algorithms_t comp_hash_algorithm) +METHOD(tcg_pts_attr_simple_evid_final_t, get_quote_info, u_int8_t, + private_tcg_pts_attr_simple_evid_final_t *this, + pts_meas_algorithms_t *comp_hash_algo, chunk_t *pcr_comp, chunk_t *tpm_quote_sig) { - this->comp_hash_algorithm = comp_hash_algorithm; -} - -METHOD(tcg_pts_attr_simple_evid_final_t, get_comp_pcr_len, u_int32_t, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - if (this->pcr_comp.ptr && this->pcr_comp.len > 0) + if (comp_hash_algo) { - return this->pcr_comp.len; + *comp_hash_algo = this->comp_hash_algorithm; } - return 0; -} - -METHOD(tcg_pts_attr_simple_evid_final_t, get_pcr_comp, chunk_t, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - return this->pcr_comp; -} - -METHOD(tcg_pts_attr_simple_evid_final_t, set_pcr_comp, void, - private_tcg_pts_attr_simple_evid_final_t *this, chunk_t pcr_comp) -{ - this->pcr_comp = pcr_comp; -} - -METHOD(tcg_pts_attr_simple_evid_final_t, get_tpm_quote_sign_len, u_int32_t, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - if (this->tpm_quote_sign.ptr && this->tpm_quote_sign.len > 0) + if (pcr_comp) { - return this->tpm_quote_sign.len; + *pcr_comp = this->pcr_comp; } - return 0; -} - -METHOD(tcg_pts_attr_simple_evid_final_t, get_tpm_quote_sign, chunk_t, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - return this->tpm_quote_sign; -} - -METHOD(tcg_pts_attr_simple_evid_final_t, set_tpm_quote_sign, void, - private_tcg_pts_attr_simple_evid_final_t *this, chunk_t tpm_quote_sign) -{ - this->tpm_quote_sign = tpm_quote_sign; + if (tpm_quote_sig) + { + *tpm_quote_sig = this->tpm_quote_sig; + } + return this->flags; } -METHOD(tcg_pts_attr_simple_evid_final_t, get_evid_sign, chunk_t, - private_tcg_pts_attr_simple_evid_final_t *this) +METHOD(tcg_pts_attr_simple_evid_final_t, get_evid_sig, bool, + private_tcg_pts_attr_simple_evid_final_t *this, chunk_t *evid_sig) { - return this->evid_sign; + if (evid_sig) + { + *evid_sig = this->evid_sig; + } + return this->has_evid_sig; } -METHOD(tcg_pts_attr_simple_evid_final_t, set_evid_sign, void, - private_tcg_pts_attr_simple_evid_final_t *this, chunk_t evid_sign) +METHOD(tcg_pts_attr_simple_evid_final_t, set_evid_sig, void, + private_tcg_pts_attr_simple_evid_final_t *this, chunk_t evid_sig) { - this->evid_sign = evid_sign; + this->evid_sig = evid_sig; + this->has_evid_sig = TRUE; } /** * Described in header. */ -pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create( - pts_simple_evid_final_flag_t flags, - pts_meas_algorithms_t comp_hash_algorithm, - chunk_t pcr_comp, - chunk_t tpm_quote_sign, - chunk_t evid_sign) +pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(u_int8_t flags, + pts_meas_algorithms_t comp_hash_algorithm, + chunk_t pcr_comp, chunk_t tpm_quote_sig) { private_tcg_pts_attr_simple_evid_final_t *this; @@ -363,28 +340,20 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create( .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, - .get_flags= _get_flags, - .set_flags= _set_flags, - .get_comp_hash_algorithm = _get_comp_hash_algorithm, - .set_comp_hash_algorithm = _set_comp_hash_algorithm, - .get_comp_pcr_len = _get_comp_pcr_len, - .get_pcr_comp = _get_pcr_comp, - .set_pcr_comp = _set_pcr_comp, - .get_tpm_quote_sign_len = _get_tpm_quote_sign_len, - .get_tpm_quote_sign = _get_tpm_quote_sign, - .set_tpm_quote_sign = _set_tpm_quote_sign, - .get_evid_sign = _get_evid_sign, - .set_evid_sign = _set_evid_sign, + .get_quote_info = _get_quote_info, + .get_evid_sig = _get_evid_sig, + .set_evid_sig = _set_evid_sig, }, .vendor_id = PEN_TCG, .type = TCG_PTS_SIMPLE_EVID_FINAL, .flags = flags, .comp_hash_algorithm = comp_hash_algorithm, .pcr_comp = pcr_comp, - .tpm_quote_sign = tpm_quote_sign, - .evid_sign = evid_sign, + .tpm_quote_sig = tpm_quote_sig, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -408,24 +377,17 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, - .get_flags= _get_flags, - .set_flags= _set_flags, - .get_comp_hash_algorithm = _get_comp_hash_algorithm, - .set_comp_hash_algorithm = _set_comp_hash_algorithm, - .get_comp_pcr_len = _get_comp_pcr_len, - .get_pcr_comp = _get_pcr_comp, - .set_pcr_comp = _set_pcr_comp, - .get_tpm_quote_sign_len = _get_tpm_quote_sign_len, - .get_tpm_quote_sign = _get_tpm_quote_sign, - .set_tpm_quote_sign = _set_tpm_quote_sign, - .get_evid_sign = _get_evid_sign, - .set_evid_sign = _set_evid_sign, + .get_quote_info = _get_quote_info, + .get_evid_sig = _get_evid_sig, + .set_evid_sig = _set_evid_sig, }, .vendor_id = PEN_TCG, .type = TCG_PTS_SIMPLE_EVID_FINAL, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h index 351981921..3d98bfce7 100644 --- a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h +++ b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h @@ -22,32 +22,12 @@ #define TCG_PTS_ATTR_SIMPLE_EVID_FINAL_H_ typedef struct tcg_pts_attr_simple_evid_final_t tcg_pts_attr_simple_evid_final_t; -typedef enum pts_simple_evid_final_flag_t pts_simple_evid_final_flag_t; #include "tcg_attr.h" #include "tcg_pts_attr_meas_algo.h" #include "pa_tnc/pa_tnc_attr.h" /** - * PTS Simple Evidence Final Flags - */ -enum pts_simple_evid_final_flag_t { - /** No Optional TPM PCR Composite nor Optional TPM Quote Signature fields included */ - PTS_SIMPLE_EVID_FINAL_FLAG_NO = 0, - /** Optional TPM PCR Composite and Optional TPM Quote Signature fields included */ - /** using TPM_QUOTE_INFO */ - PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO = 1, - /** Optional TPM PCR Composite and Optional TPM Quote Signature fields included */ - /** using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO was not appended */ - PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2 = 2, - /** Optional TPM PCR Composite and Optional TPM Quote Signature fields included */ - /** using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO was appended */ - PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2_CAP_VER = 3, - /** Optional Evidence Signature included */ - PTS_SIMPLE_EVID_FINAL_FLAG_EVID = 4, -}; - -/** * Class implementing the TCG PTS Simple Evidence Final attribute * */ @@ -57,112 +37,49 @@ struct tcg_pts_attr_simple_evid_final_t { * Public PA-TNC attribute interface */ pa_tnc_attr_t pa_tnc_attribute; - - /** - * Get flags for PTS Simple Evidence Final - * - * @return Set of flags - */ - pts_simple_evid_final_flag_t (*get_flags)(tcg_pts_attr_simple_evid_final_t *this); /** - * Set flags for PTS Simple Evidence Final - * - * @param flags Set of flags - */ - void (*set_flags)(tcg_pts_attr_simple_evid_final_t *this, - pts_simple_evid_final_flag_t flags); - - /** - * Get Optional Composite Hash Algorithm - * - * @return Composite Hash Algorithm - */ - pts_meas_algorithms_t (*get_comp_hash_algorithm)(tcg_pts_attr_simple_evid_final_t *this); - - /** - * Set Optional Composite Hash Algorithm + * Get Optional PCR Composite and TPM Quote Signature * - * @param hash_algorithm Composite Hash Algorithm + * @param comp_hash_algo Optional Composite Hash Algorithm + * @param pcr_comp Optional PCR Composite + * @param tpm_quote sig Optional TPM Quote Signature + * @return PTS_SIMPLE_EVID_FINAL flags */ - void (*set_comp_hash_algorithm)(tcg_pts_attr_simple_evid_final_t *this, - pts_meas_algorithms_t hash_algorithm); - - /** - * Get Optional TPM PCR Composite Length - * - * @return Length of Composite PCR Length - */ - u_int32_t (*get_comp_pcr_len)(tcg_pts_attr_simple_evid_final_t *this); - - /** - * Get Optional TPM PCR Composite - * - * @return PCR Composite - */ - chunk_t (*get_pcr_comp)(tcg_pts_attr_simple_evid_final_t *this); - - /** - * Set Optional TPM PCR Composite - * - * @param pcr_comp PCR Composite - */ - void (*set_pcr_comp)(tcg_pts_attr_simple_evid_final_t *this, - chunk_t pcr_comp); - - /** - * Get Optional TPM Quote Signature Length - * - * @return TPM Quote Signature Length - */ - u_int32_t (*get_tpm_quote_sign_len)(tcg_pts_attr_simple_evid_final_t *this); - - /** - * Get Optional TPM Quote Signature - * - * @return TPM Quote Signature - */ - chunk_t (*get_tpm_quote_sign)(tcg_pts_attr_simple_evid_final_t *this); - - /** - * Set Optional TPM Quote Signature - * - * @param tpm_quote_sign TPM Quote Signature - */ - void (*set_tpm_quote_sign)(tcg_pts_attr_simple_evid_final_t *this, - chunk_t tpm_quote_sign); + u_int8_t (*get_quote_info)(tcg_pts_attr_simple_evid_final_t *this, + pts_meas_algorithms_t *comp_hash_algo, + chunk_t *pcr_comp, chunk_t *tpm_quote_sig); /** * Get Optional Evidence Signature * - * @return Optional Evidence Signature + * @evid_sig Optional Evidence Signature + * @return TRUE if Evidence Signature is available */ - chunk_t (*get_evid_sign)(tcg_pts_attr_simple_evid_final_t *this); - + bool (*get_evid_sig)(tcg_pts_attr_simple_evid_final_t *this, chunk_t *evid_sig); + /** * Set Optional Evidence Signature * - * @param signature Optional Evidence Signature + * @evid_sig Optional Evidence Signature */ - void (*set_evid_sign)(tcg_pts_attr_simple_evid_final_t *this, - chunk_t signature); + void (*set_evid_sig)(tcg_pts_attr_simple_evid_final_t *this, chunk_t evid_sig); }; /** * Creates an tcg_pts_attr_simple_evid_final_t object - * + * * @param flags Set of flags * @param comp_hash_algorithm Composite Hash Algorithm * @param pcr_comp Optional TPM PCR Composite * @param tpm_quote_sign Optional TPM Quote Signature - * @param evid_sign Optional Evidence Signature */ -pa_tnc_attr_t* tcg_pts_attr_simple_evid_final_create(pts_simple_evid_final_flag_t flags, +pa_tnc_attr_t* tcg_pts_attr_simple_evid_final_create( + u_int8_t flags, pts_meas_algorithms_t comp_hash_algorithm, chunk_t pcr_comp, - chunk_t tpm_quote_sign, - chunk_t evid_sign); + chunk_t tpm_quote_sign); /** * Creates an tcg_pts_attr_simple_evid_final_t object from received data diff --git a/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c b/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c index a1e91cccf..944a12cc9 100644 --- a/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c +++ b/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c @@ -72,6 +72,11 @@ struct private_tcg_pts_attr_tpm_version_info_t { * TPM Version Information */ chunk_t tpm_version_info; + + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -135,12 +140,22 @@ METHOD(pa_tnc_attr_t, process, status_t, return SUCCESS; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_tpm_version_info_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_tpm_version_info_t *this) { - free(this->value.ptr); - free(this->tpm_version_info.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this->tpm_version_info.ptr); + free(this); + } } METHOD(tcg_pts_attr_tpm_version_info_t, get_tpm_version_info, chunk_t, @@ -173,6 +188,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create(chunk_t tpm_version_info) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_tpm_version_info = _get_tpm_version_info, @@ -180,7 +196,8 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create(chunk_t tpm_version_info) }, .vendor_id = PEN_TCG, .type = TCG_PTS_TPM_VERSION_INFO, - .tpm_version_info = tpm_version_info, + .tpm_version_info = chunk_clone(tpm_version_info), + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -204,6 +221,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_tpm_version_info = _get_tpm_version_info, @@ -212,6 +230,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create_from_data(chunk_t data) .vendor_id = PEN_TCG, .type = TCG_PTS_TPM_VERSION_INFO, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c b/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c index 0f644fdf9..a9f4a115d 100644 --- a/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c +++ b/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c @@ -67,6 +67,7 @@ typedef struct private_tcg_pts_attr_file_meta_t private_tcg_pts_attr_file_meta_t #define PTS_FILE_META_SIZE 8 #define PTS_FILE_MEAS_RESERVED 0x00 +#define PTS_FILE_METADATA_SIZE 52 /** * Private data of an tcg_pts_attr_file_meta_t object. @@ -103,6 +104,10 @@ struct private_tcg_pts_attr_file_meta_t { */ pts_file_meta_t *metadata; + /** + * Reference count + */ + refcount_t ref; }; METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, @@ -140,52 +145,29 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; enumerator_t *enumerator; + pts_file_metadata_t *entry; u_int64_t number_of_files; - char *filename; - u_int16_t meta_length; - pts_file_type_t type; - u_int64_t filesize; - time_t create_time; - time_t last_modify_time; - time_t last_access_time; - u_int64_t owner_id; - u_int64_t group_id; number_of_files = this->metadata->get_file_count(this->metadata); writer = bio_writer_create(PTS_FILE_META_SIZE); - /* Write the 64 bit integer field - number of files as two 32 bit parts */ - writer->write_uint32(writer, number_of_files >> 32); - writer->write_uint32(writer, number_of_files & 0xffffffff); + writer->write_uint64(writer, number_of_files); enumerator = this->metadata->create_enumerator(this->metadata); - while (enumerator->enumerate(enumerator, &filename, &meta_length, &type, - &filesize, &filesize, &create_time, &last_modify_time, &last_access_time, - &owner_id, &group_id)) + while (enumerator->enumerate(enumerator, &entry)) { - u_int64_t create_time64 = (u_int64_t)create_time; - u_int64_t modify_time64 = (u_int64_t)last_modify_time; - u_int64_t access_time64 = (u_int64_t)last_access_time; - - writer->write_uint16(writer, PTS_FILE_METADATA_SIZE + strlen(filename)); - writer->write_uint8 (writer, type); + writer->write_uint16(writer, PTS_FILE_METADATA_SIZE + + strlen(entry->filename)); + writer->write_uint8 (writer, entry->type); writer->write_uint8 (writer, PTS_FILE_MEAS_RESERVED); - - /* Write the 64 bit integer fields as two 32 bit parts */ - writer->write_uint32(writer, filesize >> 32); - writer->write_uint32(writer, filesize & 0xffffffff); - writer->write_uint32(writer, create_time64 >> 32); - writer->write_uint32(writer, create_time64 & 0xffffffff); - writer->write_uint32(writer, modify_time64 >> 32); - writer->write_uint32(writer, modify_time64 & 0xffffffff); - writer->write_uint32(writer, access_time64 >> 32); - writer->write_uint32(writer, access_time64 & 0xffffffff); - writer->write_uint32(writer, owner_id >> 32); - writer->write_uint32(writer, owner_id & 0xffffffff); - writer->write_uint32(writer, group_id >> 32); - writer->write_uint32(writer, group_id & 0xffffffff); - - writer->write_data (writer, chunk_create(filename, strlen(filename))); + writer->write_uint64(writer, entry->filesize); + writer->write_uint64(writer, entry->created); + writer->write_uint64(writer, entry->modified); + writer->write_uint64(writer, entry->accessed); + writer->write_uint64(writer, entry->owner); + writer->write_uint64(writer, entry->group); + writer->write_data (writer, chunk_create(entry->filename, + strlen(entry->filename))); } enumerator->destroy(enumerator); @@ -197,36 +179,12 @@ METHOD(pa_tnc_attr_t, process, status_t, private_tcg_pts_attr_file_meta_t *this, u_int32_t *offset) { bio_reader_t *reader; - int number_of_files; - u_int32_t number_of_files32; - - u_int16_t meta_length; - pts_file_type_t type; - u_int8_t type8; - u_int8_t reserved; - - int filesize; - u_int32_t filesize32; - - int create_time; - u_int32_t create_time32; - time_t create_time_t; - int modify_time; - u_int32_t modify_time32; - time_t modify_time_t; - int access_time; - u_int32_t access_time32; - time_t access_time_t; - - int owner_id; - u_int32_t owner_id32; - - int group_id; - u_int32_t group_id32; - - size_t len; + pts_file_metadata_t *entry; + u_int8_t type, reserved; + u_int16_t len; + u_int64_t number_of_files, filesize, created, modified, accessed; + u_int64_t owner, group; chunk_t filename; - char buf[BUF_LEN]; status_t status = FAILED; if (this->value.len < PTS_FILE_META_SIZE) @@ -236,124 +194,76 @@ METHOD(pa_tnc_attr_t, process, status_t, return FAILED; } reader = bio_reader_create(this->value); + reader->read_uint64(reader, &number_of_files); - reader->read_uint32(reader, &number_of_files32); - number_of_files = (sizeof(number_of_files) > 4) ? number_of_files32 << 32 : 0; - reader->read_uint32(reader, &number_of_files32); - number_of_files += number_of_files32; - this->metadata = pts_file_meta_create(); while (number_of_files--) { - if (!reader->read_uint16(reader, &meta_length)) + if (!reader->read_uint16(reader, &len)) { DBG1(DBG_TNC, "insufficient data for PTS file metadata length"); goto end; } - if (!reader->read_uint8 (reader, &type8)) + if (!reader->read_uint8(reader, &type)) { DBG1(DBG_TNC, "insufficient data for file type"); goto end; } - type = (pts_file_type_t)type8; - if (!reader->read_uint8 (reader, &reserved)) + if (!reader->read_uint8(reader, &reserved)) { DBG1(DBG_TNC, "insufficient data for reserved field"); goto end; } - if (!reader->read_uint32(reader, &filesize32)) - { - DBG1(DBG_TNC, "insufficient data for file size"); - goto end; - } - filesize = (sizeof(filesize) > 4) ? filesize32 << 32 : 0; - if (!reader->read_uint32(reader, &filesize32)) - { - DBG1(DBG_TNC, "insufficient data for file size"); - goto end; - } - filesize += filesize32; - - if (!reader->read_uint32(reader, &create_time32)) - { - DBG1(DBG_TNC, "insufficient data for file size"); - goto end; - } - create_time = (sizeof(create_time) > 4) ? create_time32 << 32 : 0; - if (!reader->read_uint32(reader, &create_time32)) - { - DBG1(DBG_TNC, "insufficient data for file size"); - goto end; - } - create_time += create_time32; - create_time_t = (time_t)create_time; - - if (!reader->read_uint32(reader, &modify_time32)) + if (!reader->read_uint64(reader, &filesize)) { DBG1(DBG_TNC, "insufficient data for file size"); goto end; } - modify_time = (sizeof(modify_time) > 4) ? modify_time32 << 32 : 0; - if (!reader->read_uint32(reader, &modify_time32)) + if (!reader->read_uint64(reader, &created)) { - DBG1(DBG_TNC, "insufficient data for file size"); + DBG1(DBG_TNC, "insufficient data for file create time"); goto end; } - modify_time += modify_time32; - modify_time_t = (time_t)modify_time; - - if (!reader->read_uint32(reader, &access_time32)) + if (!reader->read_uint64(reader, &modified)) { - DBG1(DBG_TNC, "insufficient data for file size"); + DBG1(DBG_TNC, "insufficient data for last modify time"); goto end; } - access_time = (sizeof(access_time) > 4) ? access_time32 << 32 : 0; - if (!reader->read_uint32(reader, &access_time32)) + if (!reader->read_uint64(reader, &accessed)) { - DBG1(DBG_TNC, "insufficient data for file size"); + DBG1(DBG_TNC, "insufficient data for last access time"); goto end; } - access_time += access_time32; - access_time_t = (time_t)access_time; - - if (!reader->read_uint32(reader, &owner_id32)) + if (!reader->read_uint64(reader, &owner)) { - DBG1(DBG_TNC, "insufficient data for file size"); + DBG1(DBG_TNC, "insufficient data for owner id"); goto end; } - owner_id = (sizeof(owner_id) > 4) ? owner_id32 << 32 : 0; - if (!reader->read_uint32(reader, &owner_id32)) + if (!reader->read_uint64(reader, &group)) { - DBG1(DBG_TNC, "insufficient data for file size"); + DBG1(DBG_TNC, "insufficient data for group id"); goto end; } - owner_id += owner_id32; - - if (!reader->read_uint32(reader, &group_id32)) - { - DBG1(DBG_TNC, "insufficient data for file size"); - goto end; - } - group_id = (sizeof(group_id) > 4) ? group_id32 << 32 : 0; - if (!reader->read_uint32(reader, &group_id32)) - { - DBG1(DBG_TNC, "insufficient data for file size"); - goto end; - } - group_id += group_id32; - - if (!reader->read_data(reader, meta_length - PTS_FILE_METADATA_SIZE, &filename)) + if (!reader->read_data(reader, len - PTS_FILE_METADATA_SIZE, &filename)) { DBG1(DBG_TNC, "insufficient data for filename"); goto end; } - len = min(filename.len, BUF_LEN-1); - memcpy(buf, filename.ptr, len); - buf[len] = '\0'; - this->metadata->add(this->metadata, buf, type, filesize, create_time_t, - modify_time_t, access_time_t, owner_id, group_id); + entry = malloc_thing(pts_file_metadata_t); + entry->type = type; + entry->filesize = filesize; + entry->created = created; + entry->modified = modified; + entry->accessed = accessed; + entry->owner = owner; + entry->group = group; + entry->filename = malloc(filename.len + 1); + entry->filename[filename.len] = '\0'; + memcpy(entry->filename, filename.ptr, filename.len); + + this->metadata->add(this->metadata, entry); } status = SUCCESS; @@ -362,12 +272,22 @@ end: return status; } +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_pts_attr_file_meta_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + METHOD(pa_tnc_attr_t, destroy, void, private_tcg_pts_attr_file_meta_t *this) { - this->metadata->destroy(this->metadata); - free(this->value.ptr); - free(this); + if (ref_put(&this->ref)) + { + this->metadata->destroy(this->metadata); + free(this->value.ptr); + free(this); + } } METHOD(tcg_pts_attr_file_meta_t, get_metadata, pts_file_meta_t*, @@ -393,6 +313,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create(pts_file_meta_t *metadata) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_metadata = _get_metadata, @@ -400,6 +321,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create(pts_file_meta_t *metadata) .vendor_id = PEN_TCG, .type = TCG_PTS_UNIX_FILE_META, .metadata = metadata, + .ref = 1, ); return &this->public.pa_tnc_attribute; @@ -423,6 +345,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create_from_data(chunk_t data) .set_noskip_flag = _set_noskip_flag, .build = _build, .process = _process, + .get_ref = _get_ref, .destroy = _destroy, }, .get_metadata = _get_metadata, @@ -430,6 +353,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create_from_data(chunk_t data) .vendor_id = PEN_TCG, .type = TCG_PTS_UNIX_FILE_META, .value = chunk_clone(data), + .ref = 1, ); return &this->public.pa_tnc_attribute; diff --git a/src/libradius/Makefile.am b/src/libradius/Makefile.am new file mode 100644 index 000000000..5672f7b84 --- /dev/null +++ b/src/libradius/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +ipseclib_LTLIBRARIES = libradius.la +libradius_la_SOURCES = \ + radius_message.h radius_message.c \ + radius_socket.h radius_socket.c \ + radius_client.h radius_client.c \ + radius_config.h radius_config.c \ + radius_mppe.h + diff --git a/src/libcharon/plugins/eap_radius/radius_client.c b/src/libradius/radius_client.c index 245308e59..acdac78c9 100644 --- a/src/libcharon/plugins/eap_radius/radius_client.c +++ b/src/libradius/radius_client.c @@ -14,14 +14,12 @@ */ #include "radius_client.h" - -#include "eap_radius_plugin.h" -#include "radius_server.h" +#include "radius_config.h" #include <unistd.h> #include <errno.h> -#include <daemon.h> +#include <debug.h> #include <utils/host.h> #include <utils/linked_list.h> #include <threading/condvar.h> @@ -40,9 +38,9 @@ struct private_radius_client_t { radius_client_t public; /** - * Selected RADIUS server + * Selected RADIUS server configuration */ - radius_server_t *server; + radius_config_t *config; /** * RADIUS servers State attribute @@ -86,37 +84,41 @@ METHOD(radius_client_t, request, radius_message_t*, char virtual[] = {0x00,0x00,0x00,0x05}; radius_socket_t *socket; radius_message_t *res; + chunk_t data; /* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */ req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual))); /* add our NAS-Identifier */ req->add(req, RAT_NAS_IDENTIFIER, - this->server->get_nas_identifier(this->server)); + this->config->get_nas_identifier(this->config)); /* add State attribute, if server sent one */ if (this->state.ptr) { req->add(req, RAT_STATE, this->state); } - socket = this->server->get_socket(this->server); + socket = this->config->get_socket(this->config); DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names, - req->get_code(req), this->server->get_name(this->server)); + req->get_code(req), this->config->get_name(this->config)); + res = socket->request(socket, req); if (res) { DBG1(DBG_CFG, "received RADIUS %N from server '%s'", radius_message_code_names, res->get_code(res), - this->server->get_name(this->server)); + this->config->get_name(this->config)); + data = res->get_encoding(res); + DBG3(DBG_CFG, "%B", &data); + save_state(this, res); if (res->get_code(res) == RMC_ACCESS_ACCEPT) { chunk_clear(&this->msk); this->msk = socket->decrypt_msk(socket, req, res); } - this->server->put_socket(this->server, socket, TRUE); + this->config->put_socket(this->config, socket, TRUE); return res; } - this->server->put_socket(this->server, socket, FALSE); - charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING); + this->config->put_socket(this->config, socket, FALSE); return NULL; } @@ -129,7 +131,7 @@ METHOD(radius_client_t, get_msk, chunk_t, METHOD(radius_client_t, destroy, void, private_radius_client_t *this) { - this->server->destroy(this->server); + this->config->destroy(this->config); chunk_clear(&this->msk); free(this->state.ptr); free(this); @@ -138,12 +140,9 @@ METHOD(radius_client_t, destroy, void, /** * See header */ -radius_client_t *radius_client_create() +radius_client_t *radius_client_create(radius_config_t *config) { private_radius_client_t *this; - enumerator_t *enumerator; - radius_server_t *server; - int current, best = -1; INIT(this, .public = { @@ -151,36 +150,8 @@ radius_client_t *radius_client_create() .get_msk = _get_msk, .destroy = _destroy, }, + .config = config, ); - enumerator = eap_radius_create_server_enumerator(); - while (enumerator->enumerate(enumerator, &server)) - { - current = server->get_preference(server); - if (current > best || - /* for two with equal preference, 50-50 chance */ - (current == best && random() % 2 == 0)) - { - DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d", - server->get_name(server), current); - best = current; - DESTROY_IF(this->server); - this->server = server->get_ref(server); - } - else - { - DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d", - server->get_name(server), current); - } - } - enumerator->destroy(enumerator); - - if (!this->server) - { - free(this); - return NULL; - } - return &this->public; } - diff --git a/src/libcharon/plugins/eap_radius/radius_client.h b/src/libradius/radius_client.h index e4f3a7222..cf5f79b6c 100644 --- a/src/libcharon/plugins/eap_radius/radius_client.h +++ b/src/libradius/radius_client.h @@ -15,13 +15,14 @@ /** * @defgroup radius_client radius_client - * @{ @ingroup eap_radius + * @{ @ingroup libradius */ #ifndef RADIUS_CLIENT_H_ #define RADIUS_CLIENT_H_ #include "radius_message.h" +#include "radius_config.h" typedef struct radius_client_t radius_client_t; @@ -59,8 +60,9 @@ struct radius_client_t { /** * Create a RADIUS client. * + * @param config reference to a server configuration, gets owned * @return radius_client_t object */ -radius_client_t *radius_client_create(); +radius_client_t *radius_client_create(radius_config_t *config); #endif /** RADIUS_CLIENT_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/radius_server.c b/src/libradius/radius_config.c index 3baf39807..6e3394bb0 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.c +++ b/src/libradius/radius_config.c @@ -13,23 +13,23 @@ * for more details. */ -#include "radius_server.h" +#include "radius_config.h" #include <threading/mutex.h> #include <threading/condvar.h> #include <utils/linked_list.h> -typedef struct private_radius_server_t private_radius_server_t; +typedef struct private_radius_config_t private_radius_config_t; /** - * Private data of an radius_server_t object. + * Private data of an radius_config_t object. */ -struct private_radius_server_t { +struct private_radius_config_t { /** - * Public radius_server_t interface. + * Public radius_config_t interface. */ - radius_server_t public; + radius_config_t public; /** * list of radius sockets, as radius_socket_t @@ -82,8 +82,8 @@ struct private_radius_server_t { refcount_t ref; }; -METHOD(radius_server_t, get_socket, radius_socket_t*, - private_radius_server_t *this) +METHOD(radius_config_t, get_socket, radius_socket_t*, + private_radius_config_t *this) { radius_socket_t *skt; @@ -96,8 +96,8 @@ METHOD(radius_server_t, get_socket, radius_socket_t*, return skt; } -METHOD(radius_server_t, put_socket, void, - private_radius_server_t *this, radius_socket_t *skt, bool result) +METHOD(radius_config_t, put_socket, void, + private_radius_config_t *this, radius_socket_t *skt, bool result) { this->mutex->lock(this->mutex); this->sockets->insert_last(this->sockets, skt); @@ -106,14 +106,14 @@ METHOD(radius_server_t, put_socket, void, this->reachable = result; } -METHOD(radius_server_t, get_nas_identifier, chunk_t, - private_radius_server_t *this) +METHOD(radius_config_t, get_nas_identifier, chunk_t, + private_radius_config_t *this) { return this->nas_identifier; } -METHOD(radius_server_t, get_preference, int, - private_radius_server_t *this) +METHOD(radius_config_t, get_preference, int, + private_radius_config_t *this) { int pref; @@ -147,22 +147,22 @@ METHOD(radius_server_t, get_preference, int, return pref; } -METHOD(radius_server_t, get_name, char*, - private_radius_server_t *this) +METHOD(radius_config_t, get_name, char*, + private_radius_config_t *this) { return this->name; } -METHOD(radius_server_t, get_ref, radius_server_t*, - private_radius_server_t *this) +METHOD(radius_config_t, get_ref, radius_config_t*, + private_radius_config_t *this) { ref_get(&this->ref); return &this->public; } -METHOD(radius_server_t, destroy, void, - private_radius_server_t *this) +METHOD(radius_config_t, destroy, void, + private_radius_config_t *this) { if (ref_put(&this->ref)) { @@ -177,10 +177,12 @@ METHOD(radius_server_t, destroy, void, /** * See header */ -radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, - char *nas_identifier, char *secret, int sockets, int preference) +radius_config_t *radius_config_create(char *name, char *address, + u_int16_t auth_port, u_int16_t acct_port, + char *nas_identifier, char *secret, + int sockets, int preference) { - private_radius_server_t *this; + private_radius_config_t *this; radius_socket_t *socket; INIT(this, @@ -206,7 +208,7 @@ radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, while (sockets--) { - socket = radius_socket_create(address, port, + socket = radius_socket_create(address, auth_port, acct_port, chunk_create(secret, strlen(secret))); if (!socket) { diff --git a/src/libcharon/plugins/eap_radius/radius_server.h b/src/libradius/radius_config.h index c59361c49..40ed6197a 100644 --- a/src/libcharon/plugins/eap_radius/radius_server.h +++ b/src/libradius/radius_config.h @@ -14,28 +14,28 @@ */ /** - * @defgroup radius_server radius_server - * @{ @ingroup eap_radius + * @defgroup radius_config radius_config + * @{ @ingroup libradius */ -#ifndef RADIUS_SERVER_H_ -#define RADIUS_SERVER_H_ +#ifndef RADIUS_CONFIG_H_ +#define RADIUS_CONFIG_H_ -typedef struct radius_server_t radius_server_t; +typedef struct radius_config_t radius_config_t; #include "radius_socket.h" /** * RADIUS server configuration. */ -struct radius_server_t { +struct radius_config_t { /** - * Get a RADIUS socket from the pool to communicate with this server. + * Get a RADIUS socket from the pool to communicate with this config. * * @return RADIUS socket */ - radius_socket_t* (*get_socket)(radius_server_t *this); + radius_socket_t* (*get_socket)(radius_config_t *this); /** * Release a socket to the pool after use. @@ -43,14 +43,14 @@ struct radius_server_t { * @param skt RADIUS socket to release * @param result result of the socket use, TRUE for success */ - void (*put_socket)(radius_server_t *this, radius_socket_t *skt, bool result); + void (*put_socket)(radius_config_t *this, radius_socket_t *skt, bool result); /** * Get the NAS-Identifier to use with this server. * * @return NAS-Identifier, internal data */ - chunk_t (*get_nas_identifier)(radius_server_t *this); + chunk_t (*get_nas_identifier)(radius_config_t *this); /** * Get the preference of this server. @@ -58,40 +58,43 @@ struct radius_server_t { * Based on the available sockets and the server reachability a preference * value is calculated: better servers return a higher value. */ - int (*get_preference)(radius_server_t *this); + int (*get_preference)(radius_config_t *this); /** * Get the name of the RADIUS server. * * @return server name */ - char* (*get_name)(radius_server_t *this); + char* (*get_name)(radius_config_t *this); /** - * Increase reference count of this server. + * Increase reference count of this server configuration. * * @return this */ - radius_server_t* (*get_ref)(radius_server_t *this); + radius_config_t* (*get_ref)(radius_config_t *this); /** - * Destroy a radius_server_t. + * Destroy a radius_config_t. */ - void (*destroy)(radius_server_t *this); + void (*destroy)(radius_config_t *this); }; /** - * Create a radius_server instance. + * Create a radius_config_t instance. * * @param name server name * @param address server address - * @param port server port + * @param auth_port server port for authentication + * @param acct_port server port for accounting * @param nas_identifier NAS-Identifier to use with this server * @param secret secret to use with this server * @param sockets number of sockets to create in pool * @param preference preference boost for this server */ -radius_server_t *radius_server_create(char *name, char *address, u_int16_t port, - char *nas_identifier, char *secret, int sockets, int preference); +radius_config_t *radius_config_create(char *name, char *address, + u_int16_t auth_port, u_int16_t acct_port, + char *nas_identifier, char *secret, + int sockets, int preference); -#endif /** RADIUS_SERVER_H_ @}*/ +#endif /** RADIUS_CONFIG_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/radius_message.c b/src/libradius/radius_message.c index 23a29b772..ce8903cdb 100644 --- a/src/libcharon/plugins/eap_radius/radius_message.c +++ b/src/libradius/radius_message.c @@ -15,7 +15,7 @@ #include "radius_message.h" -#include <daemon.h> +#include <debug.h> #include <crypto/hashers/hasher.h> typedef struct private_radius_message_t private_radius_message_t; @@ -74,7 +74,14 @@ ENUM_BEGIN(radius_message_code_names, RMC_ACCESS_REQUEST, RMC_ACCOUNTING_RESPONS "Accounting-Response"); ENUM_NEXT(radius_message_code_names, RMC_ACCESS_CHALLENGE, RMC_ACCESS_CHALLENGE, RMC_ACCOUNTING_RESPONSE, "Access-Challenge"); -ENUM_END(radius_message_code_names, RMC_ACCESS_CHALLENGE); +ENUM_NEXT(radius_message_code_names, RMC_DISCONNECT_REQUEST, RMC_COA_NAK, RMC_ACCESS_CHALLENGE, + "Disconnect-Request", + "Disconnect-ACK", + "Disconnect-NAK", + "CoA-Request", + "CoA-ACK", + "CoA-NAK"); +ENUM_END(radius_message_code_names, RMC_COA_NAK); ENUM(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX, "User-Name", @@ -261,7 +268,7 @@ METHOD(radius_message_t, add, void, { rattr_t *attribute; - data.len = min(data.len, 253); + data.len = min(data.len, MAX_RADIUS_ATTRIBUTE_SIZE); this->msg = realloc(this->msg, ntohs(this->msg->length) + sizeof(rattr_t) + data.len); attribute = ((void*)this->msg) + ntohs(this->msg->length); @@ -272,19 +279,48 @@ METHOD(radius_message_t, add, void, } METHOD(radius_message_t, sign, void, - private_radius_message_t *this, rng_t *rng, signer_t *signer) + private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret, + hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth) { - char buf[HASH_SIZE_MD5]; + if (rng) + { + /* build Request-Authenticator */ + rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator); + } + else + { + /* prepare build of Response-Authenticator */ + if (req_auth) + { + memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5); + } + else + { + memset(this->msg->authenticator, 0, sizeof(this->msg->authenticator)); + } + } - /* build Request-Authenticator */ - rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator); + if (msg_auth) + { + char buf[HASH_SIZE_MD5]; - /* build Message-Authenticator attribute, using 16 null bytes */ - memset(buf, 0, sizeof(buf)); - add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf))); - signer->get_signature(signer, + /* build Message-Authenticator attribute, using 16 null bytes */ + memset(buf, 0, sizeof(buf)); + add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf))); + signer->get_signature(signer, chunk_create((u_char*)this->msg, ntohs(this->msg->length)), ((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5); + } + + if (!rng) + { + chunk_t msg; + + /* build Response-Authenticator */ + msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length)); + hasher->get_hash(hasher, msg, NULL); + hasher->get_hash(hasher, secret, this->msg->authenticator); + } } METHOD(radius_message_t, verify, bool, @@ -297,18 +333,29 @@ METHOD(radius_message_t, verify, bool, chunk_t data, msg; bool has_eap = FALSE, has_auth = FALSE; - /* replace Response by Request Authenticator for verification */ - memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5); - memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5); msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length)); - /* verify Response-Authenticator */ - hasher->get_hash(hasher, msg, NULL); - hasher->get_hash(hasher, secret, buf); - if (!memeq(buf, res_auth, HASH_SIZE_MD5)) + if (this->msg->code != RMC_ACCESS_REQUEST) { - DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed"); - return FALSE; + /* replace Response by Request Authenticator for verification */ + memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5); + if (req_auth) + { + memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5); + } + else + { + memset(this->msg->authenticator, 0, HASH_SIZE_MD5); + } + + /* verify Response-Authenticator */ + hasher->get_hash(hasher, msg, NULL); + hasher->get_hash(hasher, secret, buf); + if (!memeq(buf, res_auth, HASH_SIZE_MD5)) + { + DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed"); + return FALSE; + } } /* verify Message-Authenticator attribute */ @@ -346,8 +393,12 @@ METHOD(radius_message_t, verify, bool, } } enumerator->destroy(enumerator); - /* restore Response-Authenticator */ - memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5); + + if (this->msg->code != RMC_ACCESS_REQUEST) + { + /* restore Response-Authenticator */ + memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5); + } if (has_eap && !has_auth) { /* Message-Authenticator is required if we have an EAP-Message */ @@ -398,7 +449,7 @@ METHOD(radius_message_t, destroy, void, /** * Generic constructor */ -static private_radius_message_t *radius_message_create() +static private_radius_message_t *radius_message_create_empty() { private_radius_message_t *this; @@ -423,12 +474,12 @@ static private_radius_message_t *radius_message_create() /** * See header */ -radius_message_t *radius_message_create_request() +radius_message_t *radius_message_create(radius_message_code_t code) { - private_radius_message_t *this = radius_message_create(); + private_radius_message_t *this = radius_message_create_empty(); INIT(this->msg, - .code = RMC_ACCESS_REQUEST, + .code = code, .identifier = 0, .length = htons(sizeof(rmsg_t)), ); @@ -439,9 +490,9 @@ radius_message_t *radius_message_create_request() /** * See header */ -radius_message_t *radius_message_parse_response(chunk_t data) +radius_message_t *radius_message_parse(chunk_t data) { - private_radius_message_t *this = radius_message_create(); + private_radius_message_t *this = radius_message_create_empty(); this->msg = malloc(data.len); memcpy(this->msg, data.ptr, data.len); @@ -454,4 +505,3 @@ radius_message_t *radius_message_parse_response(chunk_t data) } return &this->public; } - diff --git a/src/libcharon/plugins/eap_radius/radius_message.h b/src/libradius/radius_message.h index 266839d3b..90698ae7b 100644 --- a/src/libcharon/plugins/eap_radius/radius_message.h +++ b/src/libradius/radius_message.h @@ -14,8 +14,13 @@ */ /** + * @defgroup libradius libradius + * + * @addtogroup libradius + * RADIUS protocol support library. + * * @defgroup radius_message radius_message - * @{ @ingroup eap_radius + * @{ @ingroup libradius */ #ifndef RADIUS_MESSAGE_H_ @@ -23,6 +28,10 @@ #include <library.h> +#define MAX_RADIUS_ATTRIBUTE_SIZE 253 + +#define RADIUS_TUNNEL_TYPE_ESP 9 + typedef struct radius_message_t radius_message_t; typedef enum radius_message_code_t radius_message_code_t; typedef enum radius_attribute_type_t radius_attribute_type_t; @@ -37,6 +46,12 @@ enum radius_message_code_t { RMC_ACCOUNTING_REQUEST = 4, RMC_ACCOUNTING_RESPONSE = 5, RMC_ACCESS_CHALLENGE = 11, + RMC_DISCONNECT_REQUEST = 40, + RMC_DISCONNECT_ACK = 41, + RMC_DISCONNECT_NAK = 42, + RMC_COA_REQUEST = 43, + RMC_COA_ACK = 44, + RMC_COA_NAK = 45, }; /** @@ -236,18 +251,23 @@ struct radius_message_t { /** * Calculate and add the Message-Authenticator attribute to the message. * - * @param rng RNG to create Request-Authenticator + * @param req_auth 16 byte Authenticator of request, or NULL + * @param secret shared RADIUS secret * @param signer HMAC-MD5 signer with secret set + * @param hasher MD5 hasher + * @param rng RNG to create Request-Authenticator, NULL to omit + * @param msg_auth calculate and add Message-Authenticator */ - void (*sign)(radius_message_t *this, rng_t *rng, signer_t *signer); + void (*sign)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret, + hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth); /** - * Verify the integrity of a received RADIUS response. + * Verify the integrity of a received RADIUS message. * - * @param req_auth 16 byte Authenticator of the corresponding request + * @param req_auth 16 byte Authenticator of request, or NULL * @param secret shared RADIUS secret - * @param hasher hasher to verify Response-Authenticator - * @param signer signer to verify Message-Authenticator attribute + * @param signer HMAC-MD5 signer with secret set + * @param hasher MD5 hasher */ bool (*verify)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret, hasher_t *hasher, signer_t *signer); @@ -259,18 +279,19 @@ struct radius_message_t { }; /** - * Create an empty RADIUS request message (RMT_ACCESS_REQUEST). + * Create an empty RADIUS message. * + * @param code request type * @return radius_message_t object */ -radius_message_t *radius_message_create_request(); +radius_message_t *radius_message_create(radius_message_code_t code); /** - * Parse and verify a recevied RADIUS response. + * Parse and verify a recevied RADIUS message. * * @param data received message data * @return radius_message_t object, NULL if length invalid */ -radius_message_t *radius_message_parse_response(chunk_t data); +radius_message_t *radius_message_parse(chunk_t data); #endif /** RADIUS_MESSAGE_H_ @}*/ diff --git a/src/libradius/radius_mppe.h b/src/libradius/radius_mppe.h new file mode 100644 index 000000000..1b7a732ec --- /dev/null +++ b/src/libradius/radius_mppe.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR 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 radius_mppe radius_mppe + * @{ @ingroup libradius + */ + +#ifndef RADIUS_MPPE_H_ +#define RADIUS_MPPE_H_ + +/** + * Microsoft specific vendor attributes + */ +#define MS_MPPE_SEND_KEY 16 +#define MS_MPPE_RECV_KEY 17 + +typedef struct mppe_key_t mppe_key_t; + +struct mppe_key_t { + u_int32_t id; + u_int8_t type; + u_int8_t length; + u_int16_t salt; + u_int8_t key[]; +} __attribute__((packed)); + +#endif /** RADIUS_MPPE_H_ @}*/ diff --git a/src/libcharon/plugins/eap_radius/radius_socket.c b/src/libradius/radius_socket.c index b3229c288..048c8814e 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.c +++ b/src/libradius/radius_socket.c @@ -14,23 +14,14 @@ */ #include "radius_socket.h" +#include "radius_mppe.h" #include <errno.h> #include <unistd.h> +#include <pen/pen.h> #include <debug.h> -/** - * Vendor-Id of Microsoft specific attributes - */ -#define VENDOR_ID_MICROSOFT 311 - -/** - * Microsoft specific vendor attributes - */ -#define MS_MPPE_SEND_KEY 16 -#define MS_MPPE_RECV_KEY 17 - typedef struct private_radius_socket_t private_radius_socket_t; /** @@ -44,19 +35,29 @@ struct private_radius_socket_t { radius_socket_t public; /** - * socket file descriptor + * Server port for authentication */ - int fd; + u_int16_t auth_port; /** - * Server address + * socket file descriptor for authentication */ - char *address; + int auth_fd; /** - * Server port + * Server port for accounting */ - u_int16_t port; + u_int16_t acct_port; + + /** + * socket file descriptor for accounting + */ + int acct_fd; + + /** + * Server address + */ + char *address; /** * current RADIUS identifier @@ -87,35 +88,36 @@ struct private_radius_socket_t { /** * Check or establish RADIUS connection */ -static bool check_connection(private_radius_socket_t *this) +static bool check_connection(private_radius_socket_t *this, + int *fd, u_int16_t port) { - if (this->fd == -1) + if (*fd == -1) { host_t *server; - server = host_create_from_dns(this->address, AF_UNSPEC, this->port); + server = host_create_from_dns(this->address, AF_UNSPEC, port); if (!server) { DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed", this->address); return FALSE; } - this->fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP); - if (this->fd == -1) + *fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP); + if (*fd == -1) { DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s", server, strerror(errno)); server->destroy(server); return FALSE; } - if (connect(this->fd, server->get_sockaddr(server), + if (connect(*fd, server->get_sockaddr(server), *server->get_sockaddr_len(server)) < 0) { DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s", server, strerror(errno)); server->destroy(server); - close(this->fd); - this->fd = -1; + close(*fd); + *fd = -1; return FALSE; } server->destroy(server); @@ -127,19 +129,36 @@ METHOD(radius_socket_t, request, radius_message_t*, private_radius_socket_t *this, radius_message_t *request) { chunk_t data; - int i; + int i, *fd; + u_int16_t port; + rng_t *rng = NULL; + + if (request->get_code(request) == RMC_ACCOUNTING_REQUEST) + { + fd = &this->acct_fd; + port = this->acct_port; + } + else + { + fd = &this->auth_fd; + port = this->auth_port; + rng = this->rng; + } /* set Message Identifier */ request->set_identifier(request, this->identifier++); /* sign the request */ - request->sign(request, this->rng, this->signer); + request->sign(request, NULL, this->secret, this->hasher, this->signer, + rng, rng != NULL); - if (!check_connection(this)) + if (!check_connection(this, fd, port)) { return NULL; } data = request->get_encoding(request); + DBG3(DBG_CFG, "%B", &data); + /* timeout after 2, 3, 4, 5 seconds */ for (i = 2; i <= 5; i++) { @@ -150,7 +169,7 @@ METHOD(radius_socket_t, request, radius_message_t*, fd_set fds; int res; - if (send(this->fd, data.ptr, data.len, 0) != data.len) + if (send(*fd, data.ptr, data.len, 0) != data.len) { DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno)); return NULL; @@ -161,8 +180,8 @@ METHOD(radius_socket_t, request, radius_message_t*, while (TRUE) { FD_ZERO(&fds); - FD_SET(this->fd, &fds); - res = select(this->fd + 1, &fds, NULL, NULL, &tv); + FD_SET(*fd, &fds); + res = select((*fd) + 1, &fds, NULL, NULL, &tv); /* TODO: updated tv to time not waited. Linux does this for us. */ if (res < 0) { /* failed */ @@ -176,14 +195,14 @@ METHOD(radius_socket_t, request, radius_message_t*, retransmit = TRUE; break; } - res = recv(this->fd, buf, sizeof(buf), MSG_DONTWAIT); + res = recv(*fd, buf, sizeof(buf), MSG_DONTWAIT); if (res <= 0) { DBG1(DBG_CFG, "receiving RADIUS message failed: %s", strerror(errno)); break; } - response = radius_message_parse_response(chunk_create(buf, res)); + response = radius_message_parse(chunk_create(buf, res)); if (response) { if (response->verify(response, @@ -262,13 +281,7 @@ METHOD(radius_socket_t, decrypt_msk, chunk_t, private_radius_socket_t *this, radius_message_t *request, radius_message_t *response) { - struct { - u_int32_t id; - u_int8_t type; - u_int8_t length; - u_int16_t salt; - u_int8_t key[]; - } __attribute__((packed)) *mppe_key; + mppe_key_t *mppe_key; enumerator_t *enumerator; chunk_t data, send = chunk_empty, recv = chunk_empty; int type; @@ -276,14 +289,13 @@ METHOD(radius_socket_t, decrypt_msk, chunk_t, enumerator = response->create_enumerator(response); while (enumerator->enumerate(enumerator, &type, &data)) { - if (type == RAT_VENDOR_SPECIFIC && - data.len > sizeof(*mppe_key)) + if (type == RAT_VENDOR_SPECIFIC && data.len > sizeof(mppe_key_t)) { - mppe_key = (void*)data.ptr; - if (ntohl(mppe_key->id) == VENDOR_ID_MICROSOFT && + mppe_key = (mppe_key_t*)data.ptr; + if (ntohl(mppe_key->id) == PEN_MICROSOFT && mppe_key->length == data.len - sizeof(mppe_key->id)) { - data = chunk_create(mppe_key->key, data.len - sizeof(*mppe_key)); + data = chunk_create(mppe_key->key, data.len - sizeof(mppe_key_t)); if (mppe_key->type == MS_MPPE_SEND_KEY) { send = decrypt_mppe_key(this, mppe_key->salt, data, request); @@ -311,9 +323,13 @@ METHOD(radius_socket_t, destroy, void, DESTROY_IF(this->hasher); DESTROY_IF(this->signer); DESTROY_IF(this->rng); - if (this->fd != -1) + if (this->auth_fd != -1) + { + close(this->auth_fd); + }; + if (this->acct_fd != -1) { - close(this->fd); + close(this->acct_fd); } free(this); } @@ -321,8 +337,8 @@ METHOD(radius_socket_t, destroy, void, /** * See header */ -radius_socket_t *radius_socket_create(char *address, u_int16_t port, - chunk_t secret) +radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port, + u_int16_t acct_port, chunk_t secret) { private_radius_socket_t *this; @@ -333,13 +349,15 @@ radius_socket_t *radius_socket_create(char *address, u_int16_t port, .destroy = _destroy, }, .address = address, - .port = port, - .fd = -1, + .auth_port = auth_port, + .auth_fd = -1, + .acct_port = acct_port, + .acct_fd = -1, + .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5), + .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128), + .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), ); - this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); - this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128); - this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); if (!this->hasher || !this->signer || !this->rng) { DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required"); diff --git a/src/libcharon/plugins/eap_radius/radius_socket.h b/src/libradius/radius_socket.h index 2875008eb..07d642c08 100644 --- a/src/libcharon/plugins/eap_radius/radius_socket.h +++ b/src/libradius/radius_socket.h @@ -15,7 +15,7 @@ /** * @defgroup radius_socket radius_socket - * @{ @ingroup eap_radius + * @{ @ingroup libradius */ #ifndef RADIUS_SOCKET_H_ @@ -67,10 +67,11 @@ struct radius_socket_t { * Create a radius_socket instance. * * @param address server name - * @param port server port + * @param auth_port server port for authentication + * @param acct_port server port for accounting * @param secret RADIUS secret */ -radius_socket_t *radius_socket_create(char *address, u_int16_t port, - chunk_t secret); +radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port, + u_int16_t acct_port, chunk_t secret); #endif /** RADIUS_SOCKET_H_ @}*/ diff --git a/src/libsimaka/simaka_manager.h b/src/libsimaka/simaka_manager.h index a0edd60b9..64a67e56c 100644 --- a/src/libsimaka/simaka_manager.h +++ b/src/libsimaka/simaka_manager.h @@ -113,7 +113,7 @@ struct simaka_manager_t { identification_t *pseudonym); /** - * Get a stored pseudonym from one of the registerd SIM cards. + * Get a stored pseudonym from one of the registered SIM cards. * * @param id permanent identity of the peer * @return associated pseudonym identity, NULL if none found @@ -134,7 +134,7 @@ struct simaka_manager_t { u_int16_t counter); /** - * Retrieve fast reauthentication parameters from one of the registerd cards. + * Retrieve fast reauthentication parameters from one of the registered cards. * * @param id permanent identity of the peer * @param mk buffer receiving master key MK diff --git a/src/libsimaka/simaka_message.c b/src/libsimaka/simaka_message.c index 969dc45ae..a5754b985 100644 --- a/src/libsimaka/simaka_message.c +++ b/src/libsimaka/simaka_message.c @@ -139,7 +139,7 @@ ENUM(simaka_client_error_names, SIM_UNABLE_TO_PROCESS, SIM_RANDS_NOT_FRESH, */ bool simaka_attribute_skippable(simaka_attribute_t attribute) { - bool skippable = !(attribute >= 0 && attribute <= 127); + bool skippable = !((int)attribute >= 0 && attribute <= 127); DBG1(DBG_LIB, "%sskippable EAP-SIM/AKA attribute %N", skippable ? "ignoring " : "found non-", diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index b6897c4c3..d33bee6c7 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -128,6 +128,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) \ LOCAL_MODULE := libstrongswan +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 284decbd9..d3c360b47 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -257,6 +257,13 @@ if MONOLITHIC endif endif +if USE_PKCS8 + SUBDIRS += plugins/pkcs8 +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/pkcs8/libstrongswan-pkcs8.la +endif +endif + if USE_PGP SUBDIRS += plugins/pgp if MONOLITHIC diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c index 4466b37a4..4cb38d126 100644 --- a/src/libstrongswan/asn1/asn1.c +++ b/src/libstrongswan/asn1/asn1.c @@ -222,7 +222,7 @@ size_t asn1_length(chunk_t *blob) if (blob->len < 2) { - DBG2(DBG_LIB, "insufficient number of octets to parse ASN.1 length"); + DBG2(DBG_ASN, "insufficient number of octets to parse ASN.1 length"); return ASN1_INVALID_LENGTH; } @@ -234,7 +234,7 @@ size_t asn1_length(chunk_t *blob) { /* single length octet */ if (n > blob->len) { - DBG2(DBG_LIB, "length is larger than remaining blob size"); + DBG2(DBG_ASN, "length is larger than remaining blob size"); return ASN1_INVALID_LENGTH; } return n; @@ -245,13 +245,13 @@ size_t asn1_length(chunk_t *blob) if (n == 0 || n > blob->len) { - DBG2(DBG_LIB, "number of length octets invalid"); + DBG2(DBG_ASN, "number of length octets invalid"); return ASN1_INVALID_LENGTH; } if (n > sizeof(len)) { - DBG2(DBG_LIB, "number of length octets is larger than limit of" + DBG2(DBG_ASN, "number of length octets is larger than limit of" " %d octets", (int)sizeof(len)); return ASN1_INVALID_LENGTH; } @@ -265,7 +265,7 @@ size_t asn1_length(chunk_t *blob) } if (len > blob->len) { - DBG2(DBG_LIB, "length is larger than remaining blob size"); + DBG2(DBG_ASN, "length is larger than remaining blob size"); return ASN1_INVALID_LENGTH; } return len; @@ -326,10 +326,10 @@ static const int tm_leap_1970 = 477; */ time_t asn1_to_time(const chunk_t *utctime, asn1_t type) { - int tm_year, tm_mon, tm_day, tm_days, tm_hour, tm_min, tm_sec; + int tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec; int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap; int tz_hour, tz_min, tz_offset; - time_t tm_secs; + time_t tm_days, tm_secs; u_char *eot = NULL; if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL) @@ -435,6 +435,11 @@ chunk_t asn1_from_time(const time_t *time, asn1_t type) struct tm t; gmtime_r(time, &t); + /* RFC 5280 says that dates through the year 2049 MUST be encoded as UTCTIME + * and dates in 2050 or later MUST be encoded as GENERALIZEDTIME. We only + * enforce the latter to avoid overflows but allow callers to force the + * encoding to GENERALIZEDTIME */ + type = (t.tm_year >= 150) ? ASN1_GENERALIZEDTIME : type; if (type == ASN1_GENERALIZEDTIME) { format = "%04d%02d%02d%02d%02d%02dZ"; @@ -443,7 +448,7 @@ chunk_t asn1_from_time(const time_t *time, asn1_t type) else /* ASN1_UTCTIME */ { format = "%02d%02d%02d%02d%02d%02dZ"; - offset = (t.tm_year < 100)? 0 : -100; + offset = (t.tm_year < 100) ? 0 : -100; } snprintf(buf, BUF_LEN, format, t.tm_year + offset, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); @@ -471,12 +476,12 @@ void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private) { break; } - DBG2(DBG_LIB, " %s", oid_str); + DBG2(DBG_ASN, " %s", oid_str); free(oid_str); } else { - DBG2(DBG_LIB, " '%s'", oid_names[oid].name); + DBG2(DBG_ASN, " '%s'", oid_names[oid].name); } return; case ASN1_UTF8STRING: @@ -484,14 +489,14 @@ void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private) case ASN1_PRINTABLESTRING: case ASN1_T61STRING: case ASN1_VISIBLESTRING: - DBG2(DBG_LIB, " '%.*s'", (int)object.len, object.ptr); + DBG2(DBG_ASN, " '%.*s'", (int)object.len, object.ptr); return; case ASN1_UTCTIME: case ASN1_GENERALIZEDTIME: { time_t time = asn1_to_time(&object, type); - DBG2(DBG_LIB, " '%T'", &time, TRUE); + DBG2(DBG_ASN, " '%T'", &time, TRUE); } return; default: @@ -499,11 +504,11 @@ void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private) } if (private) { - DBG4(DBG_LIB, "%B", &object); + DBG4(DBG_ASN, "%B", &object); } else { - DBG3(DBG_LIB, "%B", &object); + DBG3(DBG_ASN, "%B", &object); } } @@ -517,14 +522,14 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c /* an ASN.1 object must possess at least a tag and length field */ if (object->len < 2) { - DBG2(DBG_LIB, "L%d - %s: ASN.1 object smaller than 2 octets", level, + DBG2(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets", level, name); return FALSE; } if (*object->ptr != type) { - DBG2(DBG_LIB, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", + DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", level, name, type, *object->ptr); return FALSE; } @@ -533,12 +538,12 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c if (len == ASN1_INVALID_LENGTH || object->len < len) { - DBG2(DBG_LIB, "L%d - %s: length of ASN.1 object invalid or too large", + DBG2(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large", level, name); return FALSE; } - DBG2(DBG_LIB, "L%d - %s:", level, name); + DBG2(DBG_ASN, "L%d - %s:", level, name); asn1_debug_simple_object(*object, type, FALSE); return TRUE; } @@ -547,14 +552,20 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c * ASN.1 definition of an algorithmIdentifier */ static const asn1Object_t algorithmIdentifierObjects[] = { - { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */ - { 1, "parameters", ASN1_EOC, ASN1_RAW|ASN1_OPT }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } + { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */ + { 1, "parameters", ASN1_OID, ASN1_RAW|ASN1_OPT }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 1, "parameters", ASN1_SEQUENCE, ASN1_RAW|ASN1_OPT }, /* 4 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 5 */ + { 1, "parameters", ASN1_OCTET_STRING, ASN1_RAW|ASN1_OPT }, /* 6 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; -#define ALGORITHM_ID_ALG 1 -#define ALGORITHM_ID_PARAMETERS 2 +#define ALGORITHM_ID_ALG 1 +#define ALGORITHM_ID_PARAMETERS_OID 2 +#define ALGORITHM_ID_PARAMETERS_SEQ 4 +#define ALGORITHM_ID_PARAMETERS_OCT 6 /* * Defined in header @@ -576,7 +587,9 @@ int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters case ALGORITHM_ID_ALG: alg = asn1_known_oid(object); break; - case ALGORITHM_ID_PARAMETERS: + case ALGORITHM_ID_PARAMETERS_OID: + case ALGORITHM_ID_PARAMETERS_SEQ: + case ALGORITHM_ID_PARAMETERS_OCT: if (parameters != NULL) { *parameters = object; @@ -606,7 +619,7 @@ bool is_asn1(chunk_t blob) tag = *blob.ptr; if (tag != ASN1_SEQUENCE && tag != ASN1_SET && tag != ASN1_OCTET_STRING) { - DBG2(DBG_LIB, " file content is not binary ASN.1"); + DBG2(DBG_ASN, " file content is not binary ASN.1"); return FALSE; } @@ -624,7 +637,7 @@ bool is_asn1(chunk_t blob) return TRUE; } - DBG2(DBG_LIB, " file size does not match ASN.1 coded length"); + DBG2(DBG_ASN, " file size does not match ASN.1 coded length"); return FALSE; } diff --git a/src/libstrongswan/asn1/asn1.h b/src/libstrongswan/asn1/asn1.h index 05a060827..15ffff62e 100644 --- a/src/libstrongswan/asn1/asn1.h +++ b/src/libstrongswan/asn1/asn1.h @@ -35,8 +35,8 @@ typedef enum { ASN1_BOOLEAN = 0x01, ASN1_INTEGER = 0x02, ASN1_BIT_STRING = 0x03, - ASN1_OCTET_STRING = 0x04, - ASN1_NULL = 0x05, + ASN1_OCTET_STRING = 0x04, + ASN1_NULL = 0x05, ASN1_OID = 0x06, ASN1_ENUMERATED = 0x0A, ASN1_UTF8STRING = 0x0C, @@ -48,7 +48,7 @@ typedef enum { ASN1_UTCTIME = 0x17, ASN1_GENERALIZEDTIME = 0x18, ASN1_GRAPHICSTRING = 0x19, - ASN1_VISIBLESTRING = 0x1A, + ASN1_VISIBLESTRING = 0x1A, ASN1_GENERALSTRING = 0x1B, ASN1_UNIVERSALSTRING = 0x1C, ASN1_BMPSTRING = 0x1E, @@ -75,7 +75,7 @@ typedef enum { ASN1_CONTEXT_C_4 = 0xA4, ASN1_CONTEXT_C_5 = 0xA5, - ASN1_INVALID = 0x100, + ASN1_INVALID = 0x100, } asn1_t; #define ASN1_INVALID_LENGTH 0xffffffff @@ -191,6 +191,8 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type); /** * Converts time_t to an ASN.1 UTCTIME or GENERALIZEDTIME string * + * @note The type is automatically changed to GENERALIZEDTIME if needed + * * @param time time_t in UTC * @param type ASN1_UTCTIME or ASN1_GENERALIZEDTIME * @return body of an ASN.1 code time object diff --git a/src/libstrongswan/asn1/asn1_parser.c b/src/libstrongswan/asn1/asn1_parser.c index 2a7a38a52..40e11b321 100644 --- a/src/libstrongswan/asn1/asn1_parser.c +++ b/src/libstrongswan/asn1/asn1_parser.c @@ -120,7 +120,7 @@ METHOD(asn1_parser_t, iterate, bool, if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) ) { /* field is missing */ - DBG2(DBG_LIB, "L%d - %s:", level, obj.name); + DBG2(DBG_ASN, "L%d - %s:", level, obj.name); if (obj.type & ASN1_CONSTRUCTED) { this->line++ ; /* skip context-specific tag */ @@ -147,7 +147,7 @@ METHOD(asn1_parser_t, iterate, bool, if (blob->len < 2) { - DBG1(DBG_LIB, "L%d - %s: ASN.1 object smaller than 2 octets", + DBG1(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets", level, obj.name); this->success = FALSE; goto end; @@ -157,7 +157,7 @@ METHOD(asn1_parser_t, iterate, bool, if (blob1->len == ASN1_INVALID_LENGTH) { - DBG1(DBG_LIB, "L%d - %s: length of ASN.1 object invalid or too large", + DBG1(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large", level, obj.name); this->success = FALSE; } @@ -170,7 +170,7 @@ METHOD(asn1_parser_t, iterate, bool, if (obj.flags & ASN1_RAW) { - DBG2(DBG_LIB, "L%d - %s:", level, obj.name); + DBG2(DBG_ASN, "L%d - %s:", level, obj.name); object->ptr = start_ptr; object->len = (size_t)(blob->ptr - start_ptr); goto end; @@ -178,14 +178,14 @@ METHOD(asn1_parser_t, iterate, bool, if (*start_ptr != obj.type && !(this->implicit && this->line == 0)) { - DBG1(DBG_LIB, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", + DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", level, obj.name, obj.type, *start_ptr); - DBG3(DBG_LIB, "%b", start_ptr, (u_int)(blob->ptr - start_ptr)); + DBG3(DBG_ASN, "%b", start_ptr, (u_int)(blob->ptr - start_ptr)); this->success = FALSE; goto end; } - DBG2(DBG_LIB, "L%d - %s:", level, obj.name); + DBG2(DBG_ASN, "L%d - %s:", level, obj.name); /* In case of "SEQUENCE OF" or "SET OF" start a loop */ if (obj.flags & ASN1_LOOP) @@ -214,11 +214,11 @@ METHOD(asn1_parser_t, iterate, bool, object->len = (size_t)(blob->ptr - start_ptr); if (this->private) { - DBG4(DBG_LIB, "%B", object); + DBG4(DBG_ASN, "%B", object); } else { - DBG3(DBG_LIB, "%B", object); + DBG3(DBG_ASN, "%B", object); } } else if (obj.flags & ASN1_BODY) diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index 73c068851..5daa6dad6 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -97,6 +97,11 @@ 0x0C "sha384WithRSAEncryption" OID_SHA384_WITH_RSA 0x0D "sha512WithRSAEncryption" OID_SHA512_WITH_RSA 0x0E "sha224WithRSAEncryption" OID_SHA224_WITH_RSA + 0x05 "PKCS-5" + 0x03 "pbeWithMD5AndDES-CBC" OID_PBE_MD5_DES_CBC + 0x0A "pbeWithSHA1AndDES-CBC" OID_PBE_SHA1_DES_CBC + 0x0C "id-PBKDF2" OID_PBKDF2 + 0x0D "id-PBES2" OID_PBES2 0x07 "PKCS-7" 0x01 "data" OID_PKCS7_DATA 0x02 "signedData" OID_PKCS7_SIGNED_DATA diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index fbc4b6eda..31c7e7d90 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -65,7 +65,6 @@ extern enum_name_t *auth_class_names; * to transport credentials during the authentication process. */ enum auth_rule_t { - /** identity to use for IKEv2 authentication exchange, identification_t* */ AUTH_RULE_IDENTITY, /** authentication class, auth_class_t */ @@ -125,8 +124,8 @@ extern enum_name_t *auth_rule_names; * * RFC4739 defines multiple authentication rounds. This class defines such * a round from a configuration perspective, either for the local or the remote - * peer. Local config are called "rulesets", as they define how we authenticate. - * Remote peer configs are called "constraits", they define what is needed to + * peer. Local configs are called "rulesets". They define how we authenticate. + * Remote peer configs are called "constraits". They define what is needed to * complete the authentication round successfully. * * @verbatim @@ -150,7 +149,7 @@ extern enum_name_t *auth_rule_names; @endverbatim * - * Values for each items are either pointers (casted to void*) or short + * Values for each item are either pointers (casted to void*) or short * integers (use uintptr_t cast). */ struct auth_cfg_t { @@ -164,7 +163,7 @@ struct auth_cfg_t { void (*add)(auth_cfg_t *this, auth_rule_t rule, ...); /** - * Get an rule value. + * Get a rule value. * * @param rule rule type * @return bool if item has been found @@ -179,9 +178,9 @@ struct auth_cfg_t { enumerator_t* (*create_enumerator)(auth_cfg_t *this); /** - * Replace an rule at enumerator position. + * Replace a rule at enumerator position. * - * @param pos enumerator position position + * @param pos enumerator position * @param rule rule type * @param ... associated value to rule */ @@ -192,7 +191,7 @@ struct auth_cfg_t { * Check if a used config fulfills a set of configured constraints. * * @param constraints required authorization rules - * @param log_error wheter to log compliance errors + * @param log_error whether to log compliance errors * @return TRUE if this complies with constraints */ bool (*complies)(auth_cfg_t *this, auth_cfg_t *constraints, bool log_error); @@ -208,20 +207,20 @@ struct auth_cfg_t { /** * Purge all rules in a config. * - * @param keep_ca wheter to keep AUTH_RULE_CA_CERT entries + * @param keep_ca whether to keep AUTH_RULE_CA_CERT entries */ void (*purge)(auth_cfg_t *this, bool keep_ca); /** * Check two configs for equality. * - * @param other other config to compaire against this + * @param other other config to compare against this * @return TRUE if auth infos identical */ bool (*equals)(auth_cfg_t *this, auth_cfg_t *other); /** - * Clone a authentication config, including all rules. + * Clone an authentication config, including all rules. * * @return cloned configuration */ diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index 68c54fb45..d3157c80e 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -23,6 +23,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END, "BUILD_BLOB_PEM", "BUILD_BLOB_PGP", "BUILD_BLOB_DNSKEY", + "BUILD_BLOB_ALGID_PARAMS", "BUILD_KEY_SIZE", "BUILD_SIGNING_KEY", "BUILD_SIGNING_CERT", diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index 325b668cd..41250ccae 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -28,8 +28,8 @@ typedef enum builder_part_t builder_part_t; /** * Constructor function to build credentials. * - * Any added parts are cloned/refcounted by the builder implementation, a - * caller may need to free the passed ressources themself. + * Any added parts are cloned/refcounted by the builder implementation. + * Callers may need to free the passed resources themselves. * * @param subtype constructor specific subtype, e.g. a certificate_type_t * @param args list of builder part types, followed by parts, BUILD_END @@ -53,10 +53,12 @@ enum builder_part_t { BUILD_BLOB_ASN1_DER, /** PEM encoded ASN.1/PGP blob, chunk_t */ BUILD_BLOB_PEM, - /** OpenPGP key blob, chunk_t */ + /** OpenPGP key blob, chunk_t */ BUILD_BLOB_PGP, /** DNS public key blob (RFC 4034, RSA specifc RFC 3110), chunk_t */ BUILD_BLOB_DNSKEY, + /** parameters from algorithmIdentifier (ASN.1 blob), chunk_t */ + BUILD_BLOB_ALGID_PARAMS, /** key size in bits, as used for key generation, u_int */ BUILD_KEY_SIZE, /** private key to use for signing, private_key_t* */ diff --git a/src/libstrongswan/credentials/cert_validator.h b/src/libstrongswan/credentials/cert_validator.h index 733d9d612..00e30d7a0 100644 --- a/src/libstrongswan/credentials/cert_validator.h +++ b/src/libstrongswan/credentials/cert_validator.h @@ -39,7 +39,7 @@ struct cert_validator_t { * * @param subject subject certificate to check * @param issuer issuer of subject - * @param online wheter to do online revocation checking + * @param online whether to do online revocation checking * @param pathlen the current length of the path bottom-up * @param anchor is issuer trusted root anchor * @param auth container for resulting authentication info diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h index 8bd2a6a83..00171a718 100644 --- a/src/libstrongswan/credentials/certificates/x509.h +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -78,12 +78,12 @@ enum x509_constraint_t { * X.509 certPolicy extension. */ struct x509_cert_policy_t { - /** OID of certPolicy */ - chunk_t oid; /** Certification Practice Statement URI qualifier */ char *cps_uri; /** UserNotice Text qualifier */ char *unotice_text; + /** OID of certPolicy */ + chunk_t oid; }; /** diff --git a/src/libstrongswan/credentials/cred_encoding.c b/src/libstrongswan/credentials/cred_encoding.c index a7637b598..4865984dd 100644 --- a/src/libstrongswan/credentials/cred_encoding.c +++ b/src/libstrongswan/credentials/cred_encoding.c @@ -116,7 +116,7 @@ METHOD(cred_encoding_t, get_cache, bool, { chunk_t *chunk; - if (type >= CRED_ENCODING_MAX || type < 0) + if (type >= CRED_ENCODING_MAX || (int)type < 0) { return FALSE; } @@ -142,7 +142,7 @@ static bool encode(private_cred_encoding_t *this, cred_encoding_type_t type, bool success = FALSE; chunk_t *chunk; - if (type >= CRED_ENCODING_MAX || type < 0) + if (type >= CRED_ENCODING_MAX || (int)type < 0) { return FALSE; } @@ -195,7 +195,7 @@ METHOD(cred_encoding_t, cache, void, { chunk_t *chunk; - if (type >= CRED_ENCODING_MAX || type < 0) + if (type >= CRED_ENCODING_MAX || (int)type < 0) { return free(encoding.ptr); } diff --git a/src/libstrongswan/credentials/cred_encoding.h b/src/libstrongswan/credentials/cred_encoding.h index e2d69691e..b029fe2ac 100644 --- a/src/libstrongswan/credentials/cred_encoding.h +++ b/src/libstrongswan/credentials/cred_encoding.h @@ -59,7 +59,7 @@ bool cred_encoding_args(va_list args, ...); /** * Encoding type of a fingerprint/credential. * - * Fingerprints have have the KEYID_*, public keys the PUBKEY_* and + * Fingerprints have the KEYID_*, public keys the PUBKEY_* and * private keys the PRIVKEY_* prefix. */ enum cred_encoding_type_t { diff --git a/src/libstrongswan/credentials/credential_factory.h b/src/libstrongswan/credentials/credential_factory.h index 709dc916a..c31601245 100644 --- a/src/libstrongswan/credentials/credential_factory.h +++ b/src/libstrongswan/credentials/credential_factory.h @@ -54,7 +54,7 @@ struct credential_factory_t { * The variable argument list takes builder_part_t types followed * by the type specific value. The list must be terminated using BUILD_END. * All passed parts get cloned/refcounted by the builder functions, - * so free up allocated ressources after successful and unsuccessful + * so free up allocated resources after successful and unsuccessful * invocations. * * @param type credential type to build diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index b8f8ae8e3..d54359ebf 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -921,7 +921,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*, } /** - * Check if an helper contains a certificate as trust anchor + * Check if a helper contains a certificate as trust anchor */ static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert) { @@ -1004,7 +1004,7 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this, } /** - * find a private key of a give certificate + * find a private key of a given certificate */ static private_key_t *get_private_by_cert(private_credential_manager_t *this, certificate_t *cert, key_type_t type) diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h index 4b9f914c4..ad789c718 100644 --- a/src/libstrongswan/credentials/credential_manager.h +++ b/src/libstrongswan/credentials/credential_manager.h @@ -36,11 +36,11 @@ typedef struct credential_manager_t credential_manager_t; * Manages credentials using credential_sets. * * The credential manager is the entry point of the credential framework. It - * uses so called "sets" to access credentials in a modular fashion, these + * uses so called "sets" to access credentials in a modular fashion. These * are implemented through the credential_set_t interface. * The manager additionally does trust chain verification and trust status - * chaching. A set may call the managers methods if it needs credentials itself, - * the manager uses recursive locking. + * caching. A set may call the managers methods if it needs credentials itself. + * The manager uses recursive locking. * * @verbatim @@ -62,8 +62,8 @@ typedef struct credential_manager_t credential_manager_t; @endverbatim * - * The credential manager uses rwlocks for performance reasons, credential - * sets must be fully thread save. + * The credential manager uses rwlocks for performance reasons. Credential + * sets must be fully thread-safe. */ struct credential_manager_t { @@ -84,7 +84,7 @@ struct credential_manager_t { * * The enumerator enumerates over: * shared_key_t*, id_match_t me, id_match_t other - * But must accepts values for the id_matches. + * But must accept values for the id_matches. * * @param type kind of requested shared key * @param first first subject between key is shared @@ -120,7 +120,7 @@ struct credential_manager_t { * * @param type kind of requested shared key * @param me own identity - * @param other peers identity + * @param other peer identity * @return shared_key_t, NULL if none found */ shared_key_t *(*get_shared)(credential_manager_t *this, shared_key_type_t type, @@ -130,7 +130,7 @@ struct credential_manager_t { * * The get_private() method gets a secret private key identified by either * the keyid itself or an id the key belongs to. - * The auth parameter contains additional information, such as receipients + * The auth parameter contains additional information, such as recipients * trusted CA certs. Auth gets filled with subject and CA certificates * needed to validate a created signature. * @@ -163,7 +163,7 @@ struct credential_manager_t { /** * Create an enumerator over trusted public keys. * - * This method gets a an enumerator over trusted public keys to verify a + * This method creates an enumerator over trusted public keys to verify a * signature created by id. The auth parameter contains additional * authentication infos, e.g. peer and intermediate certificates. * The resulting enumerator enumerates over public_key_t *, auth_cfg_t *, @@ -180,7 +180,7 @@ struct credential_manager_t { key_type_t type, identification_t *id, auth_cfg_t *auth); /** - * Cache a certificate by invoking cache_cert() on all registerd sets. + * Cache a certificate by invoking cache_cert() on all registered sets. * * @param cert certificate to cache */ @@ -199,8 +199,8 @@ struct credential_manager_t { /** * Check if a given subject certificate is issued by an issuer certificate. * - * This operation does signature verification, but uses the credential - * managers cache for to speed up the operation. + * This operation does signature verification using the credential + * manager's cache to speed up the operation. * * @param subject subject certificate to check * @param issuer issuer certificate that potentially has signed subject @@ -228,7 +228,7 @@ struct credential_manager_t { * * To add a credential set for the current trustchain verification * operation, sets may be added for the calling thread only. This - * does not require a write lock and is therefore a much less expensive + * does not require a write lock and is therefore a much cheaper * operation. * The exclusive option allows to disable all other credential sets * until the set is deregistered. diff --git a/src/libstrongswan/credentials/credential_set.h b/src/libstrongswan/credentials/credential_set.h index 0eee237cb..8673c484f 100644 --- a/src/libstrongswan/credentials/credential_set.h +++ b/src/libstrongswan/credentials/credential_set.h @@ -38,7 +38,7 @@ typedef struct credential_set_t credential_set_t; * A credential set enumerator may not block the credential set, i.e. multiple * threads must be able to hold multiple enumerators, as the credential manager * is higly parallelized. The best way to achieve this is by using shared - * read locks for the enumerators only. Otherwiese deadlocks will occur. + * read locks for the enumerators only. Otherwise deadlocks will occur. * The writing cache_cert() routine is called by the manager only if no * enumerator is alive, so it is save to use a write lock there. */ @@ -97,7 +97,7 @@ struct credential_set_t { /** * Cache a certificate in the credential set. * - * The caching policy is implementation dependent, the sets may cache the + * The caching policy is implementation dependent. The sets may cache the * certificate in-memory, persistent on disk or not at all. * * @param cert certificate to cache diff --git a/src/libstrongswan/crypto/crypto_tester.c b/src/libstrongswan/crypto/crypto_tester.c index 4635dccea..8b1daa885 100644 --- a/src/libstrongswan/crypto/crypto_tester.c +++ b/src/libstrongswan/crypto/crypto_tester.c @@ -102,6 +102,8 @@ static const char* get_name(void *sym) return "unknown"; } +#ifdef CLOCK_THREAD_CPUTIME_ID + /** * Start a benchmark timer */ @@ -122,6 +124,14 @@ static u_int end_timing(struct timespec *start) (end.tv_sec - start->tv_sec) * 1000; } +#else /* CLOCK_THREAD_CPUTIME_ID */ + +/* Make benchmarking a no-op if CLOCK_THREAD_CPUTIME_ID is not available */ +#define start_timing(start) ((start)->tv_sec = 0, (start)->tv_nsec = 0) +#define end_timing(...) (this->bench_time) + +#endif /* CLOCK_THREAD_CPUTIME_ID */ + /** * Benchmark a crypter */ diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c index 5f7365321..1124ee6f7 100644 --- a/src/libstrongswan/crypto/diffie_hellman.c +++ b/src/libstrongswan/crypto/diffie_hellman.c @@ -64,7 +64,8 @@ static struct { 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, - 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_1024_BIT, .opt_exp = 32, .public = { @@ -77,7 +78,8 @@ static struct { 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, - 0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_1536_BIT, .opt_exp = 32, .public = { @@ -94,7 +96,8 @@ static struct { 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, - 0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_2048_BIT, .opt_exp = 48, .public = { @@ -115,7 +118,8 @@ static struct { 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, - 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_3072_BIT, .opt_exp = 48, .public = { @@ -144,7 +148,8 @@ static struct { 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, - 0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_4096_BIT, .opt_exp = 64, .public = { @@ -181,7 +186,8 @@ static struct { 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF, 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F, - 0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_6144_BIT, .opt_exp = 64, .public = { @@ -234,7 +240,8 @@ static struct { 0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C, 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68, 0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6, - 0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_8192_BIT, .opt_exp = 64, .public = { @@ -303,7 +310,8 @@ static struct { 0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,0xD5,0xEE,0x38,0x2B, 0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA, 0x9E,0x30,0x50,0xE2,0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71, - 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) + 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF), + .exp_len = 0, }, },{ .group = MODP_1024_160, .opt_exp = 20, .public = { diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h index aca793b71..cab3b1ba7 100644 --- a/src/libstrongswan/crypto/diffie_hellman.h +++ b/src/libstrongswan/crypto/diffie_hellman.h @@ -74,8 +74,7 @@ struct diffie_hellman_t { /** * Returns the shared secret of this diffie hellman exchange. * - * Space for returned secret is allocated and must be - * freed by the caller. + * Space for returned secret is allocated and must be freed by the caller. * * @param secret shared secret will be written into this chunk * @return SUCCESS, FAILED if not both DH values are set @@ -108,7 +107,7 @@ struct diffie_hellman_t { diffie_hellman_group_t (*get_dh_group) (diffie_hellman_t *this); /** - * Destroys an diffie_hellman_t object. + * Destroys a diffie_hellman_t object. */ void (*destroy) (diffie_hellman_t *this); }; diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c index 2593d8b79..a4d0e71fe 100644 --- a/src/libstrongswan/crypto/pkcs7.c +++ b/src/libstrongswan/crypto/pkcs7.c @@ -825,7 +825,7 @@ METHOD(pkcs7_t, build_signedData, bool, /* take the current time as signingTime */ time_t now = time(NULL); - chunk_t signingTime = asn1_from_time(&now, ASN1_UTCTIME); + chunk_t signingTime = asn1_from_time(&now, ASN1_UTCTIME); chunk_t messageDigest, attributes; diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.txt b/src/libstrongswan/crypto/proposal/proposal_keywords.txt index 4ef664d8f..b16e2eccb 100644 --- a/src/libstrongswan/crypto/proposal/proposal_keywords.txt +++ b/src/libstrongswan/crypto/proposal/proposal_keywords.txt @@ -118,6 +118,7 @@ twofish192, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192 twofish256, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256 sha, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 sha1, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 +sha1_160, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0 sha256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 sha2_256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 sha256_96, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0 @@ -127,6 +128,7 @@ sha2_384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0 sha512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 sha2_512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 md5, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0 +md5_128, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0 aesxcbc, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0 camelliaxcbc, INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0 modpnull, DIFFIE_HELLMAN_GROUP, MODP_NULL, 0 diff --git a/src/libstrongswan/debug.c b/src/libstrongswan/debug.c index 608303445..d6c5b06b6 100644 --- a/src/libstrongswan/debug.c +++ b/src/libstrongswan/debug.c @@ -26,6 +26,7 @@ ENUM(debug_names, DBG_DMN, DBG_LIB, "CFG", "KNL", "NET", + "ASN", "ENC", "TNC", "IMC", @@ -44,6 +45,7 @@ ENUM(debug_lower_names, DBG_DMN, DBG_LIB, "cfg", "knl", "net", + "asn", "enc", "tnc", "imc", diff --git a/src/libstrongswan/debug.h b/src/libstrongswan/debug.h index 849d28f9f..2a6ff98ad 100644 --- a/src/libstrongswan/debug.h +++ b/src/libstrongswan/debug.h @@ -48,6 +48,8 @@ enum debug_t { DBG_KNL, /** networking/sockets */ DBG_NET, + /** low-level encoding/decoding (ASN.1, X.509 etc.) */ + DBG_ASN, /** message encoding/decoding */ DBG_ENC, /** trusted network connect */ diff --git a/src/libstrongswan/fetcher/fetcher_manager.h b/src/libstrongswan/fetcher/fetcher_manager.h index 15250d531..449f284f7 100644 --- a/src/libstrongswan/fetcher/fetcher_manager.h +++ b/src/libstrongswan/fetcher/fetcher_manager.h @@ -26,7 +26,7 @@ typedef struct fetcher_manager_t fetcher_manager_t; #include <fetcher/fetcher.h> /** - * Fetches from URIs using registerd fetcher_t instances. + * Fetches from URIs using registered fetcher_t instances. */ struct fetcher_manager_t { diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index 6ed4d1285..cd6a41f44 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -61,6 +61,9 @@ void library_deinit() detailed = lib->settings->get_bool(lib->settings, "libstrongswan.leak_detective.detailed", TRUE); + /* make sure the cache is clear before unloading plugins */ + lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); + this->public.scheduler->destroy(this->public.scheduler); this->public.processor->destroy(this->public.processor); this->public.plugins->destroy(this->public.plugins); diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c index f4c4759bf..950504573 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c @@ -1,6 +1,6 @@ /* + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2009 Martin Willi - * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -371,14 +371,17 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, va_list args) { private_openssl_ec_private_key_t *this; - chunk_t blob = chunk_empty; + chunk_t par = chunk_empty, key = chunk_empty; while (TRUE) { switch (va_arg(args, builder_part_t)) { + case BUILD_BLOB_ALGID_PARAMS: + par = va_arg(args, chunk_t); + continue; case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); + key = va_arg(args, chunk_t); continue; case BUILD_END: break; @@ -389,18 +392,36 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, } this = create_empty(); - this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&blob.ptr, blob.len); - if (!this->ec) + + if (par.ptr) { - destroy(this); - return NULL; + this->ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len); + if (!this->ec) + { + goto error; + } + if (!d2i_ECPrivateKey(&this->ec, (const u_char**)&key.ptr, key.len)) + { + goto error; + } + } + else + { + this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&key.ptr, key.len); + if (!this->ec) + { + goto error; + } } if (!EC_KEY_check_key(this->ec)) { - destroy(this); - return NULL; + goto error; } return &this->public; + +error: + destroy(this); + return NULL; } #endif /* OPENSSL_NO_EC */ diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 422e31521..a24bae5d6 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -44,6 +44,8 @@ struct private_openssl_rsa_public_key_t { refcount_t ref; }; + + /** * Verification of an EMPSA PKCS1 signature described in PKCS#1 */ @@ -386,4 +388,3 @@ openssl_rsa_public_key_t *openssl_rsa_public_key_load(key_type_t type, destroy(this); return NULL; } - diff --git a/src/libstrongswan/plugins/pem/pem_builder.c b/src/libstrongswan/plugins/pem/pem_builder.c index b760adda9..f05d348ee 100644 --- a/src/libstrongswan/plugins/pem/pem_builder.c +++ b/src/libstrongswan/plugins/pem/pem_builder.c @@ -73,7 +73,7 @@ static bool find_boundary(char* tag, chunk_t *line) { if (present("-----", line)) { - DBG2(DBG_LIB, " -----%s %.*s-----", tag, (int)name.len, name.ptr); + DBG2(DBG_ASN, " -----%s %.*s-----", tag, (int)name.len, name.ptr); return TRUE; } line->ptr++; line->len--; name.len++; @@ -99,7 +99,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); if (hasher == NULL) { - DBG1(DBG_LIB, " MD5 hash algorithm not available"); + DBG1(DBG_ASN, " MD5 hash algorithm not available"); return NOT_SUPPORTED; } hash.len = hasher->get_hash_size(hasher); @@ -121,7 +121,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); if (crypter == NULL) { - DBG1(DBG_LIB, " %N encryption algorithm not available", + DBG1(DBG_ASN, " %N encryption algorithm not available", encryption_algorithm_names, alg); return NOT_SUPPORTED; } @@ -131,7 +131,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, blob->len % crypter->get_block_size(crypter)) { crypter->destroy(crypter); - DBG1(DBG_LIB, " data size is not multiple of block size"); + DBG1(DBG_ASN, " data size is not multiple of block size"); return PARSE_ERROR; } crypter->decrypt(crypter, *blob, iv, &decrypted); @@ -155,7 +155,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, { if (*last_padding_pos != padding) { - DBG1(DBG_LIB, " invalid passphrase"); + DBG1(DBG_ASN, " invalid passphrase"); return INVALID_ARG; } } @@ -234,7 +234,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp) } /* we are looking for a parameter: value pair */ - DBG2(DBG_LIB, " %.*s", (int)line.len, line.ptr); + DBG2(DBG_ASN, " %.*s", (int)line.len, line.ptr); ugh = extract_parameter_value(&name, &value, &line); if (ugh != NULL) { @@ -274,7 +274,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp) } else { - DBG1(DBG_LIB, " encryption algorithm '%.*s'" + DBG1(DBG_ASN, " encryption algorithm '%.*s'" " not supported", dek.len, dek.ptr); return NOT_SUPPORTED; } @@ -298,7 +298,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp) *pgp = TRUE; data.ptr++; data.len--; - DBG2(DBG_LIB, " armor checksum: %.*s", (int)data.len, + DBG2(DBG_ASN, " armor checksum: %.*s", (int)data.len, data.ptr); continue; } diff --git a/src/libstrongswan/plugins/pgp/pgp_cert.c b/src/libstrongswan/plugins/pgp/pgp_cert.c index dea183ce2..5b2ec63fc 100644 --- a/src/libstrongswan/plugins/pgp/pgp_cert.c +++ b/src/libstrongswan/plugins/pgp/pgp_cert.c @@ -286,18 +286,18 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet) } break; default: - DBG1(DBG_LIB, "PGP packet version V%d not supported", + DBG1(DBG_ASN, "PGP packet version V%d not supported", this->version); return FALSE; } if (this->valid) { - DBG2(DBG_LIB, "L2 - created %T, valid %d days", &this->created, FALSE, + DBG2(DBG_ASN, "L2 - created %T, valid %d days", &this->created, FALSE, this->valid); } else { - DBG2(DBG_LIB, "L2 - created %T, never expires", &this->created, FALSE); + DBG2(DBG_ASN, "L2 - created %T, never expires", &this->created, FALSE); } DESTROY_IF(this->key); this->key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, @@ -318,13 +318,13 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet) hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (hasher == NULL) { - DBG1(DBG_LIB, "no SHA-1 hasher available"); + DBG1(DBG_ASN, "no SHA-1 hasher available"); return FALSE; } hasher->allocate_hash(hasher, pubkey_packet_header, NULL); hasher->allocate_hash(hasher, pubkey_packet, &this->fingerprint); hasher->destroy(hasher); - DBG2(DBG_LIB, "L2 - v4 fingerprint %#B", &this->fingerprint); + DBG2(DBG_ASN, "L2 - v4 fingerprint %#B", &this->fingerprint); } else { @@ -335,7 +335,7 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet) return FALSE; } this->fingerprint = chunk_clone(this->fingerprint); - DBG2(DBG_LIB, "L2 - v3 fingerprint %#B", &this->fingerprint); + DBG2(DBG_ASN, "L2 - v3 fingerprint %#B", &this->fingerprint); } return TRUE; } @@ -355,7 +355,7 @@ static bool parse_signature(private_pgp_cert_t *this, chunk_t packet) /* we parse only v3 or v4 signature packets */ if (version != 3 && version != 4) { - DBG2(DBG_LIB, "L2 - v%d signature ignored", version); + DBG2(DBG_ASN, "L2 - v%d signature ignored", version); return TRUE; } if (version == 4) @@ -364,7 +364,7 @@ static bool parse_signature(private_pgp_cert_t *this, chunk_t packet) { return FALSE; } - DBG2(DBG_LIB, "L2 - v%d signature of type 0x%02x", version, type); + DBG2(DBG_ASN, "L2 - v%d signature of type 0x%02x", version, type); } else { @@ -377,7 +377,7 @@ static bool parse_signature(private_pgp_cert_t *this, chunk_t packet) { return FALSE; } - DBG2(DBG_LIB, "L2 - v3 signature of type 0x%02x, created %T", type, + DBG2(DBG_ASN, "L2 - v3 signature of type 0x%02x, created %T", type, &created, FALSE); } /* TODO: parse and save signature to a list */ @@ -391,7 +391,7 @@ static bool parse_user_id(private_pgp_cert_t *this, chunk_t packet) { DESTROY_IF(this->user_id); this->user_id = identification_create_from_encoding(ID_KEY_ID, packet); - DBG2(DBG_LIB, "L2 - '%Y'", this->user_id); + DBG2(DBG_ASN, "L2 - '%Y'", this->user_id); return TRUE; } diff --git a/src/libstrongswan/plugins/pgp/pgp_utils.c b/src/libstrongswan/plugins/pgp/pgp_utils.c index 2d85cc0c8..7fd905ce4 100644 --- a/src/libstrongswan/plugins/pgp/pgp_utils.c +++ b/src/libstrongswan/plugins/pgp/pgp_utils.c @@ -79,7 +79,7 @@ bool pgp_read_scalar(chunk_t *blob, size_t bytes, u_int32_t *scalar) if (bytes > blob->len) { - DBG1(DBG_LIB, "PGP data too short to read %d byte scalar", bytes); + DBG1(DBG_ASN, "PGP data too short to read %d byte scalar", bytes); return FALSE; } while (bytes-- > 0) @@ -100,13 +100,13 @@ bool pgp_read_mpi(chunk_t *blob, chunk_t *mpi) if (!pgp_read_scalar(blob, 2, &bits)) { - DBG1(DBG_LIB, "PGP data too short to read MPI length"); + DBG1(DBG_ASN, "PGP data too short to read MPI length"); return FALSE; } bytes = (bits + 7) / 8; if (bytes > blob->len) { - DBG1(DBG_LIB, "PGP data too short to read %d byte MPI", bytes); + DBG1(DBG_ASN, "PGP data too short to read %d byte MPI", bytes); return FALSE; } *mpi = chunk_create(blob->ptr, bytes); @@ -146,7 +146,7 @@ bool pgp_read_packet(chunk_t *blob, chunk_t *data, pgp_packet_tag_t *tag) if (!blob->len) { - DBG1(DBG_LIB, "missing input"); + DBG1(DBG_ASN, "missing input"); return FALSE; } t = blob->ptr[0]; @@ -154,27 +154,27 @@ bool pgp_read_packet(chunk_t *blob, chunk_t *data, pgp_packet_tag_t *tag) /* bit 7 must be set */ if (!(t & 0x80)) { - DBG1(DBG_LIB, "invalid packet tag"); + DBG1(DBG_ASN, "invalid packet tag"); return FALSE; } /* bit 6 set defines new packet format */ if (t & 0x40) { - DBG1(DBG_LIB, "new PGP packet format not supported"); + DBG1(DBG_ASN, "new PGP packet format not supported"); return FALSE; } t = (t & 0x3C) >> 2; if (!pgp_old_packet_length(blob, &len) || len > blob->len) { - DBG1(DBG_LIB, "invalid packet length"); + DBG1(DBG_ASN, "invalid packet length"); return FALSE; } *data = chunk_create(blob->ptr, len); *blob = chunk_skip(*blob, len); *tag = t; - DBG2(DBG_LIB, "L1 - PGP %N (%u bytes)", pgp_packet_tag_names, t, len); - DBG3(DBG_LIB, "%B", data); + DBG2(DBG_ASN, "L1 - PGP %N (%u bytes)", pgp_packet_tag_names, t, len); + DBG3(DBG_ASN, "%B", data); return TRUE; } diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c index a605fabc7..6d022f362 100644 --- a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c @@ -81,10 +81,10 @@ static public_key_t *parse_public_key(chunk_t blob) /* skip initial bit string octet defining 0 unused bits */ object = chunk_skip(object, 1); } - DBG2(DBG_LIB, "-- > --"); + DBG2(DBG_ASN, "-- > --"); key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type, BUILD_BLOB_ASN1_DER, object, BUILD_END); - DBG2(DBG_LIB, "-- < --"); + DBG2(DBG_ASN, "-- < --"); break; } } @@ -197,7 +197,7 @@ static private_key_t *parse_rsa_private_key(chunk_t blob) case PRIV_KEY_VERSION: if (object.len > 0 && *object.ptr != 0) { - DBG1(DBG_LIB, "PKCS#1 private key format is not version 1"); + DBG1(DBG_ASN, "PKCS#1 private key format is not version 1"); goto end; } break; diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c index d49a03856..d4ec9235d 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c @@ -726,7 +726,7 @@ pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args) { private_pkcs11_public_key_t *this; chunk_t n, e, blob; - size_t keylen; + size_t keylen = 0; n = e = blob = chunk_empty; while (TRUE) @@ -810,7 +810,7 @@ static private_pkcs11_public_key_t *find_key_by_keyid(pkcs11_library_t *p11, bool found = FALSE; size_t keylen; - switch (type) + switch (key_type) { case KEY_RSA: type = CKK_RSA; diff --git a/src/libstrongswan/plugins/pkcs8/Makefile.am b/src/libstrongswan/plugins/pkcs8/Makefile.am new file mode 100644 index 000000000..bcaf2c6a5 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs8/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-pkcs8.la +else +plugin_LTLIBRARIES = libstrongswan-pkcs8.la +endif + +libstrongswan_pkcs8_la_SOURCES = \ + pkcs8_plugin.h pkcs8_plugin.c \ + pkcs8_builder.h pkcs8_builder.c + +libstrongswan_pkcs8_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c new file mode 100644 index 000000000..346240ae1 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c @@ -0,0 +1,632 @@ +/* + * 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. + */ + +#include "pkcs8_builder.h" + +#include <debug.h> +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <credentials/keys/private_key.h> + +/** + * ASN.1 definition of a privateKeyInfo structure + */ +static const asn1Object_t pkinfoObjects[] = { + { 0, "privateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "privateKeyAlgorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ + { 1, "privateKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ + { 1, "attributes", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKINFO_PRIVATE_KEY_ALGORITHM 2 +#define PKINFO_PRIVATE_KEY 3 + +/** + * Load a generic private key from an ASN.1 encoded blob + */ +static private_key_t *parse_private_key(chunk_t blob) +{ + asn1_parser_t *parser; + chunk_t object, params = chunk_empty; + int objectID; + private_key_t *key = NULL; + key_type_t type = KEY_ANY; + + parser = asn1_parser_create(pkinfoObjects, blob); + parser->set_flags(parser, FALSE, TRUE); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PKINFO_PRIVATE_KEY_ALGORITHM: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser) + 1, ¶ms); + + switch (oid) + { + case OID_RSA_ENCRYPTION: + type = KEY_RSA; + break; + case OID_EC_PUBLICKEY: + type = KEY_ECDSA; + break; + default: + /* key type not supported */ + goto end; + } + break; + } + case PKINFO_PRIVATE_KEY: + { + DBG2(DBG_ASN, "-- > --"); + if (params.ptr) + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + type, BUILD_BLOB_ALGID_PARAMS, + params, BUILD_BLOB_ASN1_DER, + object, BUILD_END); + } + else + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + type, BUILD_BLOB_ASN1_DER, object, + BUILD_END); + } + DBG2(DBG_ASN, "-- < --"); + break; + } + } + } + +end: + parser->destroy(parser); + return key; +} + +/** + * Verify padding of decrypted blob. + * Length of blob is adjusted accordingly. + */ +static bool verify_padding(chunk_t *blob) +{ + u_int8_t padding, count; + + padding = count = blob->ptr[blob->len - 1]; + if (padding > 8) + { + return FALSE; + } + for (; blob->len && count; --blob->len, --count) + { + if (blob->ptr[blob->len - 1] != padding) + { + return FALSE; + } + } + return TRUE; +} + +/** + * Prototype for key derivation functions. + */ +typedef void (*kdf_t)(void *generator, chunk_t password, chunk_t salt, + u_int64_t iterations, chunk_t key); + +/** + * Try to decrypt the given blob with multiple passwords using the given + * key derivation function. keymat is where the kdf function writes the key + * to, key and iv point to the actual keys and initialization vectors resp. + */ +static private_key_t *decrypt_private_key(chunk_t blob, + encryption_algorithm_t encr, size_t key_len, kdf_t kdf, + void *generator, chunk_t salt, u_int64_t iterations, + chunk_t keymat, chunk_t key, chunk_t iv) +{ + enumerator_t *enumerator; + shared_key_t *shared; + crypter_t *crypter; + private_key_t *private_key = NULL; + + crypter = lib->crypto->create_crypter(lib->crypto, encr, key_len); + if (!crypter) + { + DBG1(DBG_ASN, " %N encryption algorithm not available", + encryption_algorithm_names, encr); + return NULL; + } + if (blob.len % crypter->get_block_size(crypter)) + { + DBG1(DBG_ASN, " data size is not a multiple of block size"); + crypter->destroy(crypter); + return NULL; + } + + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_PRIVATE_KEY_PASS, NULL, NULL); + while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) + { + chunk_t decrypted; + + kdf(generator, shared->get_key(shared), salt, iterations, keymat); + + crypter->set_key(crypter, key); + crypter->decrypt(crypter, blob, iv, &decrypted); + if (verify_padding(&decrypted)) + { + private_key = parse_private_key(decrypted); + if (private_key) + { + chunk_clear(&decrypted); + break; + } + } + chunk_free(&decrypted); + } + enumerator->destroy(enumerator); + crypter->destroy(crypter); + + return private_key; +} + +/** + * Function F of PBKDF2 + */ +static void pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed, + u_int64_t iterations) +{ + chunk_t u; + u_int64_t i; + + u = chunk_alloca(prf->get_block_size(prf)); + prf->get_bytes(prf, seed, u.ptr); + memcpy(block.ptr, u.ptr, block.len); + + for (i = 1; i < iterations; i++) + { + prf->get_bytes(prf, u, u.ptr); + memxor(block.ptr, u.ptr, block.len); + } +} + +/** + * PBKDF2 key derivation function + */ +static void pbkdf2(prf_t *prf, chunk_t password, chunk_t salt, + u_int64_t iterations, chunk_t key) +{ + chunk_t keymat, block, seed; + size_t blocks; + u_int32_t i = 0, *ni; + + prf->set_key(prf, password); + + block.len = prf->get_block_size(prf); + blocks = (key.len - 1) / block.len + 1; + keymat = chunk_alloca(blocks * block.len); + + seed = chunk_cata("cc", salt, chunk_from_thing(i)); + ni = (u_int32_t*)(seed.ptr + salt.len); + + for (; i < blocks; i++) + { + *ni = htonl(i + 1); + block.ptr = keymat.ptr + (i * block.len); + pbkdf2_f(block, prf, seed, iterations); + } + + memcpy(key.ptr, keymat.ptr, key.len); +} + +/** + * Decrypt an encrypted PKCS#8 encoded private key according to PBES2 + */ +static private_key_t *decrypt_private_key_pbes2(chunk_t blob, + encryption_algorithm_t encr, size_t key_len, + chunk_t iv, pseudo_random_function_t prf_func, + chunk_t salt, u_int64_t iterations) +{ + private_key_t *private_key; + prf_t *prf; + chunk_t key; + + prf = lib->crypto->create_prf(lib->crypto, prf_func); + if (!prf) + { + DBG1(DBG_ASN, " %N prf algorithm not available", + pseudo_random_function_names, prf_func); + return NULL; + } + + key = chunk_alloca(key_len); + + private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf2, prf, + salt, iterations, key, key, iv); + + prf->destroy(prf); + return private_key; +} + +/** + * PBKDF1 key derivation function + */ +static void pbkdf1(hasher_t *hasher, chunk_t password, chunk_t salt, + u_int64_t iterations, chunk_t key) +{ + chunk_t hash; + u_int64_t i; + + hash = chunk_alloca(hasher->get_hash_size(hasher)); + hasher->get_hash(hasher, password, NULL); + hasher->get_hash(hasher, salt, hash.ptr); + + for (i = 1; i < iterations; i++) + { + hasher->get_hash(hasher, hash, hash.ptr); + } + + memcpy(key.ptr, hash.ptr, key.len); +} + +/** + * Decrypt an encrypted PKCS#8 encoded private key according to PBES1 + */ +static private_key_t *decrypt_private_key_pbes1(chunk_t blob, + encryption_algorithm_t encr, size_t key_len, + hash_algorithm_t hash, chunk_t salt, + u_int64_t iterations) +{ + private_key_t *private_key = NULL; + hasher_t *hasher = NULL; + chunk_t keymat, key, iv; + + hasher = lib->crypto->create_hasher(lib->crypto, hash); + if (!hasher) + { + DBG1(DBG_ASN, " %N hash algorithm not available", + hash_algorithm_names, hash); + goto end; + } + if (hasher->get_hash_size(hasher) < key_len) + { + goto end; + } + + keymat = chunk_alloca(key_len * 2); + key.len = key_len; + key.ptr = keymat.ptr; + iv.len = key_len; + iv.ptr = keymat.ptr + key_len; + + private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf1, + hasher, salt, iterations, keymat, + key, iv); + +end: + DESTROY_IF(hasher); + return private_key; +} + +/** + * Parse an ASN1_INTEGER to a u_int64_t. + */ +static u_int64_t parse_asn1_integer_uint64(chunk_t blob) +{ + u_int64_t val = 0; + int i; + + for (i = 0; i < blob.len; i++) + { /* if it is longer than 8 bytes, we just use the 8 LSBs */ + val <<= 8; + val |= (u_int64_t)blob.ptr[i]; + } + return val; +} + +/** + * ASN.1 definition of a PBKDF2-params structure + * The salt is actually a CHOICE and could be an AlgorithmIdentifier from + * PBKDF2-SaltSources (but as per RFC 2898 that's for future versions). + */ +static const asn1Object_t pbkdf2ParamsObjects[] = { + { 0, "PBKDF2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */ + { 1, "iterationCount",ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 1, "keyLength", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 3 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "prf", ASN1_EOC, ASN1_DEF|ASN1_RAW }, /* 5 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PBKDF2_SALT 1 +#define PBKDF2_ITERATION_COUNT 2 +#define PBKDF2_KEY_LENGTH 3 +#define PBKDF2_PRF 5 + +/** + * Parse a PBKDF2-params structure + */ +static void parse_pbkdf2_params(chunk_t blob, chunk_t *salt, + u_int64_t *iterations, size_t *key_len, + pseudo_random_function_t *prf) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + + parser = asn1_parser_create(pbkdf2ParamsObjects, blob); + + *key_len = 0; /* key_len is optional */ + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PBKDF2_SALT: + { + *salt = object; + break; + } + case PBKDF2_ITERATION_COUNT: + { + *iterations = parse_asn1_integer_uint64(object); + break; + } + case PBKDF2_KEY_LENGTH: + { + *key_len = (size_t)parse_asn1_integer_uint64(object); + break; + } + case PBKDF2_PRF: + { /* defaults to id-hmacWithSHA1 */ + *prf = PRF_HMAC_SHA1; + break; + } + } + } + + parser->destroy(parser); +} + +/** + * ASN.1 definition of a PBES2-params structure + */ +static const asn1Object_t pbes2ParamsObjects[] = { + { 0, "PBES2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "keyDerivationFunc", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "encryptionScheme", ASN1_EOC, ASN1_RAW }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PBES2PARAMS_KEY_DERIVATION_FUNC 1 +#define PBES2PARAMS_ENCRYPTION_SCHEME 2 + +/** + * Parse a PBES2-params structure + */ +static void parse_pbes2_params(chunk_t blob, chunk_t *salt, + u_int64_t *iterations, size_t *key_len, + pseudo_random_function_t *prf, + encryption_algorithm_t *encr, chunk_t *iv) +{ + asn1_parser_t *parser; + chunk_t object, params; + int objectID; + + parser = asn1_parser_create(pbes2ParamsObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PBES2PARAMS_KEY_DERIVATION_FUNC: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser) + 1, ¶ms); + if (oid != OID_PBKDF2) + { /* unsupported key derivation function */ + goto end; + } + parse_pbkdf2_params(params, salt, iterations, key_len, prf); + break; + } + case PBES2PARAMS_ENCRYPTION_SCHEME: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser) + 1, ¶ms); + if (oid != OID_3DES_EDE_CBC) + { /* unsupported encryption scheme */ + goto end; + } + if (*key_len <= 0) + { /* default key len for DES-EDE3-CBC-Pad */ + *key_len = 24; + } + if (!asn1_parse_simple_object(¶ms, ASN1_OCTET_STRING, + parser->get_level(parser) + 1, "IV")) + { + goto end; + } + *encr = ENCR_3DES; + *iv = params; + break; + } + } + } + +end: + parser->destroy(parser); +} + +/** + * ASN.1 definition of a PBEParameter structure + */ +static const asn1Object_t pbeParameterObjects[] = { + { 0, "PBEParameter", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */ + { 1, "iterationCount", ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PBEPARAM_SALT 1 +#define PBEPARAM_ITERATION_COUNT 2 + +/** + * Parse a PBEParameter structure + */ +static void parse_pbe_parameters(chunk_t blob, chunk_t *salt, + u_int64_t *iterations) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + + parser = asn1_parser_create(pbeParameterObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PBEPARAM_SALT: + { + *salt = object; + break; + } + case PBEPARAM_ITERATION_COUNT: + { + *iterations = parse_asn1_integer_uint64(object); + break; + } + } + } + + parser->destroy(parser); +} + +/** + * ASN.1 definition of an encryptedPrivateKeyInfo structure + */ +static const asn1Object_t encryptedPKIObjects[] = { + { 0, "encryptedPrivateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "encryptedData", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define EPKINFO_ENCRYPTION_ALGORITHM 1 +#define EPKINFO_ENCRYPTED_DATA 2 + +/** + * Load an encrypted private key from an ASN.1 encoded blob + * Schemes per PKCS#5 (RFC 2898) + */ +static private_key_t *parse_encrypted_private_key(chunk_t blob) +{ + asn1_parser_t *parser; + chunk_t object, params, salt, iv; + u_int64_t iterations = 0; + int objectID; + encryption_algorithm_t encr = ENCR_UNDEFINED; + hash_algorithm_t hash = HASH_UNKNOWN; + pseudo_random_function_t prf = PRF_UNDEFINED; + private_key_t *key = NULL; + size_t key_len = 8; + + parser = asn1_parser_create(encryptedPKIObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case EPKINFO_ENCRYPTION_ALGORITHM: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser) + 1, ¶ms); + + switch (oid) + { + case OID_PBE_MD5_DES_CBC: + encr = ENCR_DES; + hash = HASH_MD5; + parse_pbe_parameters(params, &salt, &iterations); + break; + case OID_PBE_SHA1_DES_CBC: + encr = ENCR_DES; + hash = HASH_SHA1; + parse_pbe_parameters(params, &salt, &iterations); + break; + case OID_PBES2: + parse_pbes2_params(params, &salt, &iterations, + &key_len, &prf, &encr, &iv); + break; + default: + /* encryption scheme not supported */ + goto end; + } + break; + } + case EPKINFO_ENCRYPTED_DATA: + { + if (prf != PRF_UNDEFINED) + { + key = decrypt_private_key_pbes2(object, encr, key_len, iv, + prf, salt, iterations); + } + else + { + key = decrypt_private_key_pbes1(object, encr, key_len, hash, + salt, iterations); + } + break; + } + } + } + +end: + parser->destroy(parser); + return key; +} + +/** + * See header. + */ +private_key_t *pkcs8_private_key_load(key_type_t type, va_list args) +{ + chunk_t blob = chunk_empty; + private_key_t *key; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + /* we don't know whether it is encrypted or not, try both ways */ + key = parse_encrypted_private_key(blob); + if (!key) + { + key = parse_private_key(blob); + } + return key; +} + diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.h b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.h new file mode 100644 index 000000000..b07f2d927 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.h @@ -0,0 +1,36 @@ +/* + * 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 pkcs8_builder pkcs8_builder + * @{ @ingroup pkcs8 + */ + +#ifndef PKCS8_BUILDER_H_ +#define PKCS8_BUILDER_H_ + +#include <credentials/builder.h> +#include <credentials/keys/private_key.h> + +/** + * Load an RSA or ECDSA private key from PKCS#8 data. + * + * @param type type of the key, KEY_RSA or KEY_ECDSA + * @param args builder_part_t argument list + * @return private key, NULL on failure + */ +private_key_t *pkcs8_private_key_load(key_type_t type, va_list args); + +#endif /** PKCS8_BUILDER_H_ @}*/ diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c new file mode 100644 index 000000000..f78c83054 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#include "pkcs8_plugin.h" + +#include <library.h> + +#include "pkcs8_builder.h" + +typedef struct private_pkcs8_plugin_t private_pkcs8_plugin_t; + +/** + * private data of pkcs8_plugin + */ +struct private_pkcs8_plugin_t { + + /** + * public functions + */ + pkcs8_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_pkcs8_plugin_t *this) +{ + return "pkcs8"; +} + +METHOD(plugin_t, get_features, int, + private_pkcs8_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_REGISTER(PRIVKEY, pkcs8_private_key_load, FALSE), + PLUGIN_PROVIDE(PRIVKEY, KEY_RSA), + PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_pkcs8_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *pkcs8_plugin_create() +{ + private_pkcs8_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.h b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.h new file mode 100644 index 000000000..03ca950a3 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.h @@ -0,0 +1,42 @@ +/* + * 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 PURPSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pkcs8 pkcs8 + * @ingroup plugins + * + * @defgroup pkcs8_plugin pkcs8_plugin + * @{ @ingroup pkcs8 + */ + +#ifndef PKCS8_PLUGIN_H_ +#define PKCS8_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct pkcs8_plugin_t pkcs8_plugin_t; + +/** + * Plugin providing PKCS#8 private key decoding functions + */ +struct pkcs8_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** PKCS8_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c index 4d26a77f8..164b68e60 100644 --- a/src/libstrongswan/plugins/plugin_loader.c +++ b/src/libstrongswan/plugins/plugin_loader.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2010-2012 Tobias Brunner * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -45,6 +45,11 @@ struct private_plugin_loader_t { * List of plugins, as plugin_entry_t */ linked_list_t *plugins; + + /** + * List of names of loaded plugins + */ + char *loaded_plugins; }; /** @@ -204,6 +209,38 @@ METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*, } /** + * Create a list of the names of all loaded plugins + */ +static char* loaded_plugins_list(private_plugin_loader_t *this) +{ + int buf_len = 128, len = 0; + char *buf, *name; + enumerator_t *enumerator; + plugin_t *plugin; + + buf = malloc(buf_len); + buf[0] = '\0'; + enumerator = create_plugin_enumerator(this); + while (enumerator->enumerate(enumerator, &plugin, NULL)) + { + name = plugin->get_name(plugin); + if (len + (strlen(name) + 1) >= buf_len) + { + buf_len <<= 1; + buf = realloc(buf, buf_len); + } + len += snprintf(&buf[len], buf_len - len, "%s ", name); + } + enumerator->destroy(enumerator); + if (len > 0 && buf[len - 1] == ' ') + { + buf[len - 1] = '\0'; + } + return buf; +} + + +/** * Check if a plugin is already loaded */ static bool plugin_loaded(private_plugin_loader_t *this, char *name) @@ -516,6 +553,11 @@ METHOD(plugin_loader_t, load_plugins, bool, /* unload plugins that we were not able to load any features for */ purge_plugins(this); } + if (!critical_failed) + { + free(this->loaded_plugins); + this->loaded_plugins = loaded_plugins_list(this); + } return !critical_failed; } @@ -558,6 +600,8 @@ METHOD(plugin_loader_t, unload, void, } enumerator->destroy(enumerator); } + free(this->loaded_plugins); + this->loaded_plugins = NULL; } /** @@ -606,11 +650,18 @@ METHOD(plugin_loader_t, reload, u_int, return reloaded; } +METHOD(plugin_loader_t, loaded_plugins, char*, + private_plugin_loader_t *this) +{ + return this->loaded_plugins ?: ""; +} + METHOD(plugin_loader_t, destroy, void, private_plugin_loader_t *this) { unload(this); this->plugins->destroy(this->plugins); + free(this->loaded_plugins); free(this); } @@ -627,6 +678,7 @@ plugin_loader_t *plugin_loader_create() .reload = _reload, .unload = _unload, .create_plugin_enumerator = _create_plugin_enumerator, + .loaded_plugins = _loaded_plugins, .destroy = _destroy, }, .plugins = linked_list_create(), diff --git a/src/libstrongswan/plugins/plugin_loader.h b/src/libstrongswan/plugins/plugin_loader.h index b3ad7a35f..7fd07044d 100644 --- a/src/libstrongswan/plugins/plugin_loader.h +++ b/src/libstrongswan/plugins/plugin_loader.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -68,6 +69,15 @@ struct plugin_loader_t { enumerator_t* (*create_plugin_enumerator)(plugin_loader_t *this); /** + * Get a simple list the names of all loaded plugins. + * + * The function returns internal data, do not free. + * + * @return list of the names of all loaded plugins + */ + char* (*loaded_plugins)(plugin_loader_t *this); + + /** * Unload loaded plugins, destroy plugin_loader instance. */ void (*destroy)(plugin_loader_t *this); diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 16522bf62..a2cb589e0 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -192,7 +192,7 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit, identifi } else { - DBG1(DBG_LIB, "more than one directory name - first selected"); + DBG1(DBG_ASN, "more than one directory name - first selected"); directoryName->destroy(directoryName); } } @@ -200,7 +200,7 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit, identifi } else { - DBG1(DBG_LIB, "no directoryName found"); + DBG1(DBG_ASN, "no directoryName found"); } list->destroy(list); @@ -359,10 +359,10 @@ static bool parse_certificate(private_x509_ac_t *this) break; case AC_OBJ_VERSION: this->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; - DBG2(DBG_LIB, " v%d", this->version); + DBG2(DBG_ASN, " v%d", this->version); if (this->version != 2) { - DBG1(DBG_LIB, "v%d attribute certificates are not " + DBG1(DBG_ASN, "v%d attribute certificates are not " "supported", this->version); goto end; } @@ -408,20 +408,20 @@ static bool parse_certificate(private_x509_ac_t *this) switch (type) { case OID_AUTHENTICATION_INFO: - DBG2(DBG_LIB, " need to parse authenticationInfo"); + DBG2(DBG_ASN, " need to parse authenticationInfo"); break; case OID_ACCESS_IDENTITY: - DBG2(DBG_LIB, " need to parse accessIdentity"); + DBG2(DBG_ASN, " need to parse accessIdentity"); break; case OID_CHARGING_IDENTITY: - DBG2(DBG_LIB, "-- > --"); + DBG2(DBG_ASN, "-- > --"); this->charging = ietf_attributes_create_from_encoding(object); - DBG2(DBG_LIB, "-- < --"); + DBG2(DBG_ASN, "-- < --"); break; case OID_GROUP: - DBG2(DBG_LIB, "-- > --"); + DBG2(DBG_ASN, "-- > --"); this->groups = ietf_attributes_create_from_encoding(object); - DBG2(DBG_LIB, "-- < --"); + DBG2(DBG_ASN, "-- < --"); break; case OID_ROLE: parse_roleSyntax(object, level); @@ -436,21 +436,21 @@ static bool parse_certificate(private_x509_ac_t *this) break; case AC_OBJ_CRITICAL: critical = object.len && *object.ptr; - DBG2(DBG_LIB, " %s",(critical)?"TRUE":"FALSE"); + DBG2(DBG_ASN, " %s",(critical)?"TRUE":"FALSE"); break; case AC_OBJ_EXTN_VALUE: { switch (extn_oid) { case OID_CRL_DISTRIBUTION_POINTS: - DBG2(DBG_LIB, " need to parse crlDistributionPoints"); + DBG2(DBG_ASN, " need to parse crlDistributionPoints"); break; case OID_AUTHORITY_KEY_ID: this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, level, &this->authKeySerialNumber); break; case OID_TARGET_INFORMATION: - DBG2(DBG_LIB, " need to parse targetInformation"); + DBG2(DBG_ASN, " need to parse targetInformation"); break; case OID_NO_REV_AVAIL: this->noRevAvail = TRUE; @@ -465,7 +465,7 @@ static bool parse_certificate(private_x509_ac_t *this) NULL); if (this->algorithm != sig_alg) { - DBG1(DBG_LIB, " signature algorithms do not agree"); + DBG1(DBG_ASN, " signature algorithms do not agree"); success = FALSE; goto end; } @@ -528,7 +528,7 @@ static chunk_t build_attr_cert_validity(private_x509_ac_t *this) { return asn1_wrap(ASN1_SEQUENCE, "mm", asn1_from_time(&this->notBefore, ASN1_GENERALIZEDTIME), - asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME)); + asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME)); } diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index cba1a4610..59f490025 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -301,7 +301,7 @@ static void parse_basicConstraints(chunk_t blob, int level0, { case BASIC_CONSTRAINTS_CA: isCA = object.len && *object.ptr; - DBG2(DBG_LIB, " %s", isCA ? "TRUE" : "FALSE"); + DBG2(DBG_ASN, " %s", isCA ? "TRUE" : "FALSE"); if (isCA) { this->flags |= X509_CA; @@ -482,7 +482,7 @@ static identification_t *parse_generalName(chunk_t blob, int level0) if (id_type != ID_ANY) { gn = identification_create_from_encoding(id_type, object); - DBG2(DBG_LIB, " '%Y'", gn); + DBG2(DBG_ASN, " '%Y'", gn); goto end; } } @@ -638,7 +638,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, /* parsing went wrong - abort */ goto end; } - DBG2(DBG_LIB, " '%Y'", id); + DBG2(DBG_ASN, " '%Y'", id); if (accessMethod == OID_OCSP && asprintf(&uri, "%Y", id) > 0) { @@ -1137,36 +1137,36 @@ static bool check_address_object(ts_type_t ts_type, chunk_t object) case TS_IPV4_ADDR_RANGE: if (object.len > 5) { - DBG1(DBG_LIB, "IPv4 address object is larger than 5 octets"); + DBG1(DBG_ASN, "IPv4 address object is larger than 5 octets"); return FALSE; } break; case TS_IPV6_ADDR_RANGE: if (object.len > 17) { - DBG1(DBG_LIB, "IPv6 address object is larger than 17 octets"); + DBG1(DBG_ASN, "IPv6 address object is larger than 17 octets"); return FALSE; } break; default: - DBG1(DBG_LIB, "unknown address family"); + DBG1(DBG_ASN, "unknown address family"); return FALSE; } if (object.len == 0) { - DBG1(DBG_LIB, "An ASN.1 bit string must contain at least the " + DBG1(DBG_ASN, "An ASN.1 bit string must contain at least the " "initial octet"); return FALSE; } if (object.len == 1 && object.ptr[0] != 0) { - DBG1(DBG_LIB, "An empty ASN.1 bit string must contain a zero " + DBG1(DBG_ASN, "An empty ASN.1 bit string must contain a zero " "initial octet"); return FALSE; } if (object.ptr[0] > 7) { - DBG1(DBG_LIB, "number of unused bits is too large"); + DBG1(DBG_ASN, "number of unused bits is too large"); return FALSE; } return TRUE; @@ -1204,11 +1204,11 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0, { break; } - DBG2(DBG_LIB, " %N", ts_type_name, ts_type); + DBG2(DBG_ASN, " %N", ts_type_name, ts_type); } break; case IP_ADDR_BLOCKS_INHERIT: - DBG1(DBG_LIB, "inherit choice is not supported"); + DBG1(DBG_ASN, "inherit choice is not supported"); break; case IP_ADDR_BLOCKS_PREFIX: if (!check_address_object(ts_type, object)) @@ -1217,7 +1217,7 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0, } ts = traffic_selector_create_from_rfc3779_format(ts_type, object, object); - DBG2(DBG_LIB, " %R", ts); + DBG2(DBG_ASN, " %R", ts); this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); break; case IP_ADDR_BLOCKS_MIN: @@ -1234,7 +1234,7 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0, } ts = traffic_selector_create_from_rfc3779_format(ts_type, min_object, object); - DBG2(DBG_LIB, " %R", ts); + DBG2(DBG_ASN, " %R", ts); this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); break; default: @@ -1323,12 +1323,12 @@ static bool parse_certificate(private_x509_cert_t *this) this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; if (this->version < 1 || this->version > 3) { - DBG1(DBG_LIB, "X.509v%d not supported", this->version); + DBG1(DBG_ASN, "X.509v%d not supported", this->version); goto end; } else { - DBG2(DBG_LIB, " X.509v%d", this->version); + DBG2(DBG_ASN, " X.509v%d", this->version); } break; case X509_OBJ_SERIAL_NUMBER: @@ -1339,7 +1339,7 @@ static bool parse_certificate(private_x509_cert_t *this) break; case X509_OBJ_ISSUER: this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " '%Y'", this->issuer); + DBG2(DBG_ASN, " '%Y'", this->issuer); break; case X509_OBJ_NOT_BEFORE: this->notBefore = asn1_parse_time(object, level); @@ -1349,13 +1349,13 @@ static bool parse_certificate(private_x509_cert_t *this) break; case X509_OBJ_SUBJECT: this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " '%Y'", this->subject); + DBG2(DBG_ASN, " '%Y'", this->subject); break; case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO: - DBG2(DBG_LIB, "-- > --"); + DBG2(DBG_ASN, "-- > --"); this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); - DBG2(DBG_LIB, "-- < --"); + DBG2(DBG_ASN, "-- < --"); if (this->public_key == NULL) { goto end; @@ -1364,7 +1364,7 @@ static bool parse_certificate(private_x509_cert_t *this) case X509_OBJ_OPTIONAL_EXTENSIONS: if (this->version != 3) { - DBG1(DBG_LIB, "Only X.509v3 certificates have extensions"); + DBG1(DBG_ASN, "Only X.509v3 certificates have extensions"); goto end; } break; @@ -1373,7 +1373,7 @@ static bool parse_certificate(private_x509_cert_t *this) break; case X509_OBJ_CRITICAL: critical = object.len && *object.ptr; - DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE"); + DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE"); break; case X509_OBJ_EXTN_VALUE: { @@ -1448,7 +1448,7 @@ static bool parse_certificate(private_x509_cert_t *this) if (critical && lib->settings->get_bool(lib->settings, "libstrongswan.x509.enforce_critical", TRUE)) { - DBG1(DBG_LIB, "critical '%s' extension not supported", + DBG1(DBG_ASN, "critical '%s' extension not supported", (extn_oid == OID_UNKNOWN) ? "unknown" : (char*)oid_names[extn_oid].name); goto end; @@ -1461,7 +1461,7 @@ static bool parse_certificate(private_x509_cert_t *this) this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); if (this->algorithm != sig_alg) { - DBG1(DBG_LIB, " signature algorithms do not agree"); + DBG1(DBG_ASN, " signature algorithms do not agree"); goto end; } break; @@ -1491,7 +1491,7 @@ end: hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (hasher == NULL) { - DBG1(DBG_LIB, " unable to create hash of certificate, SHA1 not supported"); + DBG1(DBG_ASN, " unable to create hash of certificate, SHA1 not supported"); return NULL; } hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash); @@ -1904,7 +1904,7 @@ chunk_t build_generalName(identification_t *id) context = ASN1_CONTEXT_S_7; break; default: - DBG1(DBG_LIB, "encoding %N as generalName not supported", + DBG1(DBG_ASN, "encoding %N as generalName not supported", id_type_names, id->get_type(id)); return chunk_empty; } diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c index 758505ab5..7bcca16a3 100644 --- a/src/libstrongswan/plugins/x509/x509_crl.c +++ b/src/libstrongswan/plugins/x509/x509_crl.c @@ -242,14 +242,14 @@ static bool parse(private_x509_crl_t *this) break; case CRL_OBJ_VERSION: this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG2(DBG_LIB, " v%d", this->version); + DBG2(DBG_ASN, " v%d", this->version); break; case CRL_OBJ_SIG_ALG: sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case CRL_OBJ_ISSUER: this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " '%Y'", this->issuer); + DBG2(DBG_ASN, " '%Y'", this->issuer); break; case CRL_OBJ_THIS_UPDATE: this->thisUpdate = asn1_parse_time(object, level); @@ -274,7 +274,7 @@ static bool parse(private_x509_crl_t *this) case CRL_OBJ_CRL_ENTRY_CRITICAL: case CRL_OBJ_CRITICAL: critical = object.len && *object.ptr; - DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE"); + DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE"); break; case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: case CRL_OBJ_EXTN_VALUE: @@ -291,7 +291,7 @@ static bool parse(private_x509_crl_t *this) { revoked->reason = *object.ptr; } - DBG2(DBG_LIB, " '%N'", crl_reason_names, + DBG2(DBG_ASN, " '%N'", crl_reason_names, revoked->reason); } break; @@ -324,7 +324,7 @@ static bool parse(private_x509_crl_t *this) if (critical && lib->settings->get_bool(lib->settings, "libstrongswan.x509.enforce_critical", TRUE)) { - DBG1(DBG_LIB, "critical '%s' extension not supported", + DBG1(DBG_ASN, "critical '%s' extension not supported", (extn_oid == OID_UNKNOWN) ? "unknown" : (char*)oid_names[extn_oid].name); goto end; @@ -338,7 +338,7 @@ static bool parse(private_x509_crl_t *this) this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); if (this->algorithm != sig_alg) { - DBG1(DBG_LIB, " signature algorithms do not agree"); + DBG1(DBG_ASN, " signature algorithms do not agree"); goto end; } break; diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c index 23b206fb1..7dfef3993 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_response.c +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c @@ -507,7 +507,7 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, if (version != OCSP_BASIC_RESPONSE_VERSION) { - DBG1(DBG_LIB, " ocsp ResponseData version %d not " + DBG1(DBG_ASN, " ocsp ResponseData version %d not " "supported", version); goto end; } @@ -516,12 +516,12 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, case BASIC_RESPONSE_ID_BY_NAME: this->responderId = identification_create_from_encoding( ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " '%Y'", this->responderId); + DBG2(DBG_ASN, " '%Y'", this->responderId); break; case BASIC_RESPONSE_ID_BY_KEY: this->responderId = identification_create_from_encoding( ID_KEY_ID, object); - DBG2(DBG_LIB, " '%Y'", this->responderId); + DBG2(DBG_ASN, " '%Y'", this->responderId); break; case BASIC_RESPONSE_PRODUCED_AT: this->producedAt = asn1_to_time(&object, ASN1_GENERALIZEDTIME); @@ -535,7 +535,7 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, break; case BASIC_RESPONSE_CRITICAL: critical = object.len && *object.ptr; - DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE"); + DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE"); break; case BASIC_RESPONSE_EXT_VALUE: if (extn_oid == OID_NONCE) diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.c b/src/libstrongswan/plugins/x509/x509_pkcs10.c index a19a3998a..ca08db2c6 100644 --- a/src/libstrongswan/plugins/x509/x509_pkcs10.c +++ b/src/libstrongswan/plugins/x509/x509_pkcs10.c @@ -276,7 +276,7 @@ static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, i break; case PKCS10_EXTN_CRITICAL: critical = object.len && *object.ptr; - DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE"); + DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE"); break; case PKCS10_EXTN_VALUE: { @@ -309,25 +309,25 @@ static bool parse_challengePassword(private_x509_pkcs10_t *this, chunk_t blob, i if (blob.len < 2) { - DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object smaller " + DBG1(DBG_ASN, "L%d - challengePassword: ASN.1 object smaller " "than 2 octets", level); return FALSE; } tag = *blob.ptr; if (tag < ASN1_UTF8STRING || tag > ASN1_IA5STRING) { - DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object is not " + DBG1(DBG_ASN, "L%d - challengePassword: ASN.1 object is not " "a character string", level); return FALSE; } if (asn1_length(&blob) == ASN1_INVALID_LENGTH) { - DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object has an " + DBG1(DBG_ASN, "L%d - challengePassword: ASN.1 object has an " "invalid length", level); return FALSE; } - DBG2(DBG_LIB, "L%d - challengePassword:", level); - DBG4(DBG_LIB, " '%.*s'", blob.len, blob.ptr); + DBG2(DBG_ASN, "L%d - challengePassword:", level); + DBG4(DBG_ASN, " '%.*s'", blob.len, blob.ptr); return TRUE; } @@ -385,14 +385,14 @@ static bool parse_certificate_request(private_x509_pkcs10_t *this) case PKCS10_VERSION: if (object.len > 0 && *object.ptr != 0) { - DBG1(DBG_LIB, "PKCS#10 certificate request format is " + DBG1(DBG_ASN, "PKCS#10 certificate request format is " "not version 1"); goto end; } break; case PKCS10_SUBJECT: this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " '%Y'", this->subject); + DBG2(DBG_ASN, " '%Y'", this->subject); break; case PKCS10_SUBJECT_PUBLIC_KEY_INFO: this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, diff --git a/src/libstrongswan/processing/processor.c b/src/libstrongswan/processing/processor.c index be33fcd84..222f1a535 100644 --- a/src/libstrongswan/processing/processor.c +++ b/src/libstrongswan/processing/processor.c @@ -102,7 +102,7 @@ static void restart(private_processor_t *this) { thread_t *thread; - DBG2(DBG_JOB, "terminated worker thread, ID: %u", thread_current_id()); + DBG2(DBG_JOB, "terminated worker thread %.2u", thread_current_id()); /* respawn thread if required */ this->mutex->lock(this->mutex); @@ -152,7 +152,7 @@ static void process_jobs(private_processor_t *this) /* worker threads are not cancellable by default */ thread_cancelability(FALSE); - DBG2(DBG_JOB, "started worker thread, ID: %u", thread_current_id()); + DBG2(DBG_JOB, "started worker thread %.2u", thread_current_id()); this->mutex->lock(this->mutex); while (this->desired_threads >= this->total_threads) @@ -230,7 +230,7 @@ METHOD(processor_t, get_idle_threads, u_int, */ static job_priority_t sane_prio(job_priority_t prio) { - if (prio < 0 || prio >= JOB_PRIO_MAX) + if ((int)prio < 0 || prio >= JOB_PRIO_MAX) { return JOB_PRIO_MAX - 1; } diff --git a/src/libstrongswan/threading/thread.c b/src/libstrongswan/threading/thread.c index 5b6f0d2ce..49a1b8430 100644 --- a/src/libstrongswan/threading/thread.c +++ b/src/libstrongswan/threading/thread.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2009-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,6 +18,19 @@ #include <signal.h> #include <semaphore.h> +#ifdef HAVE_GETTID +#include <sys/types.h> +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_GETTID +#include <sys/syscall.h> +static inline pid_t gettid() +{ + return syscall(SYS_gettid); +} +#endif + #include <library.h> #include <debug.h> @@ -278,6 +291,17 @@ static void *thread_main(private_thread_t *this) sem_wait(&this->created); current_thread->set(current_thread, this); pthread_cleanup_push((thread_cleanup_t)thread_cleanup, this); + + /* TODO: this is not 100% portable as pthread_t is an opaque type (i.e. + * could be of any size, or even a struct) */ +#ifdef HAVE_GETTID + DBG2(DBG_LIB, "created thread %.2d [%u]", + this->id, gettid()); +#else + DBG2(DBG_LIB, "created thread %.2d [%lx]", + this->id, (u_long)this->thread_id); +#endif + res = this->main(this->arg); pthread_cleanup_pop(TRUE); @@ -414,12 +438,20 @@ void thread_exit(void *val) } /** + * A dummy thread value that reserved pthread_key_t value "0". A buggy PKCS#11 + * library mangles this key, without owning it, so we allocate it for them. + */ +static thread_value_t *dummy1; + +/** * Described in header. */ void threads_init() { private_thread_t *main_thread = thread_create_internal(); + dummy1 = thread_value_create(NULL); + main_thread->id = 0; main_thread->thread_id = pthread_self(); current_thread = thread_value_create(NULL); @@ -443,6 +475,8 @@ void threads_deinit() { private_thread_t *main_thread = (private_thread_t*)thread_current(); + dummy1->destroy(dummy1); + main_thread->mutex->lock(main_thread->mutex); thread_destroy(main_thread); current_thread->destroy(current_thread); diff --git a/src/libstrongswan/utils.c b/src/libstrongswan/utils.c index 2fe7f653c..5a104de7f 100644 --- a/src/libstrongswan/utils.c +++ b/src/libstrongswan/utils.c @@ -344,6 +344,28 @@ bool ref_put(refcount_t *ref) pthread_mutex_unlock(&ref_mutex); return !more_refs; } + +/** + * Single mutex for all compare and swap operations. + */ +static pthread_mutex_t cas_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * Compare and swap if equal to old value + */ +#define _cas_impl(name, type) \ +bool cas_##name(type *ptr, type oldval, type newval) \ +{ \ + bool swapped; \ + pthread_mutex_lock(&cas_mutex); \ + if ((swapped = (*ptr == oldval))) { *ptr = newval; } \ + pthread_mutex_unlock(&cas_mutex); \ + return swapped; \ +} + +_cas_impl(bool, bool) +_cas_impl(ptr, void*) + #endif /* HAVE_GCC_ATOMIC_OPERATIONS */ /** diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index e5e4a10c0..367b3e37c 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -579,6 +579,11 @@ typedef volatile u_int refcount_t; #define ref_get(ref) {__sync_fetch_and_add(ref, 1); } #define ref_put(ref) (!__sync_sub_and_fetch(ref, 1)) +#define cas_bool(ptr, oldval, newval) \ + (__sync_bool_compare_and_swap(ptr, oldval, newval)) +#define cas_ptr(ptr, oldval, newval) \ + (__sync_bool_compare_and_swap(ptr, oldval, newval)) + #else /* !HAVE_GCC_ATOMIC_OPERATIONS */ /** @@ -601,6 +606,27 @@ void ref_get(refcount_t *ref); */ bool ref_put(refcount_t *ref); +/** + * Atomically replace value of ptr with newval if it currently equals oldval. + * + * @param ptr pointer to variable + * @param oldval old value of the variable + * @param newval new value set if possible + * @return TRUE if value equaled oldval and newval was written + */ +bool cas_bool(bool *ptr, bool oldval, bool newval); + +/** + * Atomically replace value of ptr with newval if it currently equals oldval. + * + * @param ptr pointer to variable + * @param oldval old value of the variable + * @param newval new value set if possible + * @return TRUE if value equaled oldval and newval was written + */ +bool cas_ptr(void **ptr, void *oldval, void *newval); + + #endif /* HAVE_GCC_ATOMIC_OPERATIONS */ /** diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 93cc027de..0a8789335 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -194,6 +194,7 @@ char *whitelist[] = { "__pthread_setspecific", /* glibc functions */ "mktime", + "ctime", "__gmtime_r", "localtime_r", "tzset", diff --git a/src/libtls/Makefile.am b/src/libtls/Makefile.am index 36335e84b..4cc1a1bdb 100644 --- a/src/libtls/Makefile.am +++ b/src/libtls/Makefile.am @@ -11,6 +11,7 @@ libtls_la_SOURCES = \ tls_prf.h tls_prf.c \ tls_socket.h tls_socket.c \ tls_eap.h tls_eap.c \ + tls_cache.h tls_cache.c \ tls_peer.h tls_peer.c \ tls_server.h tls_server.c \ tls_handshake.h tls_application.h tls.h tls.c diff --git a/src/libtls/tls.c b/src/libtls/tls.c index 3941bea26..2bcaffbc8 100644 --- a/src/libtls/tls.c +++ b/src/libtls/tls.c @@ -437,7 +437,7 @@ METHOD(tls_t, destroy, void, */ tls_t *tls_create(bool is_server, identification_t *server, identification_t *peer, tls_purpose_t purpose, - tls_application_t *application) + tls_application_t *application, tls_cache_t *cache) { private_tls_t *this; @@ -472,7 +472,7 @@ tls_t *tls_create(bool is_server, identification_t *server, .purpose = purpose, ); - this->crypto = tls_crypto_create(&this->public); + this->crypto = tls_crypto_create(&this->public, cache); this->alert = tls_alert_create(); if (is_server) { diff --git a/src/libtls/tls.h b/src/libtls/tls.h index 068ba542c..e22b0facc 100644 --- a/src/libtls/tls.h +++ b/src/libtls/tls.h @@ -35,6 +35,7 @@ typedef struct tls_t tls_t; #include <library.h> #include "tls_application.h" +#include "tls_cache.h" /** * TLS/SSL version numbers @@ -240,10 +241,11 @@ void libtls_init(void); * @param peer peer identity, NULL for no client authentication * @param purpose purpose this TLS stack instance is used for * @param application higher layer application or NULL if none + * @param cache session cache to use, or NULL * @return TLS stack */ tls_t *tls_create(bool is_server, identification_t *server, identification_t *peer, tls_purpose_t purpose, - tls_application_t *application); + tls_application_t *application, tls_cache_t *cache); #endif /** TLS_H_ @}*/ diff --git a/src/libtls/tls_cache.c b/src/libtls/tls_cache.c new file mode 100644 index 000000000..a89201ad7 --- /dev/null +++ b/src/libtls/tls_cache.c @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 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 "tls_cache.h" + +#include <debug.h> +#include <utils/linked_list.h> +#include <utils/hashtable.h> +#include <threading/rwlock.h> + +typedef struct private_tls_cache_t private_tls_cache_t; + +/** + * Private data of an tls_cache_t object. + */ +struct private_tls_cache_t { + + /** + * Public tls_cache_t interface. + */ + tls_cache_t public; + + /** + * Mapping session => entry_t, fast lookup by session + */ + hashtable_t *table; + + /** + * List containing all entries + */ + linked_list_t *list; + + /** + * Lock to list and table + */ + rwlock_t *lock; + + /** + * Session limit + */ + u_int max_sessions; + + /** + * maximum age of a session, in seconds + */ + u_int max_age; +}; + +/** + * Hashtable entry + */ +typedef struct { + /** session identifier */ + chunk_t session; + /** master secret */ + chunk_t master; + /** TLS cipher suite */ + tls_cipher_suite_t suite; + /** optional identity this entry is bound to */ + identification_t *id; + /** time of add */ + time_t t; +} entry_t; + +/** + * Destroy an entry + */ +static void entry_destroy(entry_t *entry) +{ + chunk_clear(&entry->session); + chunk_clear(&entry->master); + DESTROY_IF(entry->id); + free(entry); +} + +/** + * Hashtable hash function + */ +static u_int hash(chunk_t *key) +{ + return chunk_hash(*key); +} + +/** + * Hashtable equals function + */ +static bool equals(chunk_t *a, chunk_t *b) +{ + return chunk_equals(*a, *b); +} + +METHOD(tls_cache_t, create_, void, + private_tls_cache_t *this, chunk_t session, identification_t *id, + chunk_t master, tls_cipher_suite_t suite) +{ + entry_t *entry; + + INIT(entry, + .session = chunk_clone(session), + .master = chunk_clone(master), + .suite = suite, + .id = id ? id->clone(id) : NULL, + .t = time_monotonic(NULL), + ); + + this->lock->write_lock(this->lock); + this->list->insert_first(this->list, entry); + this->table->put(this->table, &entry->session, entry); + if (this->list->get_count(this->list) > this->max_sessions && + this->list->remove_last(this->list, (void**)&entry) == SUCCESS) + { + DBG2(DBG_TLS, "session limit of %u reached, deleting %#B", + this->max_sessions, &entry->session); + this->table->remove(this->table, &entry->session); + entry_destroy(entry); + } + this->lock->unlock(this->lock); + + DBG2(DBG_TLS, "created TLS session %#B, %d sessions", + &session, this->list->get_count(this->list)); +} + +METHOD(tls_cache_t, lookup, tls_cipher_suite_t, + private_tls_cache_t *this, chunk_t session, identification_t *id, + chunk_t* master) +{ + tls_cipher_suite_t suite = 0; + entry_t *entry; + time_t now; + u_int age; + + now = time_monotonic(NULL); + + this->lock->write_lock(this->lock); + entry = this->table->get(this->table, &session); + if (entry) + { + age = now - entry->t; + if (age <= this->max_age) + { + if (!id || !entry->id || id->equals(id, entry->id)) + { + *master = chunk_clone(entry->master); + suite = entry->suite; + } + } + else + { + DBG2(DBG_TLS, "TLS session %#B expired: %u seconds", &session, age); + } + } + this->lock->unlock(this->lock); + + if (suite) + { + DBG2(DBG_TLS, "resuming TLS session %#B, age %u seconds", &session, age); + } + return suite; +} + +METHOD(tls_cache_t, check, chunk_t, + private_tls_cache_t *this, identification_t *id) +{ + chunk_t session = chunk_empty; + enumerator_t *enumerator; + entry_t *entry; + time_t now; + + now = time_monotonic(NULL); + this->lock->read_lock(this->lock); + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->t + this->max_age >= now && + entry->id && id->equals(id, entry->id)) + { + session = chunk_clone(entry->session); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return session; +} + +METHOD(tls_cache_t, destroy, void, + private_tls_cache_t *this) +{ + entry_t *entry; + + while (this->list->remove_last(this->list, (void**)&entry) == SUCCESS) + { + entry_destroy(entry); + } + this->list->destroy(this->list); + this->table->destroy(this->table); + this->lock->destroy(this->lock); + free(this); +} + +/** + * See header + */ +tls_cache_t *tls_cache_create(u_int max_sessions, u_int max_age) +{ + private_tls_cache_t *this; + + INIT(this, + .public = { + .create = _create_, + .lookup = _lookup, + .check = _check, + .destroy = _destroy, + }, + .table = hashtable_create((hashtable_hash_t)hash, + (hashtable_equals_t)equals, 8), + .list = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .max_sessions = max_sessions, + .max_age = max_age, + ); + + return &this->public; +} diff --git a/src/libtls/tls_cache.h b/src/libtls/tls_cache.h new file mode 100644 index 000000000..ea4e2013e --- /dev/null +++ b/src/libtls/tls_cache.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 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 tls_cache tls_cache + * @{ @ingroup libtls + */ + +#ifndef TLS_CACHE_H_ +#define TLS_CACHE_H_ + +typedef struct tls_cache_t tls_cache_t; + +#include "tls_crypto.h" + +/** + * TLS session cache facility. + */ +struct tls_cache_t { + + /** + * Create a new TLS session entry. + * + * @param session session identifier + * @param id identity the session is bound to + * @param master TLS master secret + * @param suite TLS cipher suite of the session + */ + void (*create)(tls_cache_t *this, chunk_t session, identification_t *id, + chunk_t master, tls_cipher_suite_t suite); + + /** + * Look up a TLS session entry. + * + * @param session session ID to find + * @param id identity the session is bound to + * @param master gets allocated master secret, if session found + * @return TLS suite of session, 0 if none found + */ + tls_cipher_suite_t (*lookup)(tls_cache_t *this, chunk_t session, + identification_t *id, chunk_t* master); + + /** + * Check if we have a session for a given identity. + * + * @param id identity to check + * @return allocated session ID, or chunk_empty + */ + chunk_t (*check)(tls_cache_t *this, identification_t *id); + + /** + * Destroy a tls_cache_t. + */ + void (*destroy)(tls_cache_t *this); +}; + +/** + * Create a tls_cache instance. + * + * @param max_sessions maximum number of sessions to store + * @param max_age maximum age of a session, in seconds + * @return tls cache + */ +tls_cache_t *tls_cache_create(u_int max_sessions, u_int max_age); + +#endif /** TLS_CACHE_H_ @}*/ diff --git a/src/libtls/tls_compression.h b/src/libtls/tls_compression.h index b4832ab06..b2c60d5d6 100644 --- a/src/libtls/tls_compression.h +++ b/src/libtls/tls_compression.h @@ -23,12 +23,12 @@ #include <library.h> +typedef struct tls_compression_t tls_compression_t; + #include "tls.h" #include "tls_alert.h" #include "tls_fragmentation.h" -typedef struct tls_compression_t tls_compression_t; - /** * TLS record protocol compression layer. */ diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c index b9a5d6627..4d84876d0 100644 --- a/src/libtls/tls_crypto.c +++ b/src/libtls/tls_crypto.c @@ -370,6 +370,11 @@ struct private_tls_crypto_t { tls_t *tls; /** + * TLS session cache + */ + tls_cache_t *cache; + + /** * All handshake data concatentated */ chunk_t handshake; @@ -437,7 +442,7 @@ typedef struct { static suite_algs_t suite_algs[] = { { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, @@ -447,7 +452,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, KEY_ECDSA, ECP_384_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, @@ -457,7 +462,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, KEY_RSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, @@ -467,7 +472,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, KEY_RSA, ECP_384_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, @@ -477,7 +482,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, KEY_RSA, MODP_2048_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256,PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, @@ -487,7 +492,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, KEY_RSA, MODP_3072_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, @@ -497,7 +502,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, KEY_RSA, MODP_2048_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16 }, { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, @@ -507,7 +512,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, KEY_RSA, MODP_3072_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32 }, { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, @@ -517,12 +522,12 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, KEY_RSA, MODP_2048_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_RSA_WITH_AES_128_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_RSA_WITH_AES_128_CBC_SHA256, @@ -532,7 +537,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_RSA_WITH_AES_256_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_RSA_WITH_AES_256_CBC_SHA256, @@ -542,7 +547,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16 }, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, @@ -552,7 +557,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32 }, { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, @@ -562,32 +567,32 @@ static suite_algs_t suite_algs[] = { }, { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, KEY_RSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_RSA_WITH_3DES_EDE_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_ECDHE_ECDSA_WITH_NULL_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_NULL, 0 }, { TLS_ECDHE_RSA_WITH_NULL_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_NULL, 0 }, { TLS_RSA_WITH_NULL_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_NULL, 0 }, { TLS_RSA_WITH_NULL_SHA256, @@ -597,7 +602,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_RSA_WITH_NULL_MD5, KEY_RSA, MODP_NONE, - HASH_MD5, PRF_HMAC_MD5, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_MD5_128, ENCR_NULL, 0 }, }; @@ -834,25 +839,25 @@ static void filter_mac_config_suites(private_tls_crypto_t *this, while (enumerator->enumerate(enumerator, &token)) { if (strcaseeq(token, "md5") && - suites[i].hash == HASH_MD5) + suites[i].mac == AUTH_HMAC_MD5_128) { suites[remaining++] = suites[i]; break; } if (strcaseeq(token, "sha1") && - suites[i].hash == HASH_SHA1) + suites[i].mac == AUTH_HMAC_SHA1_160) { suites[remaining++] = suites[i]; break; } if (strcaseeq(token, "sha256") && - suites[i].hash == HASH_SHA256) + suites[i].mac == AUTH_HMAC_SHA2_256_256) { suites[remaining++] = suites[i]; break; } if (strcaseeq(token, "sha384") && - suites[i].hash == HASH_SHA384) + suites[i].mac == AUTH_HMAC_SHA2_384_384) { suites[remaining++] = suites[i]; break; @@ -1462,13 +1467,15 @@ METHOD(tls_crypto_t, calculate_finished, bool, return TRUE; } -METHOD(tls_crypto_t, derive_secrets, void, - private_tls_crypto_t *this, chunk_t premaster, - chunk_t client_random, chunk_t server_random) +/** + * Derive master secret from premaster, optionally save session + */ +static void derive_master(private_tls_crypto_t *this, chunk_t premaster, + chunk_t session, identification_t *id, + chunk_t client_random, chunk_t server_random) { char master[48]; - chunk_t seed, block, client_write, server_write; - int mks, eks = 0, ivs = 0; + chunk_t seed; /* derive master secret */ seed = chunk_cata("cc", client_random, server_random); @@ -1477,7 +1484,22 @@ METHOD(tls_crypto_t, derive_secrets, void, sizeof(master), master); this->prf->set_key(this->prf, chunk_from_thing(master)); - memset(master, 0, sizeof(master)); + if (this->cache && session.len) + { + this->cache->create(this->cache, session, id, chunk_from_thing(master), + this->suite); + } + memwipe(master, sizeof(master)); +} + +/** + * Expand key material from master secret + */ +static void expand_keys(private_tls_crypto_t *this, + chunk_t client_random, chunk_t server_random) +{ + chunk_t seed, block, client_write, server_write; + int mks, eks = 0, ivs = 0; /* derive key block for key expansion */ mks = this->signer_out->get_key_size(this->signer_out); @@ -1546,6 +1568,57 @@ METHOD(tls_crypto_t, derive_secrets, void, } } } + + /* EAP-MSK */ + if (this->msk_label) + { + seed = chunk_cata("cc", client_random, server_random); + this->msk = chunk_alloc(64); + this->prf->get_bytes(this->prf, this->msk_label, seed, + this->msk.len, this->msk.ptr); + } +} + +METHOD(tls_crypto_t, derive_secrets, void, + private_tls_crypto_t *this, chunk_t premaster, chunk_t session, + identification_t *id, chunk_t client_random, chunk_t server_random) +{ + derive_master(this, premaster, session, id, client_random, server_random); + expand_keys(this, client_random, server_random); +} + +METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t, + private_tls_crypto_t *this, chunk_t session, identification_t *id, + chunk_t client_random, chunk_t server_random) +{ + chunk_t master; + + if (this->cache && session.len) + { + this->suite = this->cache->lookup(this->cache, session, id, &master); + if (this->suite) + { + this->suite = select_cipher_suite(this, &this->suite, 1, KEY_ANY); + if (this->suite) + { + this->prf->set_key(this->prf, master); + expand_keys(this, client_random, server_random); + } + chunk_clear(&master); + } + return this->suite; + } + return 0; +} + +METHOD(tls_crypto_t, get_session, chunk_t, + private_tls_crypto_t *this, identification_t *server) +{ + if (this->cache) + { + return this->cache->check(this->cache, server); + } + return chunk_empty; } METHOD(tls_crypto_t, change_cipher, void, @@ -1566,21 +1639,6 @@ METHOD(tls_crypto_t, change_cipher, void, } } -METHOD(tls_crypto_t, derive_eap_msk, void, - private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random) -{ - if (this->msk_label) - { - chunk_t seed; - - seed = chunk_cata("cc", client_random, server_random); - free(this->msk.ptr); - this->msk = chunk_alloc(64); - this->prf->get_bytes(this->prf, this->msk_label, seed, - this->msk.len, this->msk.ptr); - } -} - METHOD(tls_crypto_t, get_eap_msk, chunk_t, private_tls_crypto_t *this) { @@ -1606,7 +1664,7 @@ METHOD(tls_crypto_t, destroy, void, /** * See header */ -tls_crypto_t *tls_crypto_create(tls_t *tls) +tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache) { private_tls_crypto_t *this; enumerator_t *enumerator; @@ -1628,12 +1686,14 @@ tls_crypto_t *tls_crypto_create(tls_t *tls) .verify_handshake = _verify_handshake, .calculate_finished = _calculate_finished, .derive_secrets = _derive_secrets, + .resume_session = _resume_session, + .get_session = _get_session, .change_cipher = _change_cipher, - .derive_eap_msk = _derive_eap_msk, .get_eap_msk = _get_eap_msk, .destroy = _destroy, }, .tls = tls, + .cache = cache, ); enumerator = lib->creds->create_builder_enumerator(lib->creds); diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h index 35c9b6e05..7430aea66 100644 --- a/src/libtls/tls_crypto.h +++ b/src/libtls/tls_crypto.h @@ -54,13 +54,13 @@ enum tls_cipher_suite_t { TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008, TLS_RSA_WITH_DES_CBC_SHA = 0x0009, TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, - TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B, + TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B, TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C, TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D, TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E, - TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F, + TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F, TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010, - TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011, + TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011, TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012, TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013, TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014, @@ -110,7 +110,7 @@ enum tls_cipher_suite_t { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041, TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042, TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044, + TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044, TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045, TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046, @@ -126,8 +126,8 @@ enum tls_cipher_suite_t { TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085, TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086, TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088, - TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089, + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088, + TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089, TLS_PSK_WITH_RC4_128_SHA = 0x008A, TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B, TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C, @@ -511,27 +511,43 @@ struct tls_crypto_t { * Derive the master secret, MAC and encryption keys. * * @param premaster premaster secret + * @param session session identifier to cache master secret + * @param id identity the session is bound to * @param client_random random data from client hello * @param server_random random data from server hello */ void (*derive_secrets)(tls_crypto_t *this, chunk_t premaster, + chunk_t session, identification_t *id, chunk_t client_random, chunk_t server_random); /** - * Change the cipher used at protection layer. + * Try to resume a TLS session, derive key material. * - * @param inbound TRUE to change inbound cipher, FALSE for outbound + * @param session session identifier + * @param id identity the session is bound to + * @param client_random random data from client hello + * @param server_random random data from server hello + * @return selected suite */ - void (*change_cipher)(tls_crypto_t *this, bool inbound); + tls_cipher_suite_t (*resume_session)(tls_crypto_t *this, chunk_t session, + identification_t *id, + chunk_t client_random, + chunk_t server_random); /** - * Derive the EAP-TLS MSK. + * Check if we have a session to resume as a client. * - * @param client_random random data from client hello - * @param server_random random data from server hello + * @param id server identity to get a session for + * @return allocated session identifier, or chunk_empty */ - void (*derive_eap_msk)(tls_crypto_t *this, - chunk_t client_random, chunk_t server_random); + chunk_t (*get_session)(tls_crypto_t *this, identification_t *id); + + /** + * Change the cipher used at protection layer. + * + * @param inbound TRUE to change inbound cipher, FALSE for outbound + */ + void (*change_cipher)(tls_crypto_t *this, bool inbound); /** * Get the MSK to use in EAP-TLS. @@ -548,7 +564,11 @@ struct tls_crypto_t { /** * Create a tls_crypto instance. + * + * @param tls TLS stack + * @param cache TLS session cache + * @return TLS crypto helper */ -tls_crypto_t *tls_crypto_create(tls_t *tls); +tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache); #endif /** TLS_CRYPTO_H_ @}*/ diff --git a/src/libtls/tls_fragmentation.c b/src/libtls/tls_fragmentation.c index c42c16fb8..62e36aaec 100644 --- a/src/libtls/tls_fragmentation.c +++ b/src/libtls/tls_fragmentation.c @@ -251,8 +251,9 @@ METHOD(tls_fragmentation_t, process, status_t, switch (type) { case TLS_CHANGE_CIPHER_SPEC: - if (this->handshake->change_cipherspec(this->handshake)) + if (this->handshake->cipherspec_changed(this->handshake, TRUE)) { + this->handshake->change_cipherspec(this->handshake, TRUE); status = NEED_MORE; break; } @@ -324,8 +325,12 @@ static status_t build_handshake(private_tls_fragmentation_t *this) msg->write_data24(msg, hs->get_buf(hs)); DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)", tls_handshake_type_names, type, hs->get_buf(hs).len); - hs->destroy(hs); - continue; + if (!this->handshake->cipherspec_changed(this->handshake, FALSE)) + { + hs->destroy(hs); + continue; + } + /* FALL */ case INVALID_STATE: this->output_type = TLS_HANDSHAKE; this->output = chunk_clone(msg->get_buf(msg)); @@ -397,8 +402,9 @@ METHOD(tls_fragmentation_t, build, status_t, } if (!this->output.len) { - if (this->handshake->cipherspec_changed(this->handshake)) + if (this->handshake->cipherspec_changed(this->handshake, FALSE)) { + this->handshake->change_cipherspec(this->handshake, FALSE); *type = TLS_CHANGE_CIPHER_SPEC; *data = chunk_clone(chunk_from_chars(0x01)); return NEED_MORE; diff --git a/src/libtls/tls_fragmentation.h b/src/libtls/tls_fragmentation.h index d80278916..f650e7be8 100644 --- a/src/libtls/tls_fragmentation.h +++ b/src/libtls/tls_fragmentation.h @@ -23,12 +23,12 @@ #include <library.h> +typedef struct tls_fragmentation_t tls_fragmentation_t; + #include "tls.h" #include "tls_alert.h" #include "tls_handshake.h" -typedef struct tls_fragmentation_t tls_fragmentation_t; - /** * TLS record protocol fragmentation layer. */ diff --git a/src/libtls/tls_handshake.h b/src/libtls/tls_handshake.h index 4f6af2a54..bea0024eb 100644 --- a/src/libtls/tls_handshake.h +++ b/src/libtls/tls_handshake.h @@ -62,18 +62,19 @@ struct tls_handshake_t { tls_handshake_type_t *type, bio_writer_t *writer); /** - * Check if the cipher spec for outgoing messages has changed. + * Check if the cipher spec should be changed for outgoing messages. * - * @return TRUE if cipher spec changed + * @param inbound TRUE to check for inbound cipherspec change + * @return TRUE if cipher spec should be changed */ - bool (*cipherspec_changed)(tls_handshake_t *this); + bool (*cipherspec_changed)(tls_handshake_t *this, bool inbound); /** - * Change the cipher spec for incoming messages. + * Change the cipher for a direction. * - * @return TRUE if cipher spec changed + * @param inbound TRUE to change inbound cipherspec, FALSE for outbound */ - bool (*change_cipherspec)(tls_handshake_t *this); + void (*change_cipherspec)(tls_handshake_t *this, bool inbound); /** * Check if the finished message was decoded successfully. diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c index d3b5ff0aa..6091702cf 100644 --- a/src/libtls/tls_peer.c +++ b/src/libtls/tls_peer.c @@ -36,7 +36,7 @@ typedef enum { STATE_CIPHERSPEC_CHANGED_OUT, STATE_FINISHED_SENT, STATE_CIPHERSPEC_CHANGED_IN, - STATE_COMPLETE, + STATE_FINISHED_RECEIVED, } peer_state_t; /** @@ -110,6 +110,16 @@ struct private_tls_peer_t { diffie_hellman_t *dh; /** + * Resuming a session? + */ + bool resume; + + /** + * TLS session identifier + */ + chunk_t session; + + /** * List of server-supported hashsig algorithms */ chunk_t hashsig; @@ -129,7 +139,7 @@ static status_t process_server_hello(private_tls_peer_t *this, u_int8_t compression; u_int16_t version, cipher; chunk_t random, session, ext = chunk_empty; - tls_cipher_suite_t suite; + tls_cipher_suite_t suite = 0; this->crypto->append_handshake(this->crypto, TLS_SERVER_HELLO, reader->peek(reader)); @@ -155,16 +165,34 @@ static status_t process_server_hello(private_tls_peer_t *this, this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION); return NEED_MORE; } - suite = cipher; - if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY)) + + if (chunk_equals(this->session, session)) { - DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable", - tls_cipher_suite_names, suite); - this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); - return NEED_MORE; + suite = this->crypto->resume_session(this->crypto, session, this->server, + chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random)); + if (suite) + { + DBG1(DBG_TLS, "resumed %N using suite %N", + tls_version_names, version, tls_cipher_suite_names, suite); + this->resume = TRUE; + } + } + if (!suite) + { + suite = cipher; + if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY)) + { + DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable", + tls_cipher_suite_names, suite); + this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); + return NEED_MORE; + } + DBG1(DBG_TLS, "negotiated %N using suite %N", + tls_version_names, version, tls_cipher_suite_names, suite); + free(this->session.ptr); + this->session = chunk_clone(session); } - DBG1(DBG_TLS, "negotiated TLS version %N with suite %N", - tls_version_names, version, tls_cipher_suite_names, suite); this->state = STATE_HELLO_RECEIVED; return NEED_MORE; } @@ -599,10 +627,9 @@ static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader) this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR); return NEED_MORE; } - this->state = STATE_COMPLETE; - this->crypto->derive_eap_msk(this->crypto, - chunk_from_thing(this->client_random), - chunk_from_thing(this->server_random)); + this->state = STATE_FINISHED_RECEIVED; + this->crypto->append_handshake(this->crypto, TLS_FINISHED, received); + return NEED_MORE; } @@ -696,8 +723,9 @@ static status_t send_client_hello(private_tls_peer_t *this, writer->write_uint16(writer, version); writer->write_data(writer, chunk_from_thing(this->client_random)); - /* session identifier => none */ - writer->write_data8(writer, chunk_empty); + /* session identifier */ + this->session = this->crypto->get_session(this->crypto, this->server); + writer->write_data8(writer, this->session); /* add TLS cipher suites */ count = this->crypto->get_cipher_suites(this->crypto, &suites); @@ -886,6 +914,7 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this, htoun16(premaster, TLS_1_2); this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), + this->session, this->server, chunk_from_thing(this->client_random), chunk_from_thing(this->server_random)); @@ -930,6 +959,7 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this, return NEED_MORE; } this->crypto->derive_secrets(this->crypto, premaster, + this->session, this->server, chunk_from_thing(this->client_random), chunk_from_thing(this->server_random)); chunk_clear(&premaster); @@ -1042,34 +1072,52 @@ METHOD(tls_handshake_t, build, status_t, } METHOD(tls_handshake_t, cipherspec_changed, bool, - private_tls_peer_t *this) + private_tls_peer_t *this, bool inbound) { - if ((this->peer && this->state == STATE_VERIFY_SENT) || - (!this->peer && this->state == STATE_KEY_EXCHANGE_SENT)) + if (inbound) { - this->crypto->change_cipher(this->crypto, FALSE); - this->state = STATE_CIPHERSPEC_CHANGED_OUT; - return TRUE; + if (this->resume) + { + return this->state == STATE_HELLO_RECEIVED; + } + return this->state == STATE_FINISHED_SENT; + } + else + { + if (this->resume) + { + return this->state == STATE_FINISHED_RECEIVED; + } + if (this->peer) + { + return this->state == STATE_VERIFY_SENT; + } + return this->state == STATE_KEY_EXCHANGE_SENT; } - return FALSE; } -METHOD(tls_handshake_t, change_cipherspec, bool, - private_tls_peer_t *this) +METHOD(tls_handshake_t, change_cipherspec, void, + private_tls_peer_t *this, bool inbound) { - if (this->state == STATE_FINISHED_SENT) + this->crypto->change_cipher(this->crypto, inbound); + if (inbound) { - this->crypto->change_cipher(this->crypto, TRUE); this->state = STATE_CIPHERSPEC_CHANGED_IN; - return TRUE; } - return FALSE; + else + { + this->state = STATE_CIPHERSPEC_CHANGED_OUT; + } } METHOD(tls_handshake_t, finished, bool, private_tls_peer_t *this) { - return this->state == STATE_COMPLETE; + if (this->resume) + { + return this->state == STATE_FINISHED_SENT; + } + return this->state == STATE_FINISHED_RECEIVED; } METHOD(tls_handshake_t, destroy, void, @@ -1081,6 +1129,7 @@ METHOD(tls_handshake_t, destroy, void, this->server_auth->destroy(this->server_auth); free(this->hashsig.ptr); free(this->cert_types.ptr); + free(this->session.ptr); free(this); } diff --git a/src/libtls/tls_protection.h b/src/libtls/tls_protection.h index 99c94e935..05cf3df45 100644 --- a/src/libtls/tls_protection.h +++ b/src/libtls/tls_protection.h @@ -23,12 +23,12 @@ #include <library.h> +typedef struct tls_protection_t tls_protection_t; + #include "tls.h" #include "tls_alert.h" #include "tls_compression.h" -typedef struct tls_protection_t tls_protection_t; - /** * TLS record protocol protection layer. */ diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c index b8b67adf4..e3617dc9a 100644 --- a/src/libtls/tls_server.c +++ b/src/libtls/tls_server.c @@ -22,6 +22,10 @@ typedef struct private_tls_server_t private_tls_server_t; +/** + * Size of a session ID + */ +#define SESSION_ID_SIZE 16 typedef enum { STATE_INIT, @@ -121,6 +125,16 @@ struct private_tls_server_t { tls_version_t client_version; /** + * TLS session identifier + */ + chunk_t session; + + /** + * Do we resume a session? + */ + bool resume; + + /** * Hash and signature algorithms supported by peer */ chunk_t hashsig; @@ -199,6 +213,7 @@ static status_t process_client_hello(private_tls_server_t *this, bio_reader_t *extensions; tls_cipher_suite_t *suites; int count, i; + rng_t *rng; this->crypto->append_handshake(this->crypto, TLS_CLIENT_HELLO, reader->peek(reader)); @@ -228,7 +243,7 @@ static status_t process_client_hello(private_tls_server_t *this, extensions->destroy(extensions); return NEED_MORE; } - DBG1(DBG_TLS, "received TLS '%N' extension", + DBG2(DBG_TLS, "received TLS '%N' extension", tls_extension_names, extension); DBG3(DBG_TLS, "%B", &ext); switch (extension) @@ -249,6 +264,17 @@ static status_t process_client_hello(private_tls_server_t *this, memcpy(this->client_random, random.ptr, sizeof(this->client_random)); + htoun32(&this->server_random, time(NULL)); + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_TLS, "no suitable RNG found to generate server random"); + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + return NEED_MORE; + } + rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4); + rng->destroy(rng); + if (!this->tls->set_version(this->tls, version)) { DBG1(DBG_TLS, "negotiated version %N not supported", @@ -256,24 +282,44 @@ static status_t process_client_hello(private_tls_server_t *this, this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION); return NEED_MORE; } - count = ciphers.len / sizeof(u_int16_t); - suites = alloca(count * sizeof(tls_cipher_suite_t)); - DBG2(DBG_TLS, "received %d TLS cipher suites:", count); - for (i = 0; i < count; i++) + + this->client_version = version; + this->suite = this->crypto->resume_session(this->crypto, session, this->peer, + chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random)); + if (this->suite) { - suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]); - DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]); + this->session = chunk_clone(session); + this->resume = TRUE; + DBG1(DBG_TLS, "resumed %N using suite %N", + tls_version_names, this->tls->get_version(this->tls), + tls_cipher_suite_names, this->suite); } - - if (!select_suite_and_key(this, suites, count)) + else { - this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); - return NEED_MORE; + count = ciphers.len / sizeof(u_int16_t); + suites = alloca(count * sizeof(tls_cipher_suite_t)); + DBG2(DBG_TLS, "received %d TLS cipher suites:", count); + for (i = 0; i < count; i++) + { + suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]); + DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]); + } + if (!select_suite_and_key(this, suites, count)) + { + this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); + return NEED_MORE; + } + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + if (rng) + { + rng->allocate_bytes(rng, SESSION_ID_SIZE, &this->session); + rng->destroy(rng); + } + DBG1(DBG_TLS, "negotiated %N using suite %N", + tls_version_names, this->tls->get_version(this->tls), + tls_cipher_suite_names, this->suite); } - DBG1(DBG_TLS, "negotiated TLS version %N with suite %N", - tls_version_names, this->tls->get_version(this->tls), - tls_cipher_suite_names, this->suite); - this->client_version = version; this->state = STATE_HELLO_RECEIVED; return NEED_MORE; } @@ -391,6 +437,7 @@ static status_t process_key_exchange_encrypted(private_tls_server_t *this, } this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), + this->session, this->peer, chunk_from_thing(this->client_random), chunk_from_thing(this->server_random)); @@ -439,6 +486,7 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this, } this->crypto->derive_secrets(this->crypto, premaster, + this->session, this->peer, chunk_from_thing(this->client_random), chunk_from_thing(this->server_random)); chunk_clear(&premaster); @@ -576,10 +624,7 @@ METHOD(tls_handshake_t, process, status_t, expected = TLS_CERTIFICATE_VERIFY; break; } - else - { - return INVALID_STATE; - } + return INVALID_STATE; case STATE_CIPHERSPEC_CHANGED_IN: if (type == TLS_FINISHED) { @@ -605,27 +650,12 @@ METHOD(tls_handshake_t, process, status_t, static status_t send_server_hello(private_tls_server_t *this, tls_handshake_type_t *type, bio_writer_t *writer) { - tls_version_t version; - rng_t *rng; - - htoun32(&this->server_random, time(NULL)); - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) - { - DBG1(DBG_TLS, "no suitable RNG found to generate server random"); - this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); - return FAILED; - } - rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4); - rng->destroy(rng); - /* TLS version */ - version = this->tls->get_version(this->tls); - writer->write_uint16(writer, version); + writer->write_uint16(writer, this->tls->get_version(this->tls)); writer->write_data(writer, chunk_from_thing(this->server_random)); - /* session identifier => none, we don't support session resumption */ - writer->write_data8(writer, chunk_empty); + /* session identifier if we have one */ + writer->write_data8(writer, this->session); /* add selected TLS cipher suite */ writer->write_uint16(writer, this->suite); @@ -914,9 +944,8 @@ static status_t send_finished(private_tls_server_t *this, *type = TLS_FINISHED; this->state = STATE_FINISHED_SENT; - this->crypto->derive_eap_msk(this->crypto, - chunk_from_thing(this->client_random), - chunk_from_thing(this->server_random)); + this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); + return NEED_MORE; } @@ -956,33 +985,52 @@ METHOD(tls_handshake_t, build, status_t, } METHOD(tls_handshake_t, cipherspec_changed, bool, - private_tls_server_t *this) + private_tls_server_t *this, bool inbound) { - if (this->state == STATE_FINISHED_RECEIVED) + if (inbound) { - this->crypto->change_cipher(this->crypto, FALSE); - this->state = STATE_CIPHERSPEC_CHANGED_OUT; - return TRUE; + if (this->resume) + { + return this->state == STATE_FINISHED_SENT; + } + if (this->peer) + { + return this->state == STATE_CERT_VERIFY_RECEIVED; + } + return this->state == STATE_KEY_EXCHANGE_RECEIVED; + } + else + { + if (this->resume) + { + return this->state == STATE_HELLO_SENT; + } + return this->state == STATE_FINISHED_RECEIVED; } return FALSE; } -METHOD(tls_handshake_t, change_cipherspec, bool, - private_tls_server_t *this) +METHOD(tls_handshake_t, change_cipherspec, void, + private_tls_server_t *this, bool inbound) { - if ((this->peer && this->state == STATE_CERT_VERIFY_RECEIVED) || - (!this->peer && this->state == STATE_KEY_EXCHANGE_RECEIVED)) + this->crypto->change_cipher(this->crypto, inbound); + if (inbound) { - this->crypto->change_cipher(this->crypto, TRUE); this->state = STATE_CIPHERSPEC_CHANGED_IN; - return TRUE; } - return FALSE; + else + { + this->state = STATE_CIPHERSPEC_CHANGED_OUT; + } } METHOD(tls_handshake_t, finished, bool, private_tls_server_t *this) { + if (this->resume) + { + return this->state == STATE_FINISHED_RECEIVED; + } return this->state == STATE_FINISHED_SENT; } @@ -995,6 +1043,7 @@ METHOD(tls_handshake_t, destroy, void, this->server_auth->destroy(this->server_auth); free(this->hashsig.ptr); free(this->curves.ptr); + free(this->session.ptr); free(this); } diff --git a/src/libtls/tls_socket.c b/src/libtls/tls_socket.c index 691a8e79f..3abff596d 100644 --- a/src/libtls/tls_socket.c +++ b/src/libtls/tls_socket.c @@ -16,8 +16,20 @@ #include "tls_socket.h" #include <unistd.h> +#include <errno.h> #include <debug.h> +#include <threading/thread.h> + +/** + * Buffer size for plain side I/O + */ +#define PLAIN_BUF_SIZE 4096 + +/** + * Buffer size for encrypted side I/O + */ +#define CRYPTO_BUF_SIZE 4096 typedef struct private_tls_socket_t private_tls_socket_t; typedef struct private_tls_application_t private_tls_application_t; @@ -96,8 +108,8 @@ METHOD(tls_application_t, build, status_t, */ static bool exchange(private_tls_socket_t *this, bool wr) { - char buf[1024]; - ssize_t len; + char buf[CRYPTO_BUF_SIZE], *pos; + ssize_t len, out; int round = 0; for (round = 0; TRUE; round++) @@ -109,10 +121,18 @@ static bool exchange(private_tls_socket_t *this, bool wr) { case NEED_MORE: case ALREADY_DONE: - len = write(this->fd, buf, len); - if (len == -1) + pos = buf; + while (len) { - return FALSE; + out = write(this->fd, pos, len); + if (out == -1) + { + DBG1(DBG_TLS, "TLS crypto write error: %s", + strerror(errno)); + return FALSE; + } + len -= out; + pos += out; } continue; case INVALID_STATE: @@ -175,6 +195,81 @@ METHOD(tls_socket_t, write_, bool, return FALSE; } +METHOD(tls_socket_t, splice, bool, + private_tls_socket_t *this, int rfd, int wfd) +{ + char buf[PLAIN_BUF_SIZE], *pos; + fd_set set; + chunk_t data; + ssize_t len; + bool old; + + while (TRUE) + { + FD_ZERO(&set); + FD_SET(rfd, &set); + FD_SET(this->fd, &set); + + old = thread_cancelability(TRUE); + len = select(max(rfd, this->fd) + 1, &set, NULL, NULL, NULL); + thread_cancelability(old); + if (len == -1) + { + DBG1(DBG_TLS, "TLS select error: %s", strerror(errno)); + return FALSE; + } + if (FD_ISSET(this->fd, &set)) + { + if (!read_(this, &data)) + { + DBG2(DBG_TLS, "TLS read error/disconnect"); + return TRUE; + } + pos = data.ptr; + while (data.len) + { + len = write(wfd, pos, data.len); + if (len == -1) + { + free(data.ptr); + DBG1(DBG_TLS, "TLS plain write error: %s", strerror(errno)); + return FALSE; + } + data.len -= len; + pos += len; + } + free(data.ptr); + } + if (FD_ISSET(rfd, &set)) + { + len = read(rfd, buf, sizeof(buf)); + if (len > 0) + { + if (!write_(this, chunk_create(buf, len))) + { + DBG1(DBG_TLS, "TLS write error"); + return FALSE; + } + } + else + { + if (len < 0) + { + DBG1(DBG_TLS, "TLS plain read error: %s", strerror(errno)); + return FALSE; + } + return TRUE; + } + } + } +} + +METHOD(tls_socket_t, get_fd, int, + private_tls_socket_t *this) +{ + return this->fd; +} + METHOD(tls_socket_t, destroy, void, private_tls_socket_t *this) { @@ -187,7 +282,7 @@ METHOD(tls_socket_t, destroy, void, * See header */ tls_socket_t *tls_socket_create(bool is_server, identification_t *server, - identification_t *peer, int fd) + identification_t *peer, int fd, tls_cache_t *cache) { private_tls_socket_t *this; @@ -195,6 +290,8 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server, .public = { .read = _read_, .write = _write_, + .splice = _splice, + .get_fd = _get_fd, .destroy = _destroy, }, .app = { @@ -208,7 +305,7 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server, ); this->tls = tls_create(is_server, server, peer, TLS_PURPOSE_GENERIC, - &this->app.application); + &this->app.application, cache); if (!this->tls) { free(this); diff --git a/src/libtls/tls_socket.h b/src/libtls/tls_socket.h index ac714a385..edd05fd29 100644 --- a/src/libtls/tls_socket.h +++ b/src/libtls/tls_socket.h @@ -55,6 +55,25 @@ struct tls_socket_t { bool (*write)(tls_socket_t *this, chunk_t data); /** + * Read/write plain data from file descriptor. + * + * This call is blocking, but a thread cancellation point. Data is + * exchanged until one of the sockets gets closed or an error occurs. + * + * @param rfd file descriptor to read plain data from + * @param wfd file descriptor to write plain data to + * @return TRUE if data exchanged successfully + */ + bool (*splice)(tls_socket_t *this, int rfd, int wfd); + + /** + * Get the underlying file descriptor passed to the constructor. + * + * @return file descriptor + */ + int (*get_fd)(tls_socket_t *this); + + /** * Destroy a tls_socket_t. */ void (*destroy)(tls_socket_t *this); @@ -67,9 +86,10 @@ struct tls_socket_t { * @param server server identity * @param peer client identity, NULL for no client authentication * @param fd socket to read/write from + * @param cache session cache to use, or NULL * @return TLS socket wrapper */ tls_socket_t *tls_socket_create(bool is_server, identification_t *server, - identification_t *peer, int fd); + identification_t *peer, int fd, tls_cache_t *cache); #endif /** TLS_SOCKET_H_ @}*/ diff --git a/src/libtnccs/Android.mk b/src/libtnccs/Android.mk index 0055fce34..a4bbc13f5 100644 --- a/src/libtnccs/Android.mk +++ b/src/libtnccs/Android.mk @@ -21,6 +21,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := libtnccs +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/libtnccs/Makefile.am b/src/libtnccs/Makefile.am index 4f331c46b..449d32d92 100644 --- a/src/libtnccs/Makefile.am +++ b/src/libtnccs/Makefile.am @@ -13,4 +13,4 @@ tnc/imv/imv_recommendations.h tnc/imv/imv_recommendations.c \ tnc/tnccs/tnccs.h tnc/tnccs/tnccs.c \ tnc/tnccs/tnccs_manager.h tnc/tnccs/tnccs_manager.c - +EXTRA_DIST = Android.mk diff --git a/src/libtnccs/tnc/imc/imc.h b/src/libtnccs/tnc/imc/imc.h index ddedf714c..3ff7d5194 100644 --- a/src/libtnccs/tnc/imc/imc.h +++ b/src/libtnccs/tnc/imc/imc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2011 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -40,11 +40,11 @@ struct imc_t { * the API version number to be used. It also supplies the IMC ID, an IMC * identifier that the IMC must use when calling TNC Client callback functions. * - * @param imcID IMC ID assigned by TNCC - * @param minVersion minimum API version supported by TNCC - * @param maxVersion maximum API version supported by TNCC - * @param OutActualVersion mutually supported API version number - * @return TNC result code + * @param imcID IMC ID assigned by TNCC + * @param minVersion minimum API version supported by TNCC + * @param maxVersion maximum API version supported by TNCC + * @param OutActualVersion mutually supported API version number + * @return TNC result code */ TNC_Result (*initialize)(TNC_IMCID imcID, TNC_Version minVersion, @@ -55,10 +55,10 @@ struct imc_t { * The TNC Client calls this function to inform the IMC that the state of * the network connection identified by connectionID has changed to newState. * - * @param imcID IMC ID assigned by TNCC - * @param connectionID network connection ID assigned by TNCC - * @param newState new network connection state - * @return TNC result code + * @param imcID IMC ID assigned by TNCC + * @param connectionID network connection ID assigned by TNCC + * @param newState new network connection state + * @return TNC result code */ TNC_Result (*notify_connection_change)(TNC_IMCID imcID, TNC_ConnectionID connectionID, @@ -68,9 +68,9 @@ struct imc_t { * The TNC Client calls this function to indicate that an Integrity Check * Handshake is beginning and solicit messages from IMCs for the first batch. * - * @param imcID IMC ID assigned by TNCC - * @param connectionID network connection ID assigned by TNCC - * @return TNC result code + * @param imcID IMC ID assigned by TNCC + * @param connectionID network connection ID assigned by TNCC + * @return TNC result code */ TNC_Result (*begin_handshake)(TNC_IMCID imcID, TNC_ConnectionID connectionID); @@ -81,12 +81,12 @@ struct imc_t { * the number of octets indicated by messageLength. The type of the message * is indicated by messageType. * - * @param imcID IMC ID assigned by TNCS - * @param connectionID network connection ID assigned by TNCC - * @param message reference to buffer containing message - * @param messageLength number of octets in message - * @param messageType message type of message - * @return TNC result code + * @param imcID IMC ID assigned by TNCS + * @param connectionID network connection ID assigned by TNCC + * @param message reference to buffer containing message + * @param messageLength number of octets in message + * @param messageType message type of message + * @return TNC result code */ TNC_Result (*receive_message)(TNC_IMCID imcID, TNC_ConnectionID connectionID, @@ -95,13 +95,40 @@ struct imc_t { TNC_MessageType messageType); /** + * The TNC Client calls this function to deliver a message to the IMC. + * The message is contained in the buffer referenced by message and contains + * the number of octets indicated by messageLength. The type of the message + * is indicated by the message Vendor ID and message subtype. + * + * @param imcID IMC ID assigned by TNCS + * @param connectionID network connection ID assigned by TNCC + * @param messageFlags message flags + * @param message reference to buffer containing message + * @param messageLength number of octets in message + * @param messageVendorID message Vendor ID + * @param messageSubtype message subtype + * @param sourceIMVID source IMV ID + * @param destinationIMCID destination IMC ID + * @return TNC result code + */ + TNC_Result (*receive_message_long)(TNC_IMCID imcID, + TNC_ConnectionID connectionID, + TNC_UInt32 messageFlags, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_VendorID messageVendorID, + TNC_MessageSubtype messageSubtype, + TNC_UInt32 sourceIMVID, + TNC_UInt32 destinationIMCID); + + /** * The TNC Client calls this function to notify IMCs that all IMV messages * received in a batch have been delivered and this is the IMC’s last chance * to send a message in the batch of IMC messages currently being collected. * - * @param imcID IMC ID assigned by TNCC - * @param connectionID network connection ID assigned by TNCC - * @return TNC result code + * @param imcID IMC ID assigned by TNCC + * @param connectionID network connection ID assigned by TNCC + * @return TNC result code */ TNC_Result (*batch_ending)(TNC_IMCID imcID, TNC_ConnectionID connectionID); @@ -110,8 +137,8 @@ struct imc_t { * The TNC Client calls this function to close down the IMC when all work is * complete or the IMC reports TNC_RESULT_FATAL. * - * @param imcID IMC ID assigned by TNCC - * @return TNC result code + * @param imcID IMC ID assigned by TNCC + * @return TNC result code */ TNC_Result (*terminate)(TNC_IMCID imcID); @@ -122,9 +149,9 @@ struct imc_t { * TNCS bind function. The IMV can then use the TNCS bind function to obtain * pointers to any other TNCS functions. * - * @param imcID IMC ID assigned by TNCC - * @param bindFunction pointer to TNC_TNCC_BindFunction - * @return TNC result code + * @param imcID IMC ID assigned by TNCC + * @param bindFunction pointer to TNC_TNCC_BindFunction + * @return TNC result code */ TNC_Result (*provide_bind_function)(TNC_IMCID imcID, TNC_TNCC_BindFunctionPointer bindFunction); @@ -132,40 +159,67 @@ struct imc_t { /** * Sets the ID of an imc_t object. * - * @param id IMC ID to be assigned + * @param id IMC ID to be assigned */ void (*set_id)(imc_t *this, TNC_IMCID id); /** * Returns the ID of an imc_t object. * - * @return assigned IMC ID + * @return assigned IMC ID */ TNC_IMCID (*get_id)(imc_t *this); /** + * Assign an additional ID to an imc_t object. + * + * @param id additional IMC ID to be assigned + */ + void (*add_id)(imc_t *this, TNC_IMCID id); + + /** + * Checks if the ID is assigned to the imc_t object. + * + * @return TRUE if IMC ID is assigned to imc_t object + */ + bool (*has_id)(imc_t *this, TNC_IMCID id); + + /** * Returns the name of an imc_t object. * - * @return name of IMC + * @return name of IMC */ char* (*get_name)(imc_t *this); /** * Sets the supported message types of an imc_t object. * - * @param supported_types list of messages type supported by IMC - * @param type_count number of supported message types + * @param supported_types list of messages type supported by IMC + * @param type_count number of supported message types */ void (*set_message_types)(imc_t *this, TNC_MessageTypeList supported_types, TNC_UInt32 type_count); /** + * Sets the supported long message types of an imc_t object. + * + * @param supported_vids list of vendor IDs supported by IMC + * @param supported_subtypes list of messages type supported by IMC + * @param type_count number of supported message types + */ + void (*set_message_types_long)(imc_t *this, TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count); + + /** * Check if the IMC supports a given message type. * - * @param message_type message type - * @return TRUE if supported + * @param msg_vid message vendor ID + * @param msg_subtype message subtype + * @return TRUE if supported */ - bool (*type_supported)(imc_t *this, TNC_MessageType message_type); + bool (*type_supported)(imc_t *this, TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype); /** * Destroys an imc_t object. diff --git a/src/libtnccs/tnc/imc/imc_manager.h b/src/libtnccs/tnc/imc/imc_manager.h index 396964100..25e0efe9d 100644 --- a/src/libtnccs/tnc/imc/imc_manager.h +++ b/src/libtnccs/tnc/imc/imc_manager.h @@ -66,6 +66,15 @@ struct imc_manager_t { bool (*is_registered)(imc_manager_t *this, TNC_IMCID id); /** + * Reserve an additional ID for an IMC + * + * @param id ID of IMC instance + * @param new_id reserved ID assigned to IMC + * @return TRUE if primary IMC ID was used + */ + bool (*reserve_id)(imc_manager_t *this, TNC_IMCID id, TNC_UInt32 *new_id); + + /** * Return the preferred language for recommendations * * @return preferred language string @@ -84,17 +93,17 @@ struct imc_manager_t { /** * Begin a handshake between the IMCs and a connection * - * @param id connection ID + * @param id connection ID */ void (*begin_handshake)(imc_manager_t *this, TNC_ConnectionID id); /** * Sets the supported message types reported by a given IMC * - * @param id ID of reporting IMC - * @param supported_types list of messages type supported by IMC - * @param type_count number of supported message types - * @return TNC result code + * @param id ID of reporting IMC + * @param supported_types list of messages type supported by IMC + * @param type_count number of supported message types + * @return TNC result code */ TNC_Result (*set_message_types)(imc_manager_t *this, TNC_IMCID id, @@ -102,18 +111,41 @@ struct imc_manager_t { TNC_UInt32 type_count); /** + * Sets the supported long message types reported by a given IMC + * + * @param id ID of reporting IMC + * @param supported_vids list of vendor IDs supported by IMC + * @param supported_subtypes list of messages type supported by IMC + * @param type_count number of supported message types + * @return TNC result code + */ + TNC_Result (*set_message_types_long)(imc_manager_t *this, + TNC_IMCID id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count); + + /** * Delivers a message to interested IMCs. * - * @param connection_id ID of connection over which message was received - * @param message message - * @param message_len message length - * @param message_type message type + * @param connection_id connection ID + * @param excl exclusive message flag + * @param msg message + * @param msg_len message length + * @param msg_vid message Vendor ID + * @param msg_subtype message subtype + * @param src_imv_id source IMV ID + * @param dst_imc_id destination IMC ID */ void (*receive_message)(imc_manager_t *this, TNC_ConnectionID connection_id, - TNC_BufferReference message, - TNC_UInt32 message_len, - TNC_MessageType message_type); + bool excl, + 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); /** * Notify all IMCs that all IMV messages received in a batch have been diff --git a/src/libtnccs/tnc/imv/imv.h b/src/libtnccs/tnc/imv/imv.h index df338d40a..3716532d6 100644 --- a/src/libtnccs/tnc/imv/imv.h +++ b/src/libtnccs/tnc/imv/imv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2011 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -40,11 +40,11 @@ struct imv_t { * the API version number to be used. It also supplies the IMV ID, an IMV * identifier that the IMV must use when calling TNC Server callback functions. * - * @param imvID IMV ID assigned by TNCS - * @param minVersion minimum API version supported - * @param maxVersion maximum API version supported by TNCS - * @param OutActualVersion mutually supported API version number - * @return TNC result code + * @param imvID IMV ID assigned by TNCS + * @param minVersion minimum API version supported + * @param maxVersion maximum API version supported by TNCS + * @param OutActualVersion mutually supported API version number + * @return TNC result code */ TNC_Result (*initialize)(TNC_IMVID imvID, TNC_Version minVersion, @@ -55,10 +55,10 @@ struct imv_t { * The TNC Server calls this function to inform the IMV that the state of * the network connection identified by connectionID has changed to newState. * - * @param imvID IMV ID assigned by TNCS - * @param connectionID network connection ID assigned by TNCS - * @param newState new network connection state - * @return TNC result code + * @param imvID IMV ID assigned by TNCS + * @param connectionID network connection ID assigned by TNCS + * @param newState new network connection state + * @return TNC result code */ TNC_Result (*notify_connection_change)(TNC_IMVID imvID, TNC_ConnectionID connectionID, @@ -69,9 +69,9 @@ struct imv_t { * Handshake (after all IMC-IMV messages have been delivered) to solicit * recommendations from IMVs that have not yet provided a recommendation. * - * @param imvID IMV ID assigned by TNCS - * @param connectionID network connection ID assigned by TNCS - * @return TNC result code + * @param imvID IMV ID assigned by TNCS + * @param connectionID network connection ID assigned by TNCS + * @return TNC result code */ TNC_Result (*solicit_recommendation)(TNC_IMVID imvID, TNC_ConnectionID connectionID); @@ -82,12 +82,12 @@ struct imv_t { * the number of octets indicated by messageLength. The type of the message * is indicated by messageType. * - * @param imvID IMV ID assigned by TNCS - * @param connectionID network connection ID assigned by TNCS - * @param message reference to buffer containing message - * @param messageLength number of octets in message - * @param messageType message type of message - * @return TNC result code + * @param imvID IMV ID assigned by TNCS + * @param connectionID network connection ID assigned by TNCS + * @param message reference to buffer containing message + * @param messageLength number of octets in message + * @param messageType message type of message + * @return TNC result code */ TNC_Result (*receive_message)(TNC_IMVID imvID, TNC_ConnectionID connectionID, @@ -96,13 +96,40 @@ struct imv_t { TNC_MessageType messageType); /** + * The TNC Server calls this function to deliver a message to the IMV. + * The message is contained in the buffer referenced by message and contains + * the number of octets indicated by messageLength. The type of the message + * is indicated by the message Vendor ID and message subtype. + * + * @param imvID IMV ID assigned by TNCS + * @param connectionID network connection ID assigned by TNCS + * @param messageFlags message flags + * @param message reference to buffer containing message + * @param messageLength number of octets in message + * @param messageVendorID message Vendor ID + * @param messageSubtype message subtype + * @param sourceIMCID source IMC ID + * @param destinationIMVID destination IMV ID + * @return TNC result code + */ + TNC_Result (*receive_message_long)(TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_UInt32 messageFlags, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_VendorID messageVendorID, + TNC_MessageSubtype messageSubtype, + TNC_UInt32 sourceIMCID, + TNC_UInt32 destinationIMVID); + + /** * The TNC Server calls this function to notify IMVs that all IMC messages * received in a batch have been delivered and this is the IMV’s last chance * to send a message in the batch of IMV messages currently being collected. * - * @param imvID IMV ID assigned by TNCS - * @param connectionID network connection ID assigned by TNCS - * @return TNC result code + * @param imvID IMV ID assigned by TNCS + * @param connectionID network connection ID assigned by TNCS + * @return TNC result code */ TNC_Result (*batch_ending)(TNC_IMVID imvID, TNC_ConnectionID connectionID); @@ -110,8 +137,8 @@ struct imv_t { /** * The TNC Server calls this function to close down the IMV. * - * @param imvID IMV ID assigned by TNCS - * @return TNC result code + * @param imvID IMV ID assigned by TNCS + * @return TNC result code */ TNC_Result (*terminate)(TNC_IMVID imvID); @@ -122,9 +149,9 @@ struct imv_t { * TNCS bind function. The IMV can then use the TNCS bind function to obtain * pointers to any other TNCS functions. * - * @param imvID IMV ID assigned by TNCS - * @param bindFunction pointer to TNC_TNCS_BindFunction - * @return TNC result code + * @param imvID IMV ID assigned by TNCS + * @param bindFunction pointer to TNC_TNCS_BindFunction + * @return TNC result code */ TNC_Result (*provide_bind_function)(TNC_IMVID imvID, TNC_TNCS_BindFunctionPointer bindFunction); @@ -132,40 +159,67 @@ struct imv_t { /** * Sets the ID of an imv_t object. * - * @param id IMV ID to be assigned + * @param id IMV ID to be assigned */ void (*set_id)(imv_t *this, TNC_IMVID id); /** * Returns the ID of an imv_t object. * - * @return IMV ID assigned by TNCS + * @return IMV ID assigned by TNCS */ TNC_IMVID (*get_id)(imv_t *this); /** + * Assign an additional ID to an imv_t object. + * + * @param id additional IMV ID to be assigned + */ + void (*add_id)(imv_t *this, TNC_IMVID id); + + /** + * Checks if the ID is assigned to the imv_t object. + * + * @return TRUE if IMV ID is assigned to imv_t object + */ + bool (*has_id)(imv_t *this, TNC_IMVID id); + + /** * Returns the name of an imv_t object. * - * @return name of IMV + * @return name of IMV */ char* (*get_name)(imv_t *this); /** * Sets the supported message types of an imv_t object. * - * @param supported_types list of messages type supported by IMV - * @param type_count number of supported message types + * @param supported_types list of messages type supported by IMV + * @param type_count number of supported message types */ void (*set_message_types)(imv_t *this, TNC_MessageTypeList supported_types, TNC_UInt32 type_count); /** + * Sets the supported long message types of an imv_t object. + * + * @param supported_vids list of vendor IDs supported by IMC + * @param supported_subtypes list of messages type supported by IMC + * @param type_count number of supported message types + */ + void (*set_message_types_long)(imv_t *this, TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count); + + /** * Check if the IMV supports a given message type. * - * @param message_type message type - * @return TRUE if supported + * @param msg_vid message vendor ID + * @param msg_subtype message subtype + * @return TRUE if supported */ - bool (*type_supported)(imv_t *this, TNC_MessageType message_type); + bool (*type_supported)(imv_t *this, TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype); /** * Destroys an imv_t object. diff --git a/src/libtnccs/tnc/imv/imv_manager.h b/src/libtnccs/tnc/imv/imv_manager.h index caa25e857..43f40973c 100644 --- a/src/libtnccs/tnc/imv/imv_manager.h +++ b/src/libtnccs/tnc/imv/imv_manager.h @@ -67,6 +67,14 @@ struct imv_manager_t { */ bool (*is_registered)(imv_manager_t *this, TNC_IMVID id); + /** + * Reserve an additional ID for an IMV + * + * @param id ID of IMV instance + * @param new_id reserved ID assigned to IMV + * @return TRUE if primary IMV ID was used + */ + bool (*reserve_id)(imv_manager_t *this, TNC_IMVID id, TNC_UInt32 *new_id); /** * Get the configured recommendation policy @@ -106,10 +114,10 @@ struct imv_manager_t { /** * Sets the supported message types reported by a given IMV * - * @param id ID of reporting IMV - * @param supported_types list of messages type supported by IMV - * @param type_count number of supported message types - * @return TNC result code + * @param id ID of reporting IMV + * @param supported_types list of messages type supported by IMV + * @param type_count number of supported message types + * @return TNC result code */ TNC_Result (*set_message_types)(imv_manager_t *this, TNC_IMVID id, @@ -117,25 +125,48 @@ struct imv_manager_t { TNC_UInt32 type_count); /** + * Sets the supported long message types reported by a given IMV + * + * @param id ID of reporting IMV + * @param supported_vids list of vendor IDs supported by IMV + * @param supported_subtypes list of messages type supported by IMV + * @param type_count number of supported message types + * @return TNC result code + */ + TNC_Result (*set_message_types_long)(imv_manager_t *this, + TNC_IMVID id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count); + + /** * Solicit recommendations from IMVs that have not yet provided one * - * @param id connection ID + * @param id connection ID */ void (*solicit_recommendation)(imv_manager_t *this, TNC_ConnectionID id); /** * Delivers a message to interested IMVs. * - * @param connection_id ID of connection over which message was received - * @param message message - * @param message_len message length - * @param message_type message type + * @param connection_id connection ID + * @param excl exclusive message flag + * @param msg message + * @param msg_len message length + * @param msg_vid message Vendor ID + * @param msg_subtype message subtype + * @param src_imc_id source IMC ID + * @param dst_imv_id destination IMV ID */ void (*receive_message)(imv_manager_t *this, TNC_ConnectionID connection_id, - TNC_BufferReference message, - TNC_UInt32 message_len, - TNC_MessageType message_type); + bool excl, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id); /** * Notify all IMVs that all IMC messages received in a batch have been diff --git a/src/libtnccs/tnc/tnccs/tnccs.h b/src/libtnccs/tnc/tnccs/tnccs.h index 4bbab5bd3..c3020d7c3 100644 --- a/src/libtnccs/tnc/tnccs/tnccs.h +++ b/src/libtnccs/tnc/tnccs/tnccs.h @@ -63,15 +63,20 @@ typedef tnccs_t *(*tnccs_constructor_t)(bool is_server); * * @param imc_id ID of IMC or TNC_IMCID_ANY * @param imc_id ID of IMV or TNC_IMVID_ANY + * @param msg_flags message flags * @param msg message to be added * @param msg_len message length - * @param msg_type message type - * @return result code + * @param msg_vid message vendor ID + * @param msg_subtype message subtype + * @return return code */ -typedef TNC_Result (*tnccs_send_message_t)(tnccs_t* tncss, TNC_IMCID imc_id, - TNC_IMVID imv_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type); +typedef TNC_Result (*tnccs_send_message_t)(tnccs_t* tncss, + TNC_IMCID imc_id, + TNC_IMVID imv_id, + TNC_UInt32 msg_flags, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype); #endif /** TNCCS_H_ @}*/ diff --git a/src/libtnccs/tnc/tnccs/tnccs_manager.h b/src/libtnccs/tnc/tnccs/tnccs_manager.h index 26b0fa17c..9ca450468 100644 --- a/src/libtnccs/tnc/tnccs/tnccs_manager.h +++ b/src/libtnccs/tnc/tnccs/tnccs_manager.h @@ -66,13 +66,15 @@ struct tnccs_manager_t { * callback function for adding a message to a TNCCS batch and create * an empty set for collecting IMV recommendations * + * @param type TNCCS protocol type * @param tnccs TNCCS connection instance * @param send_message TNCCS callback function * @param request_handshake_retry pointer to boolean variable * @param recs pointer to IMV recommendation set * @return assigned connection ID */ - TNC_ConnectionID (*create_connection)(tnccs_manager_t *this, tnccs_t *tnccs, + TNC_ConnectionID (*create_connection)(tnccs_manager_t *this, + tnccs_type_t type, tnccs_t *tnccs, tnccs_send_message_t send_message, bool *request_handshake_retry, recommendations_t **recs); @@ -106,17 +108,22 @@ struct tnccs_manager_t { * @param imc_id ID of IMC or TNC_IMCID_ANY * @param imv_id ID of IMV or TNC_IMVID_ANY * @param id ID of target connection + * @param msg_flags message flags * @param msg message to be added * @param msg_len message length - * @param msg_type message type + * @param msg_vid message vendor ID + * @param msg_subtype message subtype * @return return code */ - TNC_Result (*send_message)(tnccs_manager_t *this, TNC_IMCID imc_id, - TNC_IMVID imv_id, - TNC_ConnectionID id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type); + TNC_Result (*send_message)(tnccs_manager_t *this, + TNC_IMCID imc_id, + TNC_IMVID imv_id, + TNC_ConnectionID id, + TNC_UInt32 msg_flags, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype); /** * Deliver an IMV Action Recommendation and IMV Evaluation Result to the TNCS @@ -137,35 +144,37 @@ struct tnccs_manager_t { * Get the value of an attribute associated with a connection or with the * TNCS as a whole. * - * @param imv_id ID of the IMV requesting the attribute + * @param is_imc TRUE if IMC, FALSE if IMV + * @param imcv_id ID of the IMC/IMV requesting the attribute * @param id ID of target connection * @param attribute_id ID of the requested attribute * @param buffer_len length of the buffer in bytes * @param buffer pointer to the buffer - * @param out_value_len actual length of the returned attribute + * @param value_len actual length of the returned attribute * @return return code */ - TNC_Result (*get_attribute)(tnccs_manager_t *this, - TNC_IMVID imv_id, + TNC_Result (*get_attribute)(tnccs_manager_t *this, bool is_imc, + TNC_UInt32 imcv_id, TNC_ConnectionID id, TNC_AttributeID attribute_id, TNC_UInt32 buffer_len, TNC_BufferReference buffer, - TNC_UInt32 *out_value_len); + TNC_UInt32 *value_len); /** * Set the value of an attribute associated with a connection or with the * TNCS as a whole. * - * @param imv_id ID of the IMV setting the attribute + * @param is_imc TRUE if IMC, FALSE if IMV + * @param imcv_id ID of the IMC/IMV setting the attribute * @param id ID of target connection * @param attribute_id ID of the attribute to be set * @param buffer_len length of the buffer in bytes * @param buffer pointer to the buffer * @return return code */ - TNC_Result (*set_attribute)(tnccs_manager_t *this, - TNC_IMVID imv_id, + TNC_Result (*set_attribute)(tnccs_manager_t *this, bool is_imc, + TNC_UInt32 imcv_id, TNC_ConnectionID id, TNC_AttributeID attribute_id, TNC_UInt32 buffer_len, diff --git a/src/libtncif/Android.mk b/src/libtncif/Android.mk index 91cfa8354..ef406dd59 100644 --- a/src/libtncif/Android.mk +++ b/src/libtncif/Android.mk @@ -16,6 +16,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := libtncif +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/libtncif/Makefile.am b/src/libtncif/Makefile.am index cfaba912a..cc262ffca 100644 --- a/src/libtncif/Makefile.am +++ b/src/libtncif/Makefile.am @@ -5,3 +5,5 @@ noinst_LTLIBRARIES = libtncif.la libtncif_la_SOURCES = \ tncif.h tncifimc.h tncifimv.h tncif_names.h tncif_names.c \ tncif_pa_subtypes.h tncif_pa_subtypes.c + +EXTRA_DIST = Android.mk diff --git a/src/libtncif/tncif.h b/src/libtncif/tncif.h index 3a889962e..f904bc600 100644 --- a/src/libtncif/tncif.h +++ b/src/libtncif/tncif.h @@ -1,22 +1,25 @@ /* tncif.h * - * Trusted Network Connect IF-IMV API version 1.20 + * Trusted Network Connect IF-IMC/IMV API version 1.30 * Microsoft Windows DLL Platform Binding C Header - * February 5, 2007 + * October 14, 2011 * - * Copyright(c) 2005-2007, Trusted Computing Group, Inc. All rights + * Common definitions for IF-IMC and IF-IMV + * extracted from tncifimc.h and tncifimv.h + * + * Copyright(c) 2005-2011, Trusted Computing Group, Inc. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * - Redistributions of source code must retain the above copyright + * o Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright + * o Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * - Neither the name of the Trusted Computing Group nor the names of + * o Neither the name of the Trusted Computing Group nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. @@ -41,32 +44,38 @@ * Any marks and brands contained herein are the property of their * respective owners. * - * Trusted Network Connect IF-IMC/IF-IMV API version 1.00 Revision 3 - * Microsoft Windows DLL Platform Binding C Header - * Common definitions for IF-IMC and IF-IMV - * extracted from tncifimc.h and tncifimv.h - * Feb 12, 2007 + */ + +/** + * @defgroup tncif tncif + * @{ @ingroup libtncif */ #ifndef TNCIF_H_ #define TNCIF_H_ /* Basic Types */ + typedef unsigned long TNC_UInt32; typedef unsigned char *TNC_BufferReference; /* Derived Types */ + typedef TNC_UInt32 TNC_ConnectionID; typedef TNC_UInt32 TNC_ConnectionState; typedef TNC_UInt32 TNC_RetryReason; typedef TNC_UInt32 TNC_MessageType; typedef TNC_MessageType *TNC_MessageTypeList; typedef TNC_UInt32 TNC_VendorID; +typedef TNC_VendorID *TNC_VendorIDList; typedef TNC_UInt32 TNC_MessageSubtype; +typedef TNC_MessageSubtype *TNC_MessageSubtypeList; typedef TNC_UInt32 TNC_Version; typedef TNC_UInt32 TNC_Result; +typedef TNC_UInt32 TNC_AttributeID; /* Result Codes */ + #define TNC_RESULT_SUCCESS 0 #define TNC_RESULT_NOT_INITIALIZED 1 #define TNC_RESULT_ALREADY_INITIALIZED 2 @@ -78,11 +87,17 @@ typedef TNC_UInt32 TNC_Result; #define TNC_RESULT_ILLEGAL_OPERATION 8 #define TNC_RESULT_OTHER 9 #define TNC_RESULT_FATAL 10 +#define TNC_RESULT_EXCEEDED_MAX_ROUND_TRIPS 0x00559700 +#define TNC_RESULT_EXCEEDED_MAX_MESSAGE_SIZE 0x00559701 +#define TNC_RESULT_NO_LONG_MESSAGE_TYPES 0x00559702 +#define TNC_RESULT_NO_SOH_SUPPORT 0x00559703 /* Network Connection ID Values */ + #define TNC_CONNECTIONID_ANY 0xFFFFFFFF /* Network Connection State Values */ + #define TNC_CONNECTION_STATE_CREATE 0 #define TNC_CONNECTION_STATE_HANDSHAKE 1 #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 @@ -90,10 +105,38 @@ typedef TNC_UInt32 TNC_Result; #define TNC_CONNECTION_STATE_ACCESS_NONE 4 #define TNC_CONNECTION_STATE_DELETE 5 +/* IMC/IMV ID Values */ + +#define TNC_IMVID_ANY ((TNC_UInt32) 0xffff) +#define TNC_IMCID_ANY ((TNC_UInt32) 0xffff) + /* Vendor ID Values */ + #define TNC_VENDORID_TCG 0 +#define TNC_VENDORID_TCG_NEW 0x005597 #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) + /* Message Subtype Values */ + #define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff) +/* Message Flags Values */ + +#define TNC_MESSAGE_FLAGS_EXCLUSIVE ((TNC_UInt32) 0x80000000) + +/* Message Attribute ID Values */ + +#define TNC_ATTRIBUTEID_PREFERRED_LANGUAGE ((TNC_AttributeID) 0x00000001) +#define TNC_ATTRIBUTEID_MAX_ROUND_TRIPS ((TNC_AttributeID) 0x00559700) +#define TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE ((TNC_AttributeID) 0x00559701) +#define TNC_ATTRIBUTEID_DHPN ((TNC_AttributeID) 0x00559702) +#define TNC_ATTRIBUTEID_HAS_LONG_TYPES ((TNC_AttributeID) 0x00559703) +#define TNC_ATTRIBUTEID_HAS_EXCLUSIVE ((TNC_AttributeID) 0x00559704) +#define TNC_ATTRIBUTEID_HAS_SOH ((TNC_AttributeID) 0x00559705) +#define TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL ((TNC_AttributeID) 0x0055970A) +#define TNC_ATTRIBUTEID_IFTNCCS_VERSION ((TNC_AttributeID) 0x0055970B) +#define TNC_ATTRIBUTEID_IFT_PROTOCOL ((TNC_AttributeID) 0x0055970C) +#define TNC_ATTRIBUTEID_IFT_VERSION ((TNC_AttributeID) 0x0055970D) +#define TNC_ATTRIBUTEID_TLS_UNIQUE ((TNC_AttributeID) 0x0055970E) + #endif /** TNCIF_H_ @}*/ diff --git a/src/libtncif/tncif_names.h b/src/libtncif/tncif_names.h index a7c9e7be3..9b50a34e9 100644 --- a/src/libtncif/tncif_names.h +++ b/src/libtncif/tncif_names.h @@ -12,6 +12,16 @@ * for more details. */ +/** + * @defgroup libtncif libtncif + * + * @addtogroup libtncif + * TNC interface definitions + * + * @defgroup tncif_names tncif_names + * @{ @ingroup libtncif + */ + #ifndef TNCIF_NAMES_H_ #define TNCIF_NAMES_H_ diff --git a/src/libtncif/tncif_pa_subtypes.c b/src/libtncif/tncif_pa_subtypes.c index de857e1ce..d15a1c864 100644 --- a/src/libtncif/tncif_pa_subtypes.c +++ b/src/libtncif/tncif_pa_subtypes.c @@ -16,7 +16,7 @@ #include "tncif_pa_subtypes.h" -ENUM(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT, +ENUM_BEGIN(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT, "Testing", "Operating System", "Anti-Virus", @@ -27,10 +27,20 @@ ENUM(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT, "VPN", "NEA Client" ); +ENUM_NEXT(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY, PA_SUBTYPE_IETF_ANY, + PA_SUBTYPE_IETF_NEA_CLIENT, + "ANY" +); +ENUM_END(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY); -ENUM(pa_subtype_tcg_names, PA_SUBTYPE_TCG_PTS, PA_SUBTYPE_TCG_PTS, +ENUM_BEGIN(pa_subtype_tcg_names, PA_SUBTYPE_TCG_PTS, PA_SUBTYPE_TCG_PTS, "PTS" ); +ENUM_NEXT(pa_subtype_tcg_names, PA_SUBTYPE_TCG_ANY, PA_SUBTYPE_TCG_ANY, + PA_SUBTYPE_TCG_PTS, + "ANY" +); +ENUM_END(pa_subtype_tcg_names, PA_SUBTYPE_TCG_ANY); ENUM_BEGIN(pa_subtype_fhh_names, PA_SUBTYPE_FHH_HOSTSCANNER, PA_SUBTYPE_FHH_DUMMY, "HostScanner", @@ -45,12 +55,21 @@ ENUM_NEXT(pa_subtype_fhh_names, PA_SUBTYPE_FHH_CLAMAV, PA_SUBTYPE_FHH_CLAMAV, PA_SUBTYPE_FHH_ATTESTATION, "ClamAV" ); -ENUM_END(pa_subtype_fhh_names, PA_SUBTYPE_FHH_CLAMAV); +ENUM_NEXT(pa_subtype_fhh_names, PA_SUBTYPE_FHH_ANY, PA_SUBTYPE_FHH_ANY, + PA_SUBTYPE_FHH_CLAMAV, + "ANY" +); +ENUM_END(pa_subtype_fhh_names, PA_SUBTYPE_FHH_ANY); -ENUM(pa_subtype_ita_names, PA_SUBTYPE_ITA_TEST, PA_SUBTYPE_ITA_SCANNER, +ENUM_BEGIN(pa_subtype_ita_names, PA_SUBTYPE_ITA_TEST, PA_SUBTYPE_ITA_SCANNER, "Test", "Scanner" ); +ENUM_NEXT(pa_subtype_ita_names, PA_SUBTYPE_ITA_ANY, PA_SUBTYPE_ITA_ANY, + PA_SUBTYPE_ITA_SCANNER, + "ANY" +); +ENUM_END(pa_subtype_ita_names, PA_SUBTYPE_ITA_ANY); /** * See header diff --git a/src/libtncif/tncif_pa_subtypes.h b/src/libtncif/tncif_pa_subtypes.h index 771971338..0be495bfc 100644 --- a/src/libtncif/tncif_pa_subtypes.h +++ b/src/libtncif/tncif_pa_subtypes.h @@ -12,6 +12,11 @@ * for more details. */ +/** + * @defgroup tncif_pa_subtypes tncif_pa_subtypes + * @{ @ingroup libtncif + */ + #ifndef TNCIF_PA_SUBTYPES_H_ #define TNCIF_PA_SUBTYPES_H_ @@ -27,15 +32,16 @@ typedef enum pa_subtype_ita_t pa_subtype_ita_t; * PA-TNC IETF Standard Subtypes as defined in section 3.5 of RFC 5792 */ enum pa_subtype_ietf_t { - PA_SUBTYPE_IETF_TESTING = 0, - PA_SUBTYPE_IETF_OPERATING_SYSTEM = 1, - PA_SUBTYPE_IETF_ANTI_VIRUS = 2, - PA_SUBTYPE_IETF_ANTI_SPYWARE = 3, - PA_SUBTYPE_IETF_ANTI_MALWARE = 4, - PA_SUBTYPE_IETF_FIREWALL = 5, - PA_SUBTYPE_IETF_IDPS = 6, - PA_SUBTYPE_IETF_VPN = 7, - PA_SUBTYPE_IETF_NEA_CLIENT = 8 + PA_SUBTYPE_IETF_TESTING = 0x00, + PA_SUBTYPE_IETF_OPERATING_SYSTEM = 0x01, + PA_SUBTYPE_IETF_ANTI_VIRUS = 0x02, + PA_SUBTYPE_IETF_ANTI_SPYWARE = 0x03, + PA_SUBTYPE_IETF_ANTI_MALWARE = 0x04, + PA_SUBTYPE_IETF_FIREWALL = 0x05, + PA_SUBTYPE_IETF_IDPS = 0x06, + PA_SUBTYPE_IETF_VPN = 0x07, + PA_SUBTYPE_IETF_NEA_CLIENT = 0x08, + PA_SUBTYPE_IETF_ANY = 0xff }; /** @@ -47,7 +53,8 @@ extern enum_name_t *pa_subtype_ietf_names; * PA-TNC TCG Subtypes */ enum pa_subtype_tcg_t { - PA_SUBTYPE_TCG_PTS = 1 + PA_SUBTYPE_TCG_PTS = 0x01, + PA_SUBTYPE_TCG_ANY = 0xff }; /** @@ -59,11 +66,12 @@ extern enum_name_t *pa_subtype_tcg_names; * PA-TNC FHH Subtypes */ enum pa_subtype_fhh_t { - PA_SUBTYPE_FHH_HOSTSCANNER = 0x30, - PA_SUBTYPE_FHH_DUMMY = 0x31, - PA_SUBTYPE_FHH_PLATID = 0x33, - PA_SUBTYPE_FHH_ATTESTATION = 0x34, - PA_SUBTYPE_FHH_CLAMAV = 0x41 + PA_SUBTYPE_FHH_HOSTSCANNER = 0x30, + PA_SUBTYPE_FHH_DUMMY = 0x31, + PA_SUBTYPE_FHH_PLATID = 0x33, + PA_SUBTYPE_FHH_ATTESTATION = 0x34, + PA_SUBTYPE_FHH_CLAMAV = 0x41, + PA_SUBTYPE_FHH_ANY = 0xff }; /** @@ -75,8 +83,9 @@ extern enum_name_t *pa_subtype_fhh_names; * PA-TNC ITA-HSR Subtypes */ enum pa_subtype_ita_t { - PA_SUBTYPE_ITA_TEST = 1, - PA_SUBTYPE_ITA_SCANNER = 2 + PA_SUBTYPE_ITA_TEST = 0x01, + PA_SUBTYPE_ITA_SCANNER = 0x02, + PA_SUBTYPE_ITA_ANY = 0xff }; /** diff --git a/src/libtncif/tncifimc.h b/src/libtncif/tncifimc.h index c6ddabd45..45af913df 100644 --- a/src/libtncif/tncifimc.h +++ b/src/libtncif/tncifimc.h @@ -1,22 +1,22 @@ /* tncifimc.h * - * Trusted Network Connect IF-IMC API version 1.20 Revision 8 + * Trusted Network Connect IF-IMC API version 1.30 * Microsoft Windows DLL Platform Binding C Header - * February 5, 2007 + * October 14, 2011 * - * Copyright(c) 2005-2007, Trusted Computing Group, Inc. All rights + * Copyright(c) 2005-2011, Trusted Computing Group, Inc. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * - Redistributions of source code must retain the above copyright + * o Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright + * o Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * - Neither the name of the Trusted Computing Group nor the names of + * o Neither the name of the Trusted Computing Group nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. @@ -45,7 +45,7 @@ /** * @defgroup tncifimc tncifimc - * @{ @ingroup tnc + * @{ @ingroup libtncif */ #ifndef TNCIFIMC_H_ @@ -53,6 +53,16 @@ #include "tncif.h" +#ifdef WIN32 +#ifdef TNC_IMC_EXPORTS +#define TNC_IMC_API __declspec(dllexport) +#else +#define TNC_IMC_API __declspec(dllimport) +#endif +#else +#define TNC_IMC_API +#endif + /* Derived Types */ typedef TNC_UInt32 TNC_IMCID; @@ -77,6 +87,22 @@ typedef TNC_Result (*TNC_IMC_ReceiveMessagePointer)( TNC_BufferReference message, TNC_UInt32 messageLength, TNC_MessageType messageType); +typedef TNC_Result (*TNC_IMC_ReceiveMessageSOHPointer)( + TNC_IMCID imcID, + TNC_ConnectionID connectionID, + TNC_BufferReference sohrReportEntry, + TNC_UInt32 sohrRELength, + TNC_MessageType systemHealthID); +typedef TNC_Result (*TNC_IMC_ReceiveMessageLongPointer)( + TNC_IMCID imcID, + TNC_ConnectionID connectionID, + TNC_UInt32 messageFlags, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_VendorID messageVendorID, + TNC_MessageSubtype messageSubtype, + TNC_UInt32 sourceIMVID, + TNC_UInt32 destinationIMCID); typedef TNC_Result (*TNC_IMC_BatchEndingPointer)( TNC_IMCID imcID, TNC_ConnectionID connectionID); @@ -86,16 +112,51 @@ typedef TNC_Result (*TNC_TNCC_ReportMessageTypesPointer)( TNC_IMCID imcID, TNC_MessageTypeList supportedTypes, TNC_UInt32 typeCount); +typedef TNC_Result (*TNC_TNCC_ReportMessageTypesLongPointer)( + TNC_IMCID imcID, + TNC_VendorIDList supportedVendorIDs, + TNC_MessageSubtypeList supportedSubtypes, + TNC_UInt32 typeCount); typedef TNC_Result (*TNC_TNCC_SendMessagePointer)( TNC_IMCID imcID, TNC_ConnectionID connectionID, TNC_BufferReference message, TNC_UInt32 messageLength, TNC_MessageType messageType); +typedef TNC_Result (*TNC_TNCC_SendMessageSOHPointer)( + TNC_IMCID imcID, + TNC_ConnectionID connectionID, + TNC_BufferReference sohReportEntry, + TNC_UInt32 sohRELength); +typedef TNC_Result (*TNC_TNCC_SendMessageLongPointer)( + TNC_IMCID imcID, + TNC_ConnectionID connectionID, + TNC_UInt32 messageFlags, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_VendorID messageVendorID, + TNC_MessageSubtype messageSubtype, + TNC_UInt32 destinationIMVID); typedef TNC_Result (*TNC_TNCC_RequestHandshakeRetryPointer)( TNC_IMCID imcID, TNC_ConnectionID connectionID, TNC_RetryReason reason); +typedef TNC_Result (*TNC_TNCC_GetAttributePointer)( + TNC_IMCID imcID, + TNC_ConnectionID connectionID, + TNC_AttributeID attributeID, + TNC_UInt32 bufferLength, + TNC_BufferReference buffer, + TNC_UInt32 *pOutValueLength); +typedef TNC_Result (*TNC_TNCC_SetAttributePointer)( + TNC_IMCID imcID, + TNC_ConnectionID connectionID, + TNC_AttributeID attributeID, + TNC_UInt32 bufferLength, + TNC_BufferReference buffer); +typedef TNC_Result (*TNC_TNCC_ReserveAdditionalIMCIDPointer)( + TNC_IMCID imcID, + TNC_UInt32 *pOutIMCID); typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)( TNC_IMCID imcID, char *functionName, @@ -104,6 +165,8 @@ typedef TNC_Result (*TNC_IMC_ProvideBindFunctionPointer)( TNC_IMCID imcID, TNC_TNCC_BindFunctionPointer bindFunction); +/* Version Numbers */ + #define TNC_IFIMC_VERSION_1 1 /* Handshake Retry Reason Values */ @@ -118,38 +181,62 @@ typedef TNC_Result (*TNC_IMC_ProvideBindFunctionPointer)( /* reserved for TNC_RETRY_REASON_IMV_MINOR_EVENT: 7 */ /* reserved for TNC_RETRY_REASON_IMV_PERIODIC: 8 */ +/* Message Attribute ID Values */ + +#define TNC_ATTRIBUTEID_SOHR ((TNC_AttributeID) 0x00559708) +#define TNC_ATTRIBUTEID_SSOHR ((TNC_AttributeID) 0x00559709) +#define TNC_ATTRIBUTEID_PRIMARY_IMC_ID ((TNC_AttributeID) 0x00559711) + /* IMC Functions */ -TNC_Result TNC_IMC_Initialize( +TNC_IMC_API TNC_Result TNC_IMC_Initialize( /*in*/ TNC_IMCID imcID, /*in*/ TNC_Version minVersion, /*in*/ TNC_Version maxVersion, /*out*/ TNC_Version *pOutActualVersion); -TNC_Result TNC_IMC_NotifyConnectionChange( +TNC_IMC_API TNC_Result TNC_IMC_NotifyConnectionChange( /*in*/ TNC_IMCID imcID, /*in*/ TNC_ConnectionID connectionID, /*in*/ TNC_ConnectionState newState); -TNC_Result TNC_IMC_BeginHandshake( +TNC_IMC_API TNC_Result TNC_IMC_BeginHandshake( /*in*/ TNC_IMCID imcID, /*in*/ TNC_ConnectionID connectionID); -TNC_Result TNC_IMC_ReceiveMessage( +TNC_IMC_API TNC_Result TNC_IMC_ReceiveMessage( /*in*/ TNC_IMCID imcID, /*in*/ TNC_ConnectionID connectionID, /*in*/ TNC_BufferReference messageBuffer, /*in*/ TNC_UInt32 messageLength, /*in*/ TNC_MessageType messageType); -TNC_Result TNC_IMC_BatchEnding( +TNC_IMC_API TNC_Result TNC_IMC_ReceiveMessageSOH( +/*in*/ TNC_IMCID imcID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_BufferReference sohrReportEntry, +/*in*/ TNC_UInt32 sohrRELength, +/*in*/ TNC_MessageType systemHealthID); + +TNC_IMC_API TNC_Result TNC_IMC_ReceiveMessageLong( +/*in*/ TNC_IMCID imcID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_UInt32 messageFlags, +/*in*/ TNC_BufferReference message, +/*in*/ TNC_UInt32 messageLength, +/*in*/ TNC_VendorID messageVendorID, +/*in*/ TNC_MessageSubtype messageSubtype, +/*in*/ TNC_UInt32 sourceIMVID, +/*in*/ TNC_UInt32 destinationIMCID); + +TNC_IMC_API TNC_Result TNC_IMC_BatchEnding( /*in*/ TNC_IMCID imcID, /*in*/ TNC_ConnectionID connectionID); -TNC_Result TNC_IMC_Terminate( +TNC_IMC_API TNC_Result TNC_IMC_Terminate( /*in*/ TNC_IMCID imcID); -TNC_Result TNC_IMC_ProvideBindFunction( +TNC_IMC_API TNC_Result TNC_IMC_ProvideBindFunction( /*in*/ TNC_IMCID imcID, /*in*/ TNC_TNCC_BindFunctionPointer bindFunction); @@ -160,6 +247,12 @@ TNC_Result TNC_TNCC_ReportMessageTypes( /*in*/ TNC_MessageTypeList supportedTypes, /*in*/ TNC_UInt32 typeCount); +TNC_Result TNC_TNCC_ReportMessageTypesLong( +/*in*/ TNC_IMCID imcID, +/*in*/ TNC_VendorIDList supportedVendorIDs, +/*in*/ TNC_MessageSubtypeList supportedSubtypes, +/*in*/ TNC_UInt32 typeCount); + TNC_Result TNC_TNCC_SendMessage( /*in*/ TNC_IMCID imcID, /*in*/ TNC_ConnectionID connectionID, @@ -167,11 +260,45 @@ TNC_Result TNC_TNCC_SendMessage( /*in*/ TNC_UInt32 messageLength, /*in*/ TNC_MessageType messageType); +TNC_Result TNC_TNCC_SendMessageSOH( +/*in*/ TNC_IMCID imcID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_BufferReference sohReportEntry, +/*in*/ TNC_UInt32 sohRELength); + +TNC_Result TNC_TNCC_SendMessageLong( +/*in*/ TNC_IMCID imcID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_UInt32 messageFlags, +/*in*/ TNC_BufferReference message, +/*in*/ TNC_UInt32 messageLength, +/*in*/ TNC_VendorID messageVendorID, +/*in*/ TNC_MessageSubtype messageSubtype, +/*in*/ TNC_UInt32 destinationIMVID); TNC_Result TNC_TNCC_RequestHandshakeRetry( /*in*/ TNC_IMCID imcID, /*in*/ TNC_ConnectionID connectionID, /*in*/ TNC_RetryReason reason); +TNC_Result TNC_TNCC_GetAttribute( +/*in*/ TNC_IMCID imcID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_AttributeID attributeID, +/*in*/ TNC_UInt32 bufferLength, +/*out*/ TNC_BufferReference buffer, +/*out*/ TNC_UInt32 *pOutValueLength); + +TNC_Result TNC_TNCC_SetAttribute( +/*in*/ TNC_IMCID imcID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_AttributeID attributeID, +/*in*/ TNC_UInt32 bufferLength, +/*in*/ TNC_BufferReference buffer); + +TNC_Result TNC_TNCS_ReserveAdditionalIMCID( +/*in*/ TNC_IMCID imcID, +/*out*/ TNC_UInt32 *pOutIMCID); + TNC_Result TNC_TNCC_BindFunction( /*in*/ TNC_IMCID imcID, /*in*/ char *functionName, diff --git a/src/libtncif/tncifimv.h b/src/libtncif/tncifimv.h index 7a2394c06..3c9db0055 100644 --- a/src/libtncif/tncifimv.h +++ b/src/libtncif/tncifimv.h @@ -1,22 +1,22 @@ /* tncifimv.h * - * Trusted Network Connect IF-IMV API version 1.20 + * Trusted Network Connect IF-IMV API version 1.30 * Microsoft Windows DLL Platform Binding C Header - * February 5, 2007 + * October 14, 2011 * - * Copyright(c) 2005-2007, Trusted Computing Group, Inc. All rights + * Copyright(c) 2005-2011, Trusted Computing Group, Inc. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * - Redistributions of source code must retain the above copyright + * o Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright + * o Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * - Neither the name of the Trusted Computing Group nor the names of + * o Neither the name of the Trusted Computing Group nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. @@ -42,80 +42,134 @@ * respective owners. */ +/** + * @defgroup tncifimv tncifimv + * @{ @ingroup libtncif + */ + #ifndef TNCIFIMV_H_ #define TNCIFIMV_H_ #include "tncif.h" +#ifdef WIN32 +#ifdef TNC_IMV_EXPORTS +#define TNC_IMV_API __declspec(dllexport) +#else +#define TNC_IMV_API __declspec(dllimport) +#endif +#else +#define TNC_IMV_API +#endif + +/* Derived Types */ + typedef TNC_UInt32 TNC_IMVID; typedef TNC_UInt32 TNC_IMV_Action_Recommendation; typedef TNC_UInt32 TNC_IMV_Evaluation_Result; -typedef TNC_UInt32 TNC_AttributeID; /* Function pointers */ typedef TNC_Result (*TNC_IMV_InitializePointer)( - TNC_IMVID imvID, - TNC_Version minVersion, - TNC_Version maxVersion, - TNC_Version *pOutActualVersion); + TNC_IMVID imvID, + TNC_Version minVersion, + TNC_Version maxVersion, + TNC_Version *pOutActualVersion); typedef TNC_Result (*TNC_IMV_NotifyConnectionChangePointer)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_ConnectionState newState); + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_ConnectionState newState); typedef TNC_Result (*TNC_IMV_ReceiveMessagePointer)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_BufferReference message, - TNC_UInt32 messageLength, - TNC_MessageType messageType); + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_MessageType messageType); +typedef TNC_Result (*TNC_IMV_ReceiveMessageSOHPointer)( + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_BufferReference sohReportEntry, + TNC_UInt32 sohRELength, + TNC_MessageType systemHealthID); +typedef TNC_Result (*TNC_IMV_ReceiveMessageLongPointer)( + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_UInt32 messageFlags, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_VendorID messageVendorID, + TNC_MessageSubtype messageSubtype, + TNC_UInt32 sourceIMCID, + TNC_UInt32 destinationIMVID); typedef TNC_Result (*TNC_IMV_SolicitRecommendationPointer)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID); + TNC_IMVID imvID, + TNC_ConnectionID connectionID); typedef TNC_Result (*TNC_IMV_BatchEndingPointer)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID); + TNC_IMVID imvID, + TNC_ConnectionID connectionID); typedef TNC_Result (*TNC_IMV_TerminatePointer)( - TNC_IMVID imvID); + TNC_IMVID imvID); typedef TNC_Result (*TNC_TNCS_ReportMessageTypesPointer)( - TNC_IMVID imvID, - TNC_MessageTypeList supportedTypes, - TNC_UInt32 typeCount); + TNC_IMVID imvID, + TNC_MessageTypeList supportedTypes, + TNC_UInt32 typeCount); +typedef TNC_Result (*TNC_TNCS_ReportMessageTypesLongPointer)( + TNC_IMVID imvID, + TNC_VendorIDList supportedVendorIDs, + TNC_MessageSubtypeList supportedSubtypes, + TNC_UInt32 typeCount); typedef TNC_Result (*TNC_TNCS_SendMessagePointer)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_BufferReference message, - TNC_UInt32 messageLength, - TNC_MessageType messageType); + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_MessageType messageType); +typedef TNC_Result (*TNC_TNCS_SendMessageSOHPointer)( + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_BufferReference sohrReportEntry, + TNC_UInt32 sohrRELength); +typedef TNC_Result (*TNC_TNCS_SendMessageLongPointer)( + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_UInt32 messageFlags, + TNC_BufferReference message, + TNC_UInt32 messageLength, + TNC_VendorID messageVendorID, + TNC_MessageSubtype messageSubtype, + TNC_UInt32 destinationIMCID); typedef TNC_Result (*TNC_TNCS_RequestHandshakeRetryPointer)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_RetryReason reason); + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_RetryReason reason); typedef TNC_Result (*TNC_TNCS_ProvideRecommendationPointer)( - TNC_IMVID imvID, - TNC_ConnectionID connectionID, - TNC_IMV_Action_Recommendation recommendation, - TNC_IMV_Evaluation_Result evaluation); + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_IMV_Action_Recommendation recommendation, + TNC_IMV_Evaluation_Result evaluation); typedef TNC_Result (*TNC_TNCS_GetAttributePointer)( - TNC_IMVID imvID, -TNC_ConnectionID connectionID, -TNC_AttributeID attributeID, - TNC_UInt32 bufferLength, - TNC_BufferReference buffer, - TNC_UInt32 *pOutValueLength); -typedef TNC_Result (*TNC_TNCS_SetAttributePointer)( - TNC_IMVID imvID, + TNC_IMVID imvID, TNC_ConnectionID connectionID, -TNC_AttributeID attributeID, - TNC_UInt32 bufferLength, - TNC_BufferReference buffer); + TNC_AttributeID attributeID, + TNC_UInt32 bufferLength, + TNC_BufferReference buffer, + TNC_UInt32 *pOutValueLength); +typedef TNC_Result (*TNC_TNCS_SetAttributePointer)( + TNC_IMVID imvID, + TNC_ConnectionID connectionID, + TNC_AttributeID attributeID, + TNC_UInt32 bufferLength, + TNC_BufferReference buffer); +typedef TNC_Result (*TNC_TNCS_ReserveAdditionalIMVIDPointer)( + TNC_IMVID imvID, + TNC_UInt32 *pOutIMVID); typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)( - TNC_IMVID imvID, - char *functionName, - void **pOutfunctionPointer); + TNC_IMVID imvID, + char *functionName, + void **pOutfunctionPointer); typedef TNC_Result (*TNC_IMV_ProvideBindFunctionPointer)( - TNC_IMVID imvID, - TNC_TNCS_BindFunctionPointer bindFunction); + TNC_IMVID imvID, + TNC_TNCS_BindFunctionPointer bindFunction); /* Version Numbers */ @@ -150,42 +204,62 @@ typedef TNC_Result (*TNC_IMV_ProvideBindFunctionPointer)( /* Message Attribute ID Values */ -#define TNC_ATTRIBUTEID_PREFERRED_LANGUAGE ((TNC_AttributeID) 0x00000001) #define TNC_ATTRIBUTEID_REASON_STRING ((TNC_AttributeID) 0x00000002) #define TNC_ATTRIBUTEID_REASON_LANGUAGE ((TNC_AttributeID) 0x00000003) +#define TNC_ATTRIBUTEID_SOH ((TNC_AttributeID) 0x00559706) +#define TNC_ATTRIBUTEID_SSOH ((TNC_AttributeID) 0x00559707) +#define TNC_ATTRIBUTEID_PRIMARY_IMV_ID ((TNC_AttributeID) 0x00559710) /* IMV Functions */ -TNC_Result TNC_IMV_Initialize( +TNC_IMV_API TNC_Result TNC_IMV_Initialize( /*in*/ TNC_IMVID imvID, /*in*/ TNC_Version minVersion, /*in*/ TNC_Version maxVersion, /*in*/ TNC_Version *pOutActualVersion); -TNC_Result TNC_IMV_NotifyConnectionChange( +TNC_IMV_API TNC_Result TNC_IMV_NotifyConnectionChange( /*in*/ TNC_IMVID imvID, /*in*/ TNC_ConnectionID connectionID, /*in*/ TNC_ConnectionState newState); -TNC_Result TNC_IMV_ReceiveMessage( +TNC_IMV_API TNC_Result TNC_IMV_ReceiveMessage( /*in*/ TNC_IMVID imvID, /*in*/ TNC_ConnectionID connectionID, /*in*/ TNC_BufferReference messageBuffer, /*in*/ TNC_UInt32 messageLength, /*in*/ TNC_MessageType messageType); -TNC_Result TNC_IMV_SolicitRecommendation( +TNC_IMV_API TNC_Result TNC_IMV_ReceiveMessageSOH( +/*in*/ TNC_IMVID imvID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_BufferReference sohReportEntry, +/*in*/ TNC_UInt32 sohRELength, +/*in*/ TNC_MessageType systemHealthID); + +TNC_IMV_API TNC_Result TNC_IMV_ReceiveMessageLong( +/*in*/ TNC_IMVID imvID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_UInt32 messageFlags, +/*in*/ TNC_BufferReference message, +/*in*/ TNC_UInt32 messageLength, +/*in*/ TNC_VendorID messageVendorID, +/*in*/ TNC_MessageSubtype messageSubtype, +/*in*/ TNC_UInt32 sourceIMCID, +/*in*/ TNC_UInt32 destinationIMVID); + +TNC_IMV_API TNC_Result TNC_IMV_SolicitRecommendation( /*in*/ TNC_IMVID imvID, /*in*/ TNC_ConnectionID connectionID); -TNC_Result TNC_IMV_BatchEnding( +TNC_IMV_API TNC_Result TNC_IMV_BatchEnding( /*in*/ TNC_IMVID imvID, /*in*/ TNC_ConnectionID connectionID); -TNC_Result TNC_IMV_Terminate( +TNC_IMV_API TNC_Result TNC_IMV_Terminate( /*in*/ TNC_IMVID imvID); -TNC_Result TNC_IMV_ProvideBindFunction( +TNC_IMV_API TNC_Result TNC_IMV_ProvideBindFunction( /*in*/ TNC_IMVID imvID, /*in*/ TNC_TNCS_BindFunctionPointer bindFunction); @@ -196,6 +270,12 @@ TNC_Result TNC_TNCS_ReportMessageTypes( /*in*/ TNC_MessageTypeList supportedTypes, /*in*/ TNC_UInt32 typeCount); +TNC_Result TNC_TNCS_ReportMessageTypesLong( +/*in*/ TNC_IMVID imvID, +/*in*/ TNC_VendorIDList supportedVendorIDs, +/*in*/ TNC_MessageSubtypeList supportedSubtypes, +/*in*/ TNC_UInt32 typeCount); + TNC_Result TNC_TNCS_SendMessage( /*in*/ TNC_IMVID imvID, /*in*/ TNC_ConnectionID connectionID, @@ -203,6 +283,22 @@ TNC_Result TNC_TNCS_SendMessage( /*in*/ TNC_UInt32 messageLength, /*in*/ TNC_MessageType messageType); +TNC_Result TNC_TNCS_SendMessageSOH( +/*in*/ TNC_IMVID imvID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_BufferReference sohrReportEntry, +/*in*/ TNC_UInt32 sohrRELength); + +TNC_Result TNC_TNCS_SendMessageLong( +/*in*/ TNC_IMVID imvID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_UInt32 messageFlags, +/*in*/ TNC_BufferReference message, +/*in*/ TNC_UInt32 messageLength, +/*in*/ TNC_VendorID messageVendorID, +/*in*/ TNC_MessageSubtype messageSubtype, +/*in*/ TNC_UInt32 destinationIMCID); + TNC_Result TNC_TNCS_RequestHandshakeRetry( /*in*/ TNC_IMVID imvID, /*in*/ TNC_ConnectionID connectionID, @@ -222,13 +318,16 @@ TNC_Result TNC_TNCS_GetAttribute( /*out*/ TNC_BufferReference buffer, /*out*/ TNC_UInt32 *pOutValueLength); -TNC_Result TNC_TNCS_SetAttribute( +TNC_Result TNC_TNCS_ReserveAdditionalIMVID( /*in*/ TNC_IMVID imvID, -/*in*/ TNC_ConnectionID connectionID, -/*in*/ TNC_AttributeID attributeID, -/*in*/ TNC_UInt32 bufferLength, -/*in*/ TNC_BufferReference buffer); +/*out*/ TNC_UInt32 *pOutIMVID); +TNC_Result TNC_TNCS_SetAttribute( +/*in*/ TNC_IMVID imvID, +/*in*/ TNC_ConnectionID connectionID, +/*in*/ TNC_AttributeID attributeID, +/*in*/ TNC_UInt32 bufferLength, +/*in*/ TNC_BufferReference buffer); TNC_Result TNC_TNCS_BindFunction( /*in*/ TNC_IMVID imvID, /*in*/ char *functionName, diff --git a/src/pki/command.c b/src/pki/command.c index 0142b4ab7..07ba5bb1d 100644 --- a/src/pki/command.c +++ b/src/pki/command.c @@ -176,6 +176,13 @@ int command_usage(char *error) fprintf(out, "Error: %s\n", error); } fprintf(out, "strongSwan %s PKI tool\n", VERSION); + + if (active == help_idx) + { + fprintf(out, "loaded plugins: %s\n", + lib->plugins->loaded_plugins(lib->plugins)); + } + fprintf(out, "usage:\n"); if (active == help_idx) { diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index 97769fca6..0398c9dc9 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -67,11 +67,11 @@ static int issue() char *error = NULL, *keyid = NULL; identification_t *id = NULL; linked_list_t *san, *cdps, *ocsp, *permitted, *excluded, *policies, *mappings; - int lifetime = 1095; int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT; int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT; chunk_t serial = chunk_empty; chunk_t encoding = chunk_empty; + time_t lifetime = 1095; time_t not_before, not_after; x509_flag_t flags = 0; x509_t *x509; diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index 7852d8594..6813c98f7 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -55,11 +55,11 @@ static int self() char *file = NULL, *dn = NULL, *hex = NULL, *error = NULL, *keyid = NULL; identification_t *id = NULL; linked_list_t *san, *ocsp, *permitted, *excluded, *policies, *mappings; - int lifetime = 1095; int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT; int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT; chunk_t serial = chunk_empty; chunk_t encoding = chunk_empty; + time_t lifetime = 1095; time_t not_before, not_after; x509_flag_t flags = 0; x509_cert_policy_t *policy = NULL; diff --git a/src/pki/commands/signcrl.c b/src/pki/commands/signcrl.c index 9a21bd99c..827fd7318 100644 --- a/src/pki/commands/signcrl.c +++ b/src/pki/commands/signcrl.c @@ -124,7 +124,7 @@ static int sign_crl() int serial_len = 0; crl_reason_t reason = CRL_REASON_UNSPECIFIED; time_t thisUpdate, nextUpdate, date = time(NULL); - int lifetime = 15; + time_t lifetime = 15; linked_list_t *list, *cdps; enumerator_t *enumerator, *lastenum = NULL; x509_cdp_t *cdp; diff --git a/src/pluto/Android.mk b/src/pluto/Android.mk index 4c4bdca92..618f79c42 100644 --- a/src/pluto/Android.mk +++ b/src/pluto/Android.mk @@ -69,6 +69,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) \ LOCAL_MODULE := pluto +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index 68ba16346..3fd0e039c 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -102,6 +102,8 @@ endif dist_man_MANS = pluto.8 +EXTRA_DIST = Android.mk + # compile options ################# diff --git a/src/pluto/ca.c b/src/pluto/ca.c index 175c0b022..827b98121 100644 --- a/src/pluto/ca.c +++ b/src/pluto/ca.c @@ -219,7 +219,8 @@ cert_t* get_authcert(identification_t *subject, chunk_t keyid, } /* compare the subjectDistinguishedNames */ - if (!certificate->has_subject(certificate, subject)) + if (!(subject && certificate->has_subject(certificate, subject)) && + (subject || !keyid.ptr)) { continue; } diff --git a/src/pluto/defs.c b/src/pluto/defs.c index f83318e12..7f3a819de 100644 --- a/src/pluto/defs.c +++ b/src/pluto/defs.c @@ -16,6 +16,7 @@ #include <string.h> #include <stdio.h> #include <dirent.h> +#include <inttypes.h> #include <time.h> #include <sys/types.h> #include <sys/stat.h> @@ -91,8 +92,7 @@ mv_chunk(u_char **pos, chunk_t content) const char* check_expiry(time_t expiration_date, int warning_interval, bool strict) { - time_t now; - int time_left; + time_t now, time_left; if (expiration_date == UNDEFINED_TIME) return "ok (expires never)"; @@ -125,8 +125,8 @@ check_expiry(time_t expiration_date, int warning_interval, bool strict) time_left /= 60; unit = "minute"; } - snprintf(buf, 35, "warning (expires in %d %s%s)", time_left, - unit, (time_left == 1)?"":"s"); + snprintf(buf, 35, "warning (expires in %" PRIu64 " %s%s)", + (u_int64_t)time_left, unit, (time_left == 1) ? "" : "s"); return buf; } } diff --git a/src/pluto/keys.c b/src/pluto/keys.c index 9031fcda5..fb61bef5c 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -835,14 +835,7 @@ static void process_secret(secret_t *s, int whackfd) err_t ugh = NULL; s->kind = SECRET_PSK; /* default */ - if (*tok == '"' || *tok == '\'') - { - log_psk("PSK", s); - - /* old PSK format: just a string */ - ugh = process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("psk")) + if (tokeqword("psk")) { log_psk("PSK", s); @@ -989,13 +982,7 @@ static void process_secret_records(int whackfd) for (;;) { - if (tok[0] == '"' || tok[0] == '\'') - { - /* found key part */ - process_secret(s, whackfd); - break; - } - else if (tokeq(":")) + if (tokeq(":")) { /* found key part */ shift(); /* discard explicit separator */ diff --git a/src/pluto/log.c b/src/pluto/log.c index 0bfc8fa9e..f6fa226d5 100644 --- a/src/pluto/log.c +++ b/src/pluto/log.c @@ -868,19 +868,8 @@ DBG_dump(const char *label, const void *p, size_t len) static void show_loaded_plugins() { - char buf[BUF_LEN]; - plugin_t *plugin; - int len = 0; - enumerator_t *enumerator; - - buf[0] = '\0'; - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin, NULL)) - { - len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin->get_name(plugin)); - } - enumerator->destroy(enumerator); - whack_log(RC_COMMENT, "loaded plugins: %s", buf); + whack_log(RC_COMMENT, "loaded plugins: %s", + lib->plugins->loaded_plugins(lib->plugins)); } void show_status(bool all, const char *name) diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c index db5f2d941..dbc857ce2 100644 --- a/src/pluto/plutomain.c +++ b/src/pluto/plutomain.c @@ -264,26 +264,6 @@ static const char *pkcs11_init_args = NULL; /* options read by optionsfrom */ options_t *options; -/** - * Log loaded plugins - */ -static void print_plugins() -{ - char buf[BUF_LEN]; - plugin_t *plugin; - int len = 0; - enumerator_t *enumerator; - - buf[0] = '\0'; - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin, NULL)) - { - len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin->get_name(plugin)); - } - enumerator->destroy(enumerator); - DBG1(DBG_DMN, "loaded plugins: %s", buf); -} - int main(int argc, char **argv) { bool fork_desired = TRUE; @@ -675,6 +655,9 @@ int main(int argc, char **argv) close(fd); } + /* for uncritical pseudo random numbers */ + srand(time(NULL) + getpid()); + init_constants(); init_log("pluto"); @@ -698,7 +681,8 @@ int main(int argc, char **argv) { exit(SS_RC_INITIALIZATION_FAILED); } - print_plugins(); + DBG1(DBG_DMN, "loaded plugins: %s", + lib->plugins->loaded_plugins(lib->plugins)); init_builder(); if (!init_secret() || !init_crypto()) @@ -852,6 +836,7 @@ void exit_pluto(int status) delete_lock(); options->destroy(options); pluto_deinit(); + lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); lib->plugins->unload(lib->plugins); libhydra_deinit(); library_deinit(); diff --git a/src/scepclient/scepclient.c b/src/scepclient/scepclient.c index 2d364d654..0b54eeee3 100644 --- a/src/scepclient/scepclient.c +++ b/src/scepclient/scepclient.c @@ -276,25 +276,6 @@ usage(const char *message) } /** - * Log loaded plugins - */ -static void print_plugins() -{ - char buf[BUF_LEN]; - plugin_t *plugin; - int len = 0; - enumerator_t *enumerator; - - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin, NULL)) - { - len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin->get_name(plugin)); - } - enumerator->destroy(enumerator); - DBG1(DBG_LIB, " loaded plugins: %s", buf); -} - -/** * @brief main of scepclient * * @param argc number of arguments @@ -704,10 +685,6 @@ int main(int argc, char **argv) case 'x': /* --maxpolltime */ max_poll_time = atoi(optarg); - if (max_poll_time < 0) - { - usage("invalid maxpolltime specified"); - } continue; case 'a': /*--algorithm */ @@ -763,7 +740,8 @@ int main(int argc, char **argv) { exit_scepclient("plugin loading failed"); } - print_plugins(); + DBG1(DBG_LIB, " loaded plugins: %s", + lib->plugins->loaded_plugins(lib->plugins)); if ((filetype_out == 0) && (!request_ca_certificate)) { diff --git a/src/starter/Android.mk b/src/starter/Android.mk index 48e4b0b27..a82fe9385 100644 --- a/src/starter/Android.mk +++ b/src/starter/Android.mk @@ -30,10 +30,17 @@ endif LOCAL_MODULE := starter +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false +LOCAL_REQUIRED_MODULES := stroke +ifneq ($(strongswan_BUILD_PLUTO),) +LOCAL_REQUIRED_MODULES += whack +endif + LOCAL_SHARED_LIBRARIES += libstrongswan libhydra libfreeswan include $(BUILD_EXECUTABLE) diff --git a/src/starter/Makefile.am b/src/starter/Makefile.am index ba97c060f..94ddf5aba 100644 --- a/src/starter/Makefile.am +++ b/src/starter/Makefile.am @@ -28,7 +28,7 @@ AM_CFLAGS = \ AM_YFLAGS = -v -d starter_LDADD = defs.o $(top_builddir)/src/libfreeswan/libfreeswan.a $(top_builddir)/src/libstrongswan/libstrongswan.la $(top_builddir)/src/libhydra/libhydra.la $(SOCKLIB) -EXTRA_DIST = keywords.txt ipsec.conf +EXTRA_DIST = keywords.txt ipsec.conf Android.mk MAINTAINERCLEANFILES = keywords.c BUILT_SOURCES = parser.h diff --git a/src/starter/confread.c b/src/starter/confread.c index ce69fd724..2fb329c85 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -135,7 +135,7 @@ static void load_setup(starter_config_t *cfg, config_parsed_t *cfgp) kw_token_t token = kw->entry->token; - if (token < KW_SETUP_FIRST || token > KW_SETUP_LAST) + if ((int)token < KW_SETUP_FIRST || token > KW_SETUP_LAST) { plog("# unsupported keyword '%s' in config setup", kw->entry->name); cfg->err++; diff --git a/src/starter/confread.h b/src/starter/confread.h index 19c404e2e..655c97084 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -198,12 +198,12 @@ struct starter_config { char *plutostderrlog; bool uniqueids; u_int overridemtu; - u_int crlcheckinterval; + time_t crlcheckinterval; bool cachecrls; strict_t strictcrlpolicy; bool nocrsend; bool nat_traversal; - u_int keep_alive; + time_t keep_alive; u_int force_keepalive; char *virtual_private; char *pkcs11module; diff --git a/src/starter/invokepluto.c b/src/starter/invokepluto.c index 11c13abe2..70c0692ea 100644 --- a/src/starter/invokepluto.c +++ b/src/starter/invokepluto.c @@ -184,7 +184,7 @@ starter_start_pluto (starter_config_t *cfg, bool no_fork, bool attach_gdb) static char buf1[15]; arg[argc++] = "--crlcheckinterval"; - snprintf(buf1, sizeof(buf1), "%u", cfg->setup.crlcheckinterval); + snprintf(buf1, sizeof(buf1), "%d", (int)cfg->setup.crlcheckinterval); arg[argc++] = buf1; } if (cfg->setup.cachecrls) @@ -212,7 +212,7 @@ starter_start_pluto (starter_config_t *cfg, bool no_fork, bool attach_gdb) static char buf2[15]; arg[argc++] = "--keep_alive"; - snprintf(buf2, sizeof(buf2), "%u", cfg->setup.keep_alive); + snprintf(buf2, sizeof(buf2), "%d", (int)cfg->setup.keep_alive); arg[argc++] = buf2; } if (cfg->setup.virtual_private) diff --git a/src/starter/y.output b/src/starter/y.output new file mode 100644 index 000000000..702cb1f9c --- /dev/null +++ b/src/starter/y.output @@ -0,0 +1,351 @@ +Grammar + + 0 $accept: config_file $end + + 1 config_file: config_file section_or_include + 2 | /* empty */ + + 3 section_or_include: FILE_VERSION STRING EOL + + 4 $@1: /* empty */ + + 5 section_or_include: CONFIG SETUP EOL $@1 kw_section + + 6 $@2: /* empty */ + + 7 section_or_include: CONN STRING EOL $@2 kw_section + + 8 $@3: /* empty */ + + 9 section_or_include: CA STRING EOL $@3 kw_section + + 10 $@4: /* empty */ + + 11 section_or_include: INCLUDE STRING $@4 EOL + 12 | EOL + + 13 kw_section: FIRST_SPACES statement_kw EOL kw_section + 14 | /* empty */ + + 15 statement_kw: STRING EQUAL STRING + 16 | STRING EQUAL + 17 | /* empty */ + + +Terminals, with rules where they appear + +$end (0) 0 +error (256) +EQUAL (258) 15 16 +FIRST_SPACES (259) 13 +EOL (260) 3 5 7 9 11 12 13 +CONFIG (261) 5 +SETUP (262) 5 +CONN (263) 7 +CA (264) 9 +INCLUDE (265) 11 +FILE_VERSION (266) 3 +STRING (267) 3 7 9 11 15 16 + + +Nonterminals, with rules where they appear + +$accept (13) + on left: 0 +config_file (14) + on left: 1 2, on right: 0 1 +section_or_include (15) + on left: 3 5 7 9 11 12, on right: 1 +$@1 (16) + on left: 4, on right: 5 +$@2 (17) + on left: 6, on right: 7 +$@3 (18) + on left: 8, on right: 9 +$@4 (19) + on left: 10, on right: 11 +kw_section (20) + on left: 13 14, on right: 5 7 9 13 +statement_kw (21) + on left: 15 16 17, on right: 13 + + +state 0 + + 0 $accept: . config_file $end + + $default reduce using rule 2 (config_file) + + config_file go to state 1 + + +state 1 + + 0 $accept: config_file . $end + 1 config_file: config_file . section_or_include + + $end shift, and go to state 2 + EOL shift, and go to state 3 + CONFIG shift, and go to state 4 + CONN shift, and go to state 5 + CA shift, and go to state 6 + INCLUDE shift, and go to state 7 + FILE_VERSION shift, and go to state 8 + + section_or_include go to state 9 + + +state 2 + + 0 $accept: config_file $end . + + $default accept + + +state 3 + + 12 section_or_include: EOL . + + $default reduce using rule 12 (section_or_include) + + +state 4 + + 5 section_or_include: CONFIG . SETUP EOL $@1 kw_section + + SETUP shift, and go to state 10 + + +state 5 + + 7 section_or_include: CONN . STRING EOL $@2 kw_section + + STRING shift, and go to state 11 + + +state 6 + + 9 section_or_include: CA . STRING EOL $@3 kw_section + + STRING shift, and go to state 12 + + +state 7 + + 11 section_or_include: INCLUDE . STRING $@4 EOL + + STRING shift, and go to state 13 + + +state 8 + + 3 section_or_include: FILE_VERSION . STRING EOL + + STRING shift, and go to state 14 + + +state 9 + + 1 config_file: config_file section_or_include . + + $default reduce using rule 1 (config_file) + + +state 10 + + 5 section_or_include: CONFIG SETUP . EOL $@1 kw_section + + EOL shift, and go to state 15 + + +state 11 + + 7 section_or_include: CONN STRING . EOL $@2 kw_section + + EOL shift, and go to state 16 + + +state 12 + + 9 section_or_include: CA STRING . EOL $@3 kw_section + + EOL shift, and go to state 17 + + +state 13 + + 11 section_or_include: INCLUDE STRING . $@4 EOL + + $default reduce using rule 10 ($@4) + + $@4 go to state 18 + + +state 14 + + 3 section_or_include: FILE_VERSION STRING . EOL + + EOL shift, and go to state 19 + + +state 15 + + 5 section_or_include: CONFIG SETUP EOL . $@1 kw_section + + $default reduce using rule 4 ($@1) + + $@1 go to state 20 + + +state 16 + + 7 section_or_include: CONN STRING EOL . $@2 kw_section + + $default reduce using rule 6 ($@2) + + $@2 go to state 21 + + +state 17 + + 9 section_or_include: CA STRING EOL . $@3 kw_section + + $default reduce using rule 8 ($@3) + + $@3 go to state 22 + + +state 18 + + 11 section_or_include: INCLUDE STRING $@4 . EOL + + EOL shift, and go to state 23 + + +state 19 + + 3 section_or_include: FILE_VERSION STRING EOL . + + $default reduce using rule 3 (section_or_include) + + +state 20 + + 5 section_or_include: CONFIG SETUP EOL $@1 . kw_section + + FIRST_SPACES shift, and go to state 24 + + $default reduce using rule 14 (kw_section) + + kw_section go to state 25 + + +state 21 + + 7 section_or_include: CONN STRING EOL $@2 . kw_section + + FIRST_SPACES shift, and go to state 24 + + $default reduce using rule 14 (kw_section) + + kw_section go to state 26 + + +state 22 + + 9 section_or_include: CA STRING EOL $@3 . kw_section + + FIRST_SPACES shift, and go to state 24 + + $default reduce using rule 14 (kw_section) + + kw_section go to state 27 + + +state 23 + + 11 section_or_include: INCLUDE STRING $@4 EOL . + + $default reduce using rule 11 (section_or_include) + + +state 24 + + 13 kw_section: FIRST_SPACES . statement_kw EOL kw_section + + STRING shift, and go to state 28 + + $default reduce using rule 17 (statement_kw) + + statement_kw go to state 29 + + +state 25 + + 5 section_or_include: CONFIG SETUP EOL $@1 kw_section . + + $default reduce using rule 5 (section_or_include) + + +state 26 + + 7 section_or_include: CONN STRING EOL $@2 kw_section . + + $default reduce using rule 7 (section_or_include) + + +state 27 + + 9 section_or_include: CA STRING EOL $@3 kw_section . + + $default reduce using rule 9 (section_or_include) + + +state 28 + + 15 statement_kw: STRING . EQUAL STRING + 16 | STRING . EQUAL + + EQUAL shift, and go to state 30 + + +state 29 + + 13 kw_section: FIRST_SPACES statement_kw . EOL kw_section + + EOL shift, and go to state 31 + + +state 30 + + 15 statement_kw: STRING EQUAL . STRING + 16 | STRING EQUAL . + + STRING shift, and go to state 32 + + $default reduce using rule 16 (statement_kw) + + +state 31 + + 13 kw_section: FIRST_SPACES statement_kw EOL . kw_section + + FIRST_SPACES shift, and go to state 24 + + $default reduce using rule 14 (kw_section) + + kw_section go to state 33 + + +state 32 + + 15 statement_kw: STRING EQUAL STRING . + + $default reduce using rule 15 (statement_kw) + + +state 33 + + 13 kw_section: FIRST_SPACES statement_kw EOL kw_section . + + $default reduce using rule 13 (kw_section) diff --git a/src/stroke/Android.mk b/src/stroke/Android.mk index 833130e25..69b3e54ca 100644 --- a/src/stroke/Android.mk +++ b/src/stroke/Android.mk @@ -15,6 +15,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := stroke +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/stroke/Makefile.am b/src/stroke/Makefile.am index 6eee8cd6c..f93680b64 100644 --- a/src/stroke/Makefile.am +++ b/src/stroke/Makefile.am @@ -5,7 +5,7 @@ stroke.c stroke_msg.h stroke_keywords.c stroke_keywords.h stroke_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la $(SOCKLIB) INCLUDES = -I$(top_srcdir)/src/libstrongswan -EXTRA_DIST = stroke_keywords.txt +EXTRA_DIST = stroke_keywords.txt Android.mk BUILT_SOURCES = stroke_keywords.c MAINTAINERCLEANFILES = stroke_keywords.c AM_CFLAGS = -DIPSEC_PIDDIR=\"${piddir}\" diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index e70245362..6aadd3ec9 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -392,7 +392,7 @@ static void exit_usage(char *error) printf(" where: START and optional END define the clients source IP\n"); printf(" Set loglevel for a logging type:\n"); printf(" stroke loglevel TYPE LEVEL\n"); - printf(" where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|enc|tnc|imc|imv|pts|tls|lib\n"); + printf(" where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|lib\n"); printf(" LEVEL is -1|0|1|2|3|4\n"); printf(" Show connection status:\n"); printf(" stroke status\n"); diff --git a/src/whack/Android.mk b/src/whack/Android.mk index 08d96a071..bf5ec0e98 100644 --- a/src/whack/Android.mk +++ b/src/whack/Android.mk @@ -18,6 +18,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := whack +LOCAL_MODULE_TAGS := optional + LOCAL_ARM_MODE := arm LOCAL_PRELINK_MODULE := false diff --git a/src/whack/Makefile.am b/src/whack/Makefile.am index fa4c9959c..23374475e 100644 --- a/src/whack/Makefile.am +++ b/src/whack/Makefile.am @@ -15,3 +15,4 @@ $(top_builddir)/src/libfreeswan/libfreeswan.a AM_CFLAGS = -DDEBUG -DIPSEC_PIDDIR=\"${piddir}\" +EXTRA_DIST = Android.mk diff --git a/testing/hosts/winnetou/etc/openssl/index.txt b/testing/hosts/winnetou/etc/openssl/index.txt index 55588a2f7..728c18c12 100644 --- a/testing/hosts/winnetou/etc/openssl/index.txt +++ b/testing/hosts/winnetou/etc/openssl/index.txt @@ -16,7 +16,7 @@ R 100620195806Z 100406093001Z,superseded 0F unknown /C=CH/O=Linux strongSwan/OU= R 111007105811Z 111017123709Z,superseded 10 unknown /C=CH/O=Linux strongSwan/OU=SHA-256/CN=moon.strongswan.org R 111007121250Z 111017123712Z,superseded 11 unknown /C=CH/O=Linux strongSwan/OU=SHA-384/CN=carol@strongswan.org R 111007122112Z 111017123715Z,superseded 12 unknown /C=CH/O=Linux strongSwan/OU=SHA-512/CN=dave@strongswan.org -V 120224075857Z 13 unknown /C=CH/O=Linux strongSwan/OU=OCSP/CN=carol@strongswan.org +R 120224075857Z 120315063217Z,superseded 13 unknown /C=CH/O=Linux strongSwan/OU=OCSP/CN=carol@strongswan.org V 120425210745Z 14 unknown /C=CH/O=Linux strongSwan/CN=winnetou.strongswan.org V 140406120117Z 15 unknown /C=CH/O=Linux strongSwan/OU=Research/serialNumber=002/CN=carol@strongswan.org V 140826095904Z 16 unknown /C=CH/O=Linux strongSwan/CN=sun.strongswan.org @@ -36,3 +36,4 @@ V 151119165922Z 23 unknown /C=CH/O=Linux strongSwan/OU=Virtual VPN Gateway/CN=m V 161015124507Z 24 unknown /C=CH/O=Linux strongSwan/OU=SHA-224/CN=moon.strongswan.org V 161015124759Z 25 unknown /C=CH/O=Linux strongSwan/OU=SHA-384/CN=carol@strongswan.org V 161015125030Z 26 unknown /C=CH/O=Linux strongSwan/OU=SHA-512/CN=dave@strongswan.org +V 170314064200Z 27 unknown /C=CH/O=Linux strongSwan/OU=OCSP/CN=carol@strongswan.org diff --git a/testing/hosts/winnetou/etc/openssl/index.txt.old b/testing/hosts/winnetou/etc/openssl/index.txt.old index d7b907224..b9ab05a4f 100644 --- a/testing/hosts/winnetou/etc/openssl/index.txt.old +++ b/testing/hosts/winnetou/etc/openssl/index.txt.old @@ -16,7 +16,7 @@ R 100620195806Z 100406093001Z,superseded 0F unknown /C=CH/O=Linux strongSwan/OU= R 111007105811Z 111017123709Z,superseded 10 unknown /C=CH/O=Linux strongSwan/OU=SHA-256/CN=moon.strongswan.org R 111007121250Z 111017123712Z,superseded 11 unknown /C=CH/O=Linux strongSwan/OU=SHA-384/CN=carol@strongswan.org R 111007122112Z 111017123715Z,superseded 12 unknown /C=CH/O=Linux strongSwan/OU=SHA-512/CN=dave@strongswan.org -V 120224075857Z 13 unknown /C=CH/O=Linux strongSwan/OU=OCSP/CN=carol@strongswan.org +R 120224075857Z 120315063217Z,superseded 13 unknown /C=CH/O=Linux strongSwan/OU=OCSP/CN=carol@strongswan.org V 120425210745Z 14 unknown /C=CH/O=Linux strongSwan/CN=winnetou.strongswan.org V 140406120117Z 15 unknown /C=CH/O=Linux strongSwan/OU=Research/serialNumber=002/CN=carol@strongswan.org V 140826095904Z 16 unknown /C=CH/O=Linux strongSwan/CN=sun.strongswan.org @@ -35,3 +35,4 @@ V 150803083841Z 22 unknown /C=CH/O=Linux strongSwan/CN=aaa.strongswan.org V 151119165922Z 23 unknown /C=CH/O=Linux strongSwan/OU=Virtual VPN Gateway/CN=mars.strongswan.org V 161015124507Z 24 unknown /C=CH/O=Linux strongSwan/OU=SHA-224/CN=moon.strongswan.org V 161015124759Z 25 unknown /C=CH/O=Linux strongSwan/OU=SHA-384/CN=carol@strongswan.org +V 161015125030Z 26 unknown /C=CH/O=Linux strongSwan/OU=SHA-512/CN=dave@strongswan.org diff --git a/testing/hosts/winnetou/etc/openssl/newcerts/27.pem b/testing/hosts/winnetou/etc/openssl/newcerts/27.pem new file mode 100644 index 000000000..a1c57b0f0 --- /dev/null +++ b/testing/hosts/winnetou/etc/openssl/newcerts/27.pem @@ -0,0 +1,95 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 39 (0x27) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=CH, O=Linux strongSwan, CN=strongSwan Root CA + Validity + Not Before: Mar 15 06:42:00 2012 GMT + Not After : Mar 14 06:42:00 2017 GMT + Subject: C=CH, O=Linux strongSwan, OU=OCSP, CN=carol@strongswan.org + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:b0:33:dd:ed:c0:d6:9d:01:de:eb:08:c4:f9:6a: + e9:46:10:f6:a4:cd:7d:aa:79:4b:c2:33:1f:61:40: + 40:de:06:9f:b8:2a:b0:84:cd:a7:79:c8:ee:a7:24: + 69:08:04:89:f8:7b:62:7e:03:9e:0a:d9:df:ff:7c: + 20:3c:a7:b1:86:7f:cc:e6:ad:0c:7e:6f:c4:9b:31: + 55:57:92:df:7b:94:86:f1:27:3a:0e:fa:0b:92:58: + ad:64:8a:40:46:5d:87:ca:11:20:03:ad:86:68:a5: + 0c:8a:19:ce:36:d0:55:bf:1f:00:47:c9:1a:af:c5: + ad:14:3c:d7:0c:9e:28:d9:61:1b:a2:a8:b7:f1:56: + a7:d9:3b:fa:09:08:2c:9b:75:e3:30:64:5e:93:80: + 48:94:35:0d:97:ca:ac:57:66:02:86:b6:1b:6b:f1: + 4a:86:30:74:48:38:46:1a:7d:07:61:30:15:33:b0: + 9d:50:fc:4d:8c:16:1e:30:13:9f:07:04:7a:3b:92: + 54:33:c7:3a:0b:67:e2:ba:46:b0:b3:0d:79:7f:e4: + ed:81:bd:34:cb:e5:30:f3:af:d4:dd:52:3e:f5:13: + 0e:c0:79:f8:43:c7:f5:b9:b0:12:6a:46:38:db:61: + 44:c8:4a:68:7b:77:34:68:63:ef:88:16:be:ae:89: + ff:89 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Subject Key Identifier: + C5:E8:58:D7:63:B0:B8:D4:2E:22:04:E1:CB:35:34:95:DA:74:F0:E6 + X509v3 Authority Key Identifier: + keyid:5D:A7:DD:70:06:51:32:7E:E7:B6:6D:B3:B5:E5:E0:60:EA:2E:4D:EF + DirName:/C=CH/O=Linux strongSwan/CN=strongSwan Root CA + serial:00 + + X509v3 Subject Alternative Name: + email:carol@strongswan.org + Authority Information Access: + OCSP - URI:http://ocsp.strongswan.org:8880 + + X509v3 CRL Distribution Points: + URI:http://crl.strongswan.org/strongswan.crl + + Signature Algorithm: sha256WithRSAEncryption + b6:2d:d8:bb:40:e9:cf:a9:33:31:6c:91:c7:40:79:8c:5f:89: + 8e:26:d8:ef:91:67:da:71:75:f9:27:84:21:c3:6c:d1:a5:fb: + 50:de:b2:02:ad:3c:a4:6b:40:58:30:41:c7:bd:31:ca:df:77: + 00:c9:ac:5b:10:e3:66:71:6c:be:4a:49:7e:58:92:de:f4:16: + 51:12:00:2c:33:e2:2c:b5:e5:d4:6e:36:a2:50:ba:86:e3:c6: + bb:50:a2:e5:11:69:c4:86:91:fc:4d:65:7e:09:49:bd:d2:ae: + cd:70:f8:98:5d:a8:b6:cf:38:c3:19:49:fd:8b:72:3b:1a:cc: + fc:19:c9:c1:36:b2:39:ba:ed:9a:cd:db:2d:27:15:b0:ba:8a: + 64:4a:5c:8f:ff:db:78:7d:cd:78:c3:c6:13:ba:93:7b:b7:57: + da:a3:f2:16:9f:f7:24:95:57:df:f4:4f:c5:9f:d6:12:b1:69: + 39:a7:5a:88:9c:74:be:f7:b0:f3:b4:89:82:46:57:de:7d:a1: + 42:a2:c2:de:1c:37:19:66:60:2a:df:ed:25:e3:72:d3:f9:9b: + 84:05:b6:97:6a:63:63:5c:30:5d:01:7a:15:c4:6e:2c:a0:21: + d2:31:30:98:60:94:26:44:9a:08:b4:85:8d:52:00:98:ef:cb: + 07:4f:b7:8e +-----BEGIN CERTIFICATE----- +MIIEWzCCA0OgAwIBAgIBJzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ +MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS +b290IENBMB4XDTEyMDMxNTA2NDIwMFoXDTE3MDMxNDA2NDIwMFowVjELMAkGA1UE +BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDTALBgNVBAsTBE9DU1Ax +HTAbBgNVBAMUFGNhcm9sQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAsDPd7cDWnQHe6wjE+WrpRhD2pM19qnlLwjMfYUBA3gaf +uCqwhM2necjupyRpCASJ+HtifgOeCtnf/3wgPKexhn/M5q0Mfm/EmzFVV5Lfe5SG +8Sc6DvoLklitZIpARl2HyhEgA62GaKUMihnONtBVvx8AR8kar8WtFDzXDJ4o2WEb +oqi38Van2Tv6CQgsm3XjMGRek4BIlDUNl8qsV2YChrYba/FKhjB0SDhGGn0HYTAV +M7CdUPxNjBYeMBOfBwR6O5JUM8c6C2fiukawsw15f+Ttgb00y+Uw86/U3VI+9RMO +wHn4Q8f1ubASakY422FEyEpoe3c0aGPviBa+ron/iQIDAQABo4IBQzCCAT8wCQYD +VR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFMXoWNdjsLjULiIE4cs1NJXa +dPDmMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYD +VQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ry +b25nU3dhbiBSb290IENBggEAMB8GA1UdEQQYMBaBFGNhcm9sQHN0cm9uZ3N3YW4u +b3JnMDsGCCsGAQUFBwEBBC8wLTArBggrBgEFBQcwAYYfaHR0cDovL29jc3Auc3Ry +b25nc3dhbi5vcmc6ODg4MDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0 +cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQC2 +Ldi7QOnPqTMxbJHHQHmMX4mOJtjvkWfacXX5J4Qhw2zRpftQ3rICrTyka0BYMEHH +vTHK33cAyaxbEONmcWy+Skl+WJLe9BZREgAsM+IsteXUbjaiULqG48a7UKLlEWnE +hpH8TWV+CUm90q7NcPiYXai2zzjDGUn9i3I7Gsz8GcnBNrI5uu2azdstJxWwuopk +SlyP/9t4fc14w8YTupN7t1fao/IWn/cklVff9E/Fn9YSsWk5p1qInHS+97DztImC +RlfefaFCosLeHDcZZmAq3+0l43LT+ZuEBbaXamNjXDBdAXoVxG4soCHSMTCYYJQm +RJoItIWNUgCY78sHT7eO +-----END CERTIFICATE----- diff --git a/testing/hosts/winnetou/etc/openssl/serial b/testing/hosts/winnetou/etc/openssl/serial index f64f5d8d8..9902f1784 100644 --- a/testing/hosts/winnetou/etc/openssl/serial +++ b/testing/hosts/winnetou/etc/openssl/serial @@ -1 +1 @@ -27 +28 diff --git a/testing/hosts/winnetou/etc/openssl/serial.old b/testing/hosts/winnetou/etc/openssl/serial.old index 6f4247a62..f64f5d8d8 100644 --- a/testing/hosts/winnetou/etc/openssl/serial.old +++ b/testing/hosts/winnetou/etc/openssl/serial.old @@ -1 +1 @@ -26 +27 diff --git a/testing/scripts/build-umlrootfs b/testing/scripts/build-umlrootfs index 75fe5c69f..37d1de66b 100755 --- a/testing/scripts/build-umlrootfs +++ b/testing/scripts/build-umlrootfs @@ -192,6 +192,11 @@ then echo -n " --enable-eap-tnc" >> $INSTALLSHELL fi +if [ "$USE_TNC_PDP" = "yes" ] +then + echo -n " --enable-tnc-pdp" >> $INSTALLSHELL +fi + if [ "$USE_TNC_IMC" = "yes" ] then echo -n " --enable-tnc-imc" >> $INSTALLSHELL @@ -237,6 +242,16 @@ then echo -n " --enable-imv-scanner" >> $INSTALLSHELL fi +if [ "$USE_IMC_ATTESTATION" = "yes" ] +then + echo -n " --enable-imc-attestation" >> $INSTALLSHELL +fi + +if [ "$USE_IMV_ATTESTATION" = "yes" ] +then + echo -n " --enable-imv-attestation" >> $INSTALLSHELL +fi + if [ "$USE_SQL" = "yes" ] then echo -n " --enable-sql --enable-sqlite" >> $INSTALLSHELL @@ -342,6 +357,16 @@ then echo -n " --enable-whitelist" >> $INSTALLSHELL fi +if [ "$USE_PKCS8" = "yes" ] +then + echo -n " --enable-pkcs8" >> $INSTALLSHELL +fi + +if [ "$USE_IFMAP" = "yes" ] +then + echo -n " --enable-tnc-ifmap" >> $INSTALLSHELL +fi + if [ "$USE_CISCO_QUIRKS" = "yes" ] then echo -n " --enable-cisco-quirks" >> $INSTALLSHELL diff --git a/testing/testing.conf b/testing/testing.conf index aff92bdd7..88aa8e15a 100755 --- a/testing/testing.conf +++ b/testing/testing.conf @@ -19,19 +19,19 @@ UMLTESTDIR=~/strongswan-testing # Bzipped kernel sources # (file extension .tar.bz2 required) -KERNEL=$UMLTESTDIR/linux-2.6.38.5.tar.bz2 +KERNEL=$UMLTESTDIR/linux-3.1.5.tar.bz2 # Extract kernel version KERNELVERSION=`basename $KERNEL .tar.bz2 | sed -e 's/linux-//'` # Kernel configuration file -KERNELCONFIG=$UMLTESTDIR/.config-2.6.38 +KERNELCONFIG=$UMLTESTDIR/.config-3.1 # Bzipped uml patch for kernel -UMLPATCH=$UMLTESTDIR/ha-2.6.37.patch.bz2 +UMLPATCH=$UMLTESTDIR/ha-3.0.patch.bz2 # Bzipped source of strongSwan -STRONGSWAN=$UMLTESTDIR/strongswan-4.5.2.tar.bz2 +STRONGSWAN=$UMLTESTDIR/strongswan-4.6.2.tar.bz2 # strongSwan compile options (use "yes" or "no") USE_LIBCURL="yes" @@ -46,6 +46,7 @@ USE_EAP_TLS="yes" USE_EAP_TTLS="yes" USE_EAP_PEAP="yes" USE_EAP_TNC="yes" +USE_TNC_PDP="yes" USE_TNC_IMC="yes" USE_TNC_IMV="yes" USE_TNCCS_11="yes" @@ -55,6 +56,8 @@ USE_IMC_TEST="yes" USE_IMV_TEST="yes" USE_IMC_SCANNER="yes" USE_IMV_SCANNER="yes" +USE_IMC_ATTESTATION="yes" +USE_IMV_ATTESTATION="yes" USE_SQL="yes" USE_MEDIATION="yes" USE_OPENSSL="yes" @@ -76,13 +79,15 @@ USE_GCM="yes" USE_HA="yes" USE_AF_ALG="yes" USE_WHITELIST="yes" +USE_PKCS8="yes" +USE_IFMAP="no" USE_CISCO_QUIRKS="no" # Gentoo linux root filesystem -ROOTFS=$UMLTESTDIR/gentoo-fs-20101120.tar.bz2 +ROOTFS=$UMLTESTDIR/gentoo-fs-20111212.tar.bz2 # Size of the finished root filesystem in MB -ROOTFSSIZE=800 +ROOTFSSIZE=850 # Amount of Memory to use per UML [MB]. # If "auto" is stated 1/12 of total host ram will be used. @@ -176,7 +181,7 @@ bob,fec2::10" # The hosts stated here will be created. Possible values # are sun, moon, dave, carol, alice, venus, bob, winnetou. # It's fine to make them all unless you don't have much -# ressources. In this case we assume you know what you do! +# resources. In this case we assume you know what you do! # STRONGSWANHOSTS="sun moon dave carol alice venus bob winnetou" diff --git a/testing/tests/ikev2/esp-alg-md5-128/description.txt b/testing/tests/ikev2/esp-alg-md5-128/description.txt new file mode 100644 index 000000000..7a14be2ae --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/description.txt @@ -0,0 +1,3 @@ +Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the ESP cipher suite +<b>3DES_CBC / HMAC_MD5_128</b> by defining <b>esp=3des-md5_128!</b> in ipsec.conf. +A ping from <b>carol</b> to <b>alice</b> successfully checks the established tunnel. diff --git a/testing/tests/ikev2/esp-alg-md5-128/evaltest.dat b/testing/tests/ikev2/esp-alg-md5-128/evaltest.dat new file mode 100644 index 000000000..d65d71240 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/evaltest.dat @@ -0,0 +1,9 @@ +moon::ipsec statusall::rw.*INSTALLED::YES +carol::ipsec statusall::home.*INSTALLED::YES +carol::ping -c 1 -s 120 -p deadbeef PH_IP_ALICE::128 bytes from PH_IP_ALICE: icmp_seq=1::YES +moon::ipsec statusall::3DES_CBC/HMAC_MD5_128::YES +carol::ipsec statusall::3DES_CBC/HMAC_MD5_128::YES +moon::ip xfrm state::auth hmac(md5)::YES +carol::ip xfrm state::auth hmac(md5)::YES +moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP.*length 184::YES +moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP.*length 184::YES diff --git a/testing/tests/ikev2/esp-alg-md5-128/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/esp-alg-md5-128/hosts/carol/etc/ipsec.conf new file mode 100755 index 000000000..09797799f --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/hosts/carol/etc/ipsec.conf @@ -0,0 +1,25 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=yes + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + ike=3des-md5-modp1024! + esp=3des-md5_128! + +conn home + left=PH_IP_CAROL + leftfirewall=yes + leftcert=carolCert.pem + leftid=carol@strongswan.org + right=PH_IP_MOON + rightsubnet=10.1.0.0/16 + rightid=@moon.strongswan.org + auto=add diff --git a/testing/tests/ikev2/esp-alg-md5-128/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/esp-alg-md5-128/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..339b56987 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/hosts/carol/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac xcbc stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/esp-alg-md5-128/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/esp-alg-md5-128/hosts/moon/etc/ipsec.conf new file mode 100755 index 000000000..ae83aaf58 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/hosts/moon/etc/ipsec.conf @@ -0,0 +1,24 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=yes + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + ike=3des-md5-modp1024! + esp=3des-md5_128! + +conn rw + left=PH_IP_MOON + leftfirewall=yes + leftcert=moonCert.pem + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + right=%any + auto=add diff --git a/testing/tests/ikev2/esp-alg-md5-128/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/esp-alg-md5-128/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..339b56987 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/hosts/moon/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac xcbc stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/esp-alg-md5-128/posttest.dat b/testing/tests/ikev2/esp-alg-md5-128/posttest.dat new file mode 100644 index 000000000..94a400606 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/posttest.dat @@ -0,0 +1,4 @@ +moon::ipsec stop +carol::ipsec stop +moon::/etc/init.d/iptables stop 2> /dev/null +carol::/etc/init.d/iptables stop 2> /dev/null diff --git a/testing/tests/ikev2/esp-alg-md5-128/pretest.dat b/testing/tests/ikev2/esp-alg-md5-128/pretest.dat new file mode 100644 index 000000000..3c3df0196 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/pretest.dat @@ -0,0 +1,7 @@ +moon::/etc/init.d/iptables start 2> /dev/null +carol::/etc/init.d/iptables start 2> /dev/null +moon::ipsec start +carol::ipsec start +carol::sleep 1 +carol::ipsec up home +carol::sleep 1 diff --git a/testing/tests/ikev2/esp-alg-md5-128/test.conf b/testing/tests/ikev2/esp-alg-md5-128/test.conf new file mode 100644 index 000000000..9cd583b16 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-md5-128/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# UML instances used for this test + +# All UML instances that are required for this test +# +UMLHOSTS="alice moon carol winnetou" + +# Corresponding block diagram +# +DIAGRAM="a-m-c-w.png" + +# UML instances on which tcpdump is to be started +# +TCPDUMPHOSTS="moon" + +# UML instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon carol" diff --git a/testing/tests/ikev2/esp-alg-sha1-160/description.txt b/testing/tests/ikev2/esp-alg-sha1-160/description.txt new file mode 100644 index 000000000..caa1d3f8a --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/description.txt @@ -0,0 +1,3 @@ +Roadwarrior <b>carol</b> proposes to gateway <b>moon</b> the ESP cipher suite +<b>AES_CBC_128 / HMAC_SHA1_160</b> by defining <b>esp=aes128-sha1_160!</b> in ipsec.conf. +A ping from <b>carol</b> to <b>alice</b> successfully checks the established tunnel. diff --git a/testing/tests/ikev2/esp-alg-sha1-160/evaltest.dat b/testing/tests/ikev2/esp-alg-sha1-160/evaltest.dat new file mode 100644 index 000000000..b0277271d --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/evaltest.dat @@ -0,0 +1,9 @@ +moon::ipsec statusall::rw.*INSTALLED::YES +carol::ipsec statusall::home.*INSTALLED::YES +carol::ping -c 1 -s 120 -p deadbeef PH_IP_ALICE::128 bytes from PH_IP_ALICE: icmp_seq=1::YES +moon::ipsec statusall::AES_CBC_128/HMAC_SHA1_160::YES +carol::ipsec statusall::AES_CBC_128/HMAC_SHA1_160::YES +moon::ip xfrm state::auth hmac(sha1)::YES +carol::ip xfrm state::auth hmac(sha1)::YES +moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP.*length 204::YES +moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP.*length 204::YES diff --git a/testing/tests/ikev2/esp-alg-sha1-160/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/esp-alg-sha1-160/hosts/carol/etc/ipsec.conf new file mode 100755 index 000000000..3991d517d --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/hosts/carol/etc/ipsec.conf @@ -0,0 +1,25 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=yes + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + ike=aes128-sha1-modp1536! + esp=aes128-sha1_160! + +conn home + left=PH_IP_CAROL + leftfirewall=yes + leftcert=carolCert.pem + leftid=carol@strongswan.org + right=PH_IP_MOON + rightsubnet=10.1.0.0/16 + rightid=@moon.strongswan.org + auto=add diff --git a/testing/tests/ikev2/esp-alg-sha1-160/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/esp-alg-sha1-160/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..339b56987 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/hosts/carol/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac xcbc stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/esp-alg-sha1-160/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/esp-alg-sha1-160/hosts/moon/etc/ipsec.conf new file mode 100755 index 000000000..893419585 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/hosts/moon/etc/ipsec.conf @@ -0,0 +1,24 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=yes + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + ike=aes128-sha1-modp1536! + esp=aes128-sha1_160! + +conn rw + left=PH_IP_MOON + leftfirewall=yes + leftcert=moonCert.pem + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + right=%any + auto=add diff --git a/testing/tests/ikev2/esp-alg-sha1-160/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/esp-alg-sha1-160/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..339b56987 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/hosts/moon/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac xcbc stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/esp-alg-sha1-160/posttest.dat b/testing/tests/ikev2/esp-alg-sha1-160/posttest.dat new file mode 100644 index 000000000..94a400606 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/posttest.dat @@ -0,0 +1,4 @@ +moon::ipsec stop +carol::ipsec stop +moon::/etc/init.d/iptables stop 2> /dev/null +carol::/etc/init.d/iptables stop 2> /dev/null diff --git a/testing/tests/ikev2/esp-alg-sha1-160/pretest.dat b/testing/tests/ikev2/esp-alg-sha1-160/pretest.dat new file mode 100644 index 000000000..3c3df0196 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/pretest.dat @@ -0,0 +1,7 @@ +moon::/etc/init.d/iptables start 2> /dev/null +carol::/etc/init.d/iptables start 2> /dev/null +moon::ipsec start +carol::ipsec start +carol::sleep 1 +carol::ipsec up home +carol::sleep 1 diff --git a/testing/tests/ikev2/esp-alg-sha1-160/test.conf b/testing/tests/ikev2/esp-alg-sha1-160/test.conf new file mode 100644 index 000000000..9cd583b16 --- /dev/null +++ b/testing/tests/ikev2/esp-alg-sha1-160/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# UML instances used for this test + +# All UML instances that are required for this test +# +UMLHOSTS="alice moon carol winnetou" + +# Corresponding block diagram +# +DIAGRAM="a-m-c-w.png" + +# UML instances on which tcpdump is to be started +# +TCPDUMPHOSTS="moon" + +# UML instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon carol" diff --git a/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem b/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem index aeca7e1db..a1c57b0f0 100644 --- a/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem +++ b/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem @@ -1,26 +1,95 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 39 (0x27) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=CH, O=Linux strongSwan, CN=strongSwan Root CA + Validity + Not Before: Mar 15 06:42:00 2012 GMT + Not After : Mar 14 06:42:00 2017 GMT + Subject: C=CH, O=Linux strongSwan, OU=OCSP, CN=carol@strongswan.org + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:b0:33:dd:ed:c0:d6:9d:01:de:eb:08:c4:f9:6a: + e9:46:10:f6:a4:cd:7d:aa:79:4b:c2:33:1f:61:40: + 40:de:06:9f:b8:2a:b0:84:cd:a7:79:c8:ee:a7:24: + 69:08:04:89:f8:7b:62:7e:03:9e:0a:d9:df:ff:7c: + 20:3c:a7:b1:86:7f:cc:e6:ad:0c:7e:6f:c4:9b:31: + 55:57:92:df:7b:94:86:f1:27:3a:0e:fa:0b:92:58: + ad:64:8a:40:46:5d:87:ca:11:20:03:ad:86:68:a5: + 0c:8a:19:ce:36:d0:55:bf:1f:00:47:c9:1a:af:c5: + ad:14:3c:d7:0c:9e:28:d9:61:1b:a2:a8:b7:f1:56: + a7:d9:3b:fa:09:08:2c:9b:75:e3:30:64:5e:93:80: + 48:94:35:0d:97:ca:ac:57:66:02:86:b6:1b:6b:f1: + 4a:86:30:74:48:38:46:1a:7d:07:61:30:15:33:b0: + 9d:50:fc:4d:8c:16:1e:30:13:9f:07:04:7a:3b:92: + 54:33:c7:3a:0b:67:e2:ba:46:b0:b3:0d:79:7f:e4: + ed:81:bd:34:cb:e5:30:f3:af:d4:dd:52:3e:f5:13: + 0e:c0:79:f8:43:c7:f5:b9:b0:12:6a:46:38:db:61: + 44:c8:4a:68:7b:77:34:68:63:ef:88:16:be:ae:89: + ff:89 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Subject Key Identifier: + C5:E8:58:D7:63:B0:B8:D4:2E:22:04:E1:CB:35:34:95:DA:74:F0:E6 + X509v3 Authority Key Identifier: + keyid:5D:A7:DD:70:06:51:32:7E:E7:B6:6D:B3:B5:E5:E0:60:EA:2E:4D:EF + DirName:/C=CH/O=Linux strongSwan/CN=strongSwan Root CA + serial:00 + + X509v3 Subject Alternative Name: + email:carol@strongswan.org + Authority Information Access: + OCSP - URI:http://ocsp.strongswan.org:8880 + + X509v3 CRL Distribution Points: + URI:http://crl.strongswan.org/strongswan.crl + + Signature Algorithm: sha256WithRSAEncryption + b6:2d:d8:bb:40:e9:cf:a9:33:31:6c:91:c7:40:79:8c:5f:89: + 8e:26:d8:ef:91:67:da:71:75:f9:27:84:21:c3:6c:d1:a5:fb: + 50:de:b2:02:ad:3c:a4:6b:40:58:30:41:c7:bd:31:ca:df:77: + 00:c9:ac:5b:10:e3:66:71:6c:be:4a:49:7e:58:92:de:f4:16: + 51:12:00:2c:33:e2:2c:b5:e5:d4:6e:36:a2:50:ba:86:e3:c6: + bb:50:a2:e5:11:69:c4:86:91:fc:4d:65:7e:09:49:bd:d2:ae: + cd:70:f8:98:5d:a8:b6:cf:38:c3:19:49:fd:8b:72:3b:1a:cc: + fc:19:c9:c1:36:b2:39:ba:ed:9a:cd:db:2d:27:15:b0:ba:8a: + 64:4a:5c:8f:ff:db:78:7d:cd:78:c3:c6:13:ba:93:7b:b7:57: + da:a3:f2:16:9f:f7:24:95:57:df:f4:4f:c5:9f:d6:12:b1:69: + 39:a7:5a:88:9c:74:be:f7:b0:f3:b4:89:82:46:57:de:7d:a1: + 42:a2:c2:de:1c:37:19:66:60:2a:df:ed:25:e3:72:d3:f9:9b: + 84:05:b6:97:6a:63:63:5c:30:5d:01:7a:15:c4:6e:2c:a0:21: + d2:31:30:98:60:94:26:44:9a:08:b4:85:8d:52:00:98:ef:cb: + 07:4f:b7:8e -----BEGIN CERTIFICATE----- -MIIEWzCCA0OgAwIBAgIBEzANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ +MIIEWzCCA0OgAwIBAgIBJzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS -b290IENBMB4XDTA3MDIyNTA3NTg1N1oXDTEyMDIyNDA3NTg1N1owVjELMAkGA1UE +b290IENBMB4XDTEyMDMxNTA2NDIwMFoXDTE3MDMxNDA2NDIwMFowVjELMAkGA1UE BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDTALBgNVBAsTBE9DU1Ax HTAbBgNVBAMUFGNhcm9sQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAyO4WxrPomcQSspX+ZnPit3t+tzYE/wi1E8rH3h5aO3e5 -vVZX3YxNvBqge2RPB3oQHrWwWT8vKmqzZNjJUx4bRIqd1JdTRI7L0f6XJHjnrRv8 -G7M2uHe+JbHQKPRT7IefJ4PZ1FEA8SCwKfWs5vk1/w/cabM6DVzzjtWTV9DXKD6J -5rRlvXtJDbhAvI2w8pCC1Gt6H8qjVSb7ItJ+SD3BlW3tq3nBsYFJRL24TyQg+Kdt -kkCRQYirog29q+J59SErjolse59dte+MhNTv+SnVFgpQE9IGEo6yaKMAWLSTv0If -pPr/QaEV9rcsYFmR3RtHc+QaaP0hvDAPMaKdhQMIUwIDAQABo4IBQzCCAT8wCQYD -VR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFDRTWKccFIi95BslK3U92mIQ -2rWGMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYD +AAOCAQ8AMIIBCgKCAQEAsDPd7cDWnQHe6wjE+WrpRhD2pM19qnlLwjMfYUBA3gaf +uCqwhM2necjupyRpCASJ+HtifgOeCtnf/3wgPKexhn/M5q0Mfm/EmzFVV5Lfe5SG +8Sc6DvoLklitZIpARl2HyhEgA62GaKUMihnONtBVvx8AR8kar8WtFDzXDJ4o2WEb +oqi38Van2Tv6CQgsm3XjMGRek4BIlDUNl8qsV2YChrYba/FKhjB0SDhGGn0HYTAV +M7CdUPxNjBYeMBOfBwR6O5JUM8c6C2fiukawsw15f+Ttgb00y+Uw86/U3VI+9RMO +wHn4Q8f1ubASakY422FEyEpoe3c0aGPviBa+ron/iQIDAQABo4IBQzCCAT8wCQYD +VR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFMXoWNdjsLjULiIE4cs1NJXa +dPDmMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYD VQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ry b25nU3dhbiBSb290IENBggEAMB8GA1UdEQQYMBaBFGNhcm9sQHN0cm9uZ3N3YW4u b3JnMDsGCCsGAQUFBwEBBC8wLTArBggrBgEFBQcwAYYfaHR0cDovL29jc3Auc3Ry b25nc3dhbi5vcmc6ODg4MDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0 -cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQAc -1bBYLYcc+js3UsHVk7W17Nr/qoNFzQZJ5Er3RjhNAgzAX1wOTrNgKXztwZde1Alj -o05ZLXUFkB4coQwl7xo7I3EMJPUmSdHoyYyG7c7AgfcL/wwnzz4rWQl74WIZjySc -ON0Ny9vrzbVboktYof/9Yp/+HgeKopfsaIiuNCAwmAWxiYqvDmlxxn16oOXeJFV8 -pFzZMirQ5l7QRD9iuabOdcnBp8ASH+5AbD4KjFQjo5RBVg92LwOkJo3Pf1twI57s -pObrcM4JbHVohDornYQYfr9ymkMxJbqqkEgD8oIip0NFSbziam4ZkwgUlRIMUMU1 -/xsH+BXYZtKJbYjlnyc8 +cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQC2 +Ldi7QOnPqTMxbJHHQHmMX4mOJtjvkWfacXX5J4Qhw2zRpftQ3rICrTyka0BYMEHH +vTHK33cAyaxbEONmcWy+Skl+WJLe9BZREgAsM+IsteXUbjaiULqG48a7UKLlEWnE +hpH8TWV+CUm90q7NcPiYXai2zzjDGUn9i3I7Gsz8GcnBNrI5uu2azdstJxWwuopk +SlyP/9t4fc14w8YTupN7t1fao/IWn/cklVff9E/Fn9YSsWk5p1qInHS+97DztImC +RlfefaFCosLeHDcZZmAq3+0l43LT+ZuEBbaXamNjXDBdAXoVxG4soCHSMTCYYJQm +RJoItIWNUgCY78sHT7eO -----END CERTIFICATE----- diff --git a/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem b/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem index 603f071d0..d6a762b1b 100644 --- a/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem +++ b/testing/tests/ikev2/ocsp-signer-cert/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAyO4WxrPomcQSspX+ZnPit3t+tzYE/wi1E8rH3h5aO3e5vVZX -3YxNvBqge2RPB3oQHrWwWT8vKmqzZNjJUx4bRIqd1JdTRI7L0f6XJHjnrRv8G7M2 -uHe+JbHQKPRT7IefJ4PZ1FEA8SCwKfWs5vk1/w/cabM6DVzzjtWTV9DXKD6J5rRl -vXtJDbhAvI2w8pCC1Gt6H8qjVSb7ItJ+SD3BlW3tq3nBsYFJRL24TyQg+KdtkkCR -QYirog29q+J59SErjolse59dte+MhNTv+SnVFgpQE9IGEo6yaKMAWLSTv0IfpPr/ -QaEV9rcsYFmR3RtHc+QaaP0hvDAPMaKdhQMIUwIDAQABAoIBAFTGd5+gmpv96TGm -LW8Gp/poRX+BcDw2bUgLf6aMwd9jVV+4RVw5bTbXOSy2ls19x71dRSlyijDoUgZT -nSXPhwu1PIBM1JoRcZeJRjXiOUWFkCoTxBuykeyPiFcvNxWN5y2h6M822iHie9FI -UYomTYzvIT0LnIu00yJJpGAhwhW9BcL+Mo9lfWmhv4I1hXC9RTqZZ4rjPojDeFvL -maZNCk3kX2pxIJ1kG41/PJjg3JD2uEVrvV7SRuOknM+7f3SDtY60/Wnqx8dfBtjJ -hEdIxG+XXEOafdqwEPmmM++6V76uD8Rs1eFrrI4rfK6/H2PjppJCYtQeryug0q+0 -UN2u00kCgYEA5qJOcDSzb7CQAi58yYicYc3ShEbaL75V7G5rlnFg4/G1axU19hXQ -wEPDf87So9hnVroCMewjyDiNgI/OyYK2cv1TABUGAEFAHPzj99jtBT0/R0kX+Jd2 -kPwCU4/T2cHrezwNobrJf010JAvwc52b+U3lWtHxBWeq5KALUVT+BhcCgYEA3wdx -OwVxTf+OBOBcxPPGUcfsKbf9uVTcXFLNRSBbjzRIOR/bIVgUQaBXem2fJJTm1mWN -Yl/U14G5orv9693GKgE5IDAMMrDF7mOsX808o3pcXM04MTAyGmQEDDEO8tgmWzWo -nrYzxe9uBR1tej9IsiEPlD9ZLtWix9C2uV7EcSUCgYBKOrDuMjgSWYxv91BYeOyE -Gf+IbVlqBmOXPg7Ik+MwWioetevxMSJHz0eLyiBHda4E3sc4FB2MIo+AckiG2Ngp -+FiPbTTKPjYJXmds7NeUWRsVsXPSocUactG43VC9BEnrFu/4Pqr9mwsnUuRoAbEi -syx/Z5SgPbZl8RDTc3xyrwKBgBFpB1HQLvQjyvZefV9ymDyyGqF3F3tsQHeEjzmi -OQOI1UqATh7gPVSSK8IG5LF6XjrGWq8fRAI+wjsN6diLy3hj+A2nMoySeCEP7tjb -sKwiVSt5abWNSZv9ysMY4U3bycK9AZjCKHB/LFuB3JX6crZVFl5AQ7oAO2DVzi3S -VAtxAoGALzFZH7o1ZvVJGa23dW7p96G5vgop6Ulp2DLz4Qg6NYIeatZhwX3lls2J -P7ZxmHiECC7zR67xwv5QKjKfg6t/sOKU/bsyp6c3hOWQjcFbWU3AwlO1TeVX9TMG -SmPYcKM+KQ969qKD3aP9MQ+t4FERvlQcBAr0Qun3quN2i3eDkDo= +MIIEogIBAAKCAQEAsDPd7cDWnQHe6wjE+WrpRhD2pM19qnlLwjMfYUBA3gafuCqw +hM2necjupyRpCASJ+HtifgOeCtnf/3wgPKexhn/M5q0Mfm/EmzFVV5Lfe5SG8Sc6 +DvoLklitZIpARl2HyhEgA62GaKUMihnONtBVvx8AR8kar8WtFDzXDJ4o2WEboqi3 +8Van2Tv6CQgsm3XjMGRek4BIlDUNl8qsV2YChrYba/FKhjB0SDhGGn0HYTAVM7Cd +UPxNjBYeMBOfBwR6O5JUM8c6C2fiukawsw15f+Ttgb00y+Uw86/U3VI+9RMOwHn4 +Q8f1ubASakY422FEyEpoe3c0aGPviBa+ron/iQIDAQABAoIBAEEGwy5M7mb/G79t +exP5CqHa/MsRMwFIxlai+z+usMG/fA5BYud/5gCh0MFKRKC63BghoNWUjCzA/1OQ +AW2hDXjvjTTMREIdCVekuzQYdfVreOliaqDAUqjtpP/nrZTKS6Sc8U2qKmJQFvKY +V2wPMrXXwQi9BOY9c4R2d36ml7iw6veYhPj0XHy3spJc3V6k7YmbApOQgWDqRwid +GGnnvDpdD0gAGAOxadCCpV+N9NK+AMSk03Qpcc2ki4THEn2e8Rs1/dH1k5nics/E +cG9VT9pZtvGXjEX7Wo06v0lXsTRWGWLKhHvzfhIb6uWnC/YUR+7Cv8JYRz+RZn98 +bv5lXokCgYEA1iRf3gH8qwvxQjLtaNKRyr8Bheo3tsOLh2tYriWaUTXqeKAd46zI +KcWAKtYWJQenVyFvnsMwKNFvFq/HgJGhKTOvZRwsrTb2wXgxcAleOBO+Ts4Vhb9J +xil8/WcWCKU+GPf8hQOkwVnhv4CxLscCXT2g9zxTpP/JCKmHaucQog8CgYEA0qUC +NBRMh55bjiHaqsSRvr45iwxzNzd8KK5A/xKyScEl+A4HWdqDpZ+8w9YC4GUQClvH +cHn5NpWfq9hrNAXPjBzVGXk+JqFcJM/yPImH+Vg8MupJprwVSHJ1mqQ/MPSpxxhy +iNaWeJX6bhPAgQSOAYbH22uNOGePmMQ8kk3v/OcCgYA7ZzPA3kQ9Hr76Yi5Bmcgf +ugSuJV73MB+QnVKoXH4GcTJt69zev5t3GvaG64SRGSJupTPVksfVSuPKI1DwdXWD +fHb3UW2DT2/8E1+DeNXOMIvmSHzn8TyB4BhwIxyVoWEsg/5k17HogQqCmSyNkV8y +hloUu4NojhwybvTFzvtqOQKBgDL0IVVRt7Vyk/kMrWVziUHXp/m/uDsaG9mHVUee +USxQIYwgcJzGo+OzgSjqIuX+7GNlEhheGO+gP/CEuGHsKeldrBquXl9f1vc8qf8E +0bR6KI20aL6BbrCIp3QR2QtRk6QKgOIi7mEa/moUMxPCc0thPAUSviVvv6eXiINn +gO7vAoGAcvwVy9gDcGTL+4mMjZ07jc/TmQPmOpqosXuDTQZITuovpzY0Nf9KPNJs +0dTuCaO+N5ZjttxIm6L9h/Ah0BN2Ir+JbplJ5uScWldz0MFJXm1wz7KJCRZQpVIO +6SJCLSmh4nZ0TIL8V0ABhaFVQK0qq2z/ASljIF6iC68DBEDfuzY= -----END RSA PRIVATE KEY----- diff --git a/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem b/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem index aeca7e1db..a1c57b0f0 100644 --- a/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem +++ b/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/certs/carolCert-ocsp.pem @@ -1,26 +1,95 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 39 (0x27) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=CH, O=Linux strongSwan, CN=strongSwan Root CA + Validity + Not Before: Mar 15 06:42:00 2012 GMT + Not After : Mar 14 06:42:00 2017 GMT + Subject: C=CH, O=Linux strongSwan, OU=OCSP, CN=carol@strongswan.org + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:b0:33:dd:ed:c0:d6:9d:01:de:eb:08:c4:f9:6a: + e9:46:10:f6:a4:cd:7d:aa:79:4b:c2:33:1f:61:40: + 40:de:06:9f:b8:2a:b0:84:cd:a7:79:c8:ee:a7:24: + 69:08:04:89:f8:7b:62:7e:03:9e:0a:d9:df:ff:7c: + 20:3c:a7:b1:86:7f:cc:e6:ad:0c:7e:6f:c4:9b:31: + 55:57:92:df:7b:94:86:f1:27:3a:0e:fa:0b:92:58: + ad:64:8a:40:46:5d:87:ca:11:20:03:ad:86:68:a5: + 0c:8a:19:ce:36:d0:55:bf:1f:00:47:c9:1a:af:c5: + ad:14:3c:d7:0c:9e:28:d9:61:1b:a2:a8:b7:f1:56: + a7:d9:3b:fa:09:08:2c:9b:75:e3:30:64:5e:93:80: + 48:94:35:0d:97:ca:ac:57:66:02:86:b6:1b:6b:f1: + 4a:86:30:74:48:38:46:1a:7d:07:61:30:15:33:b0: + 9d:50:fc:4d:8c:16:1e:30:13:9f:07:04:7a:3b:92: + 54:33:c7:3a:0b:67:e2:ba:46:b0:b3:0d:79:7f:e4: + ed:81:bd:34:cb:e5:30:f3:af:d4:dd:52:3e:f5:13: + 0e:c0:79:f8:43:c7:f5:b9:b0:12:6a:46:38:db:61: + 44:c8:4a:68:7b:77:34:68:63:ef:88:16:be:ae:89: + ff:89 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Subject Key Identifier: + C5:E8:58:D7:63:B0:B8:D4:2E:22:04:E1:CB:35:34:95:DA:74:F0:E6 + X509v3 Authority Key Identifier: + keyid:5D:A7:DD:70:06:51:32:7E:E7:B6:6D:B3:B5:E5:E0:60:EA:2E:4D:EF + DirName:/C=CH/O=Linux strongSwan/CN=strongSwan Root CA + serial:00 + + X509v3 Subject Alternative Name: + email:carol@strongswan.org + Authority Information Access: + OCSP - URI:http://ocsp.strongswan.org:8880 + + X509v3 CRL Distribution Points: + URI:http://crl.strongswan.org/strongswan.crl + + Signature Algorithm: sha256WithRSAEncryption + b6:2d:d8:bb:40:e9:cf:a9:33:31:6c:91:c7:40:79:8c:5f:89: + 8e:26:d8:ef:91:67:da:71:75:f9:27:84:21:c3:6c:d1:a5:fb: + 50:de:b2:02:ad:3c:a4:6b:40:58:30:41:c7:bd:31:ca:df:77: + 00:c9:ac:5b:10:e3:66:71:6c:be:4a:49:7e:58:92:de:f4:16: + 51:12:00:2c:33:e2:2c:b5:e5:d4:6e:36:a2:50:ba:86:e3:c6: + bb:50:a2:e5:11:69:c4:86:91:fc:4d:65:7e:09:49:bd:d2:ae: + cd:70:f8:98:5d:a8:b6:cf:38:c3:19:49:fd:8b:72:3b:1a:cc: + fc:19:c9:c1:36:b2:39:ba:ed:9a:cd:db:2d:27:15:b0:ba:8a: + 64:4a:5c:8f:ff:db:78:7d:cd:78:c3:c6:13:ba:93:7b:b7:57: + da:a3:f2:16:9f:f7:24:95:57:df:f4:4f:c5:9f:d6:12:b1:69: + 39:a7:5a:88:9c:74:be:f7:b0:f3:b4:89:82:46:57:de:7d:a1: + 42:a2:c2:de:1c:37:19:66:60:2a:df:ed:25:e3:72:d3:f9:9b: + 84:05:b6:97:6a:63:63:5c:30:5d:01:7a:15:c4:6e:2c:a0:21: + d2:31:30:98:60:94:26:44:9a:08:b4:85:8d:52:00:98:ef:cb: + 07:4f:b7:8e -----BEGIN CERTIFICATE----- -MIIEWzCCA0OgAwIBAgIBEzANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJDSDEZ +MIIEWzCCA0OgAwIBAgIBJzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS -b290IENBMB4XDTA3MDIyNTA3NTg1N1oXDTEyMDIyNDA3NTg1N1owVjELMAkGA1UE +b290IENBMB4XDTEyMDMxNTA2NDIwMFoXDTE3MDMxNDA2NDIwMFowVjELMAkGA1UE BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xDTALBgNVBAsTBE9DU1Ax HTAbBgNVBAMUFGNhcm9sQHN0cm9uZ3N3YW4ub3JnMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAyO4WxrPomcQSspX+ZnPit3t+tzYE/wi1E8rH3h5aO3e5 -vVZX3YxNvBqge2RPB3oQHrWwWT8vKmqzZNjJUx4bRIqd1JdTRI7L0f6XJHjnrRv8 -G7M2uHe+JbHQKPRT7IefJ4PZ1FEA8SCwKfWs5vk1/w/cabM6DVzzjtWTV9DXKD6J -5rRlvXtJDbhAvI2w8pCC1Gt6H8qjVSb7ItJ+SD3BlW3tq3nBsYFJRL24TyQg+Kdt -kkCRQYirog29q+J59SErjolse59dte+MhNTv+SnVFgpQE9IGEo6yaKMAWLSTv0If -pPr/QaEV9rcsYFmR3RtHc+QaaP0hvDAPMaKdhQMIUwIDAQABo4IBQzCCAT8wCQYD -VR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFDRTWKccFIi95BslK3U92mIQ -2rWGMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYD +AAOCAQ8AMIIBCgKCAQEAsDPd7cDWnQHe6wjE+WrpRhD2pM19qnlLwjMfYUBA3gaf +uCqwhM2necjupyRpCASJ+HtifgOeCtnf/3wgPKexhn/M5q0Mfm/EmzFVV5Lfe5SG +8Sc6DvoLklitZIpARl2HyhEgA62GaKUMihnONtBVvx8AR8kar8WtFDzXDJ4o2WEb +oqi38Van2Tv6CQgsm3XjMGRek4BIlDUNl8qsV2YChrYba/FKhjB0SDhGGn0HYTAV +M7CdUPxNjBYeMBOfBwR6O5JUM8c6C2fiukawsw15f+Ttgb00y+Uw86/U3VI+9RMO +wHn4Q8f1ubASakY422FEyEpoe3c0aGPviBa+ron/iQIDAQABo4IBQzCCAT8wCQYD +VR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFMXoWNdjsLjULiIE4cs1NJXa +dPDmMG0GA1UdIwRmMGSAFF2n3XAGUTJ+57Zts7Xl4GDqLk3voUmkRzBFMQswCQYD VQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ry b25nU3dhbiBSb290IENBggEAMB8GA1UdEQQYMBaBFGNhcm9sQHN0cm9uZ3N3YW4u b3JnMDsGCCsGAQUFBwEBBC8wLTArBggrBgEFBQcwAYYfaHR0cDovL29jc3Auc3Ry b25nc3dhbi5vcmc6ODg4MDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLnN0 -cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQAc -1bBYLYcc+js3UsHVk7W17Nr/qoNFzQZJ5Er3RjhNAgzAX1wOTrNgKXztwZde1Alj -o05ZLXUFkB4coQwl7xo7I3EMJPUmSdHoyYyG7c7AgfcL/wwnzz4rWQl74WIZjySc -ON0Ny9vrzbVboktYof/9Yp/+HgeKopfsaIiuNCAwmAWxiYqvDmlxxn16oOXeJFV8 -pFzZMirQ5l7QRD9iuabOdcnBp8ASH+5AbD4KjFQjo5RBVg92LwOkJo3Pf1twI57s -pObrcM4JbHVohDornYQYfr9ymkMxJbqqkEgD8oIip0NFSbziam4ZkwgUlRIMUMU1 -/xsH+BXYZtKJbYjlnyc8 +cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQC2 +Ldi7QOnPqTMxbJHHQHmMX4mOJtjvkWfacXX5J4Qhw2zRpftQ3rICrTyka0BYMEHH +vTHK33cAyaxbEONmcWy+Skl+WJLe9BZREgAsM+IsteXUbjaiULqG48a7UKLlEWnE +hpH8TWV+CUm90q7NcPiYXai2zzjDGUn9i3I7Gsz8GcnBNrI5uu2azdstJxWwuopk +SlyP/9t4fc14w8YTupN7t1fao/IWn/cklVff9E/Fn9YSsWk5p1qInHS+97DztImC +RlfefaFCosLeHDcZZmAq3+0l43LT+ZuEBbaXamNjXDBdAXoVxG4soCHSMTCYYJQm +RJoItIWNUgCY78sHT7eO -----END CERTIFICATE----- diff --git a/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem b/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem index 603f071d0..d6a762b1b 100644 --- a/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem +++ b/testing/tests/ikev2/ocsp-timeouts-good/hosts/carol/etc/ipsec.d/private/carolKey-ocsp.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAyO4WxrPomcQSspX+ZnPit3t+tzYE/wi1E8rH3h5aO3e5vVZX -3YxNvBqge2RPB3oQHrWwWT8vKmqzZNjJUx4bRIqd1JdTRI7L0f6XJHjnrRv8G7M2 -uHe+JbHQKPRT7IefJ4PZ1FEA8SCwKfWs5vk1/w/cabM6DVzzjtWTV9DXKD6J5rRl -vXtJDbhAvI2w8pCC1Gt6H8qjVSb7ItJ+SD3BlW3tq3nBsYFJRL24TyQg+KdtkkCR -QYirog29q+J59SErjolse59dte+MhNTv+SnVFgpQE9IGEo6yaKMAWLSTv0IfpPr/ -QaEV9rcsYFmR3RtHc+QaaP0hvDAPMaKdhQMIUwIDAQABAoIBAFTGd5+gmpv96TGm -LW8Gp/poRX+BcDw2bUgLf6aMwd9jVV+4RVw5bTbXOSy2ls19x71dRSlyijDoUgZT -nSXPhwu1PIBM1JoRcZeJRjXiOUWFkCoTxBuykeyPiFcvNxWN5y2h6M822iHie9FI -UYomTYzvIT0LnIu00yJJpGAhwhW9BcL+Mo9lfWmhv4I1hXC9RTqZZ4rjPojDeFvL -maZNCk3kX2pxIJ1kG41/PJjg3JD2uEVrvV7SRuOknM+7f3SDtY60/Wnqx8dfBtjJ -hEdIxG+XXEOafdqwEPmmM++6V76uD8Rs1eFrrI4rfK6/H2PjppJCYtQeryug0q+0 -UN2u00kCgYEA5qJOcDSzb7CQAi58yYicYc3ShEbaL75V7G5rlnFg4/G1axU19hXQ -wEPDf87So9hnVroCMewjyDiNgI/OyYK2cv1TABUGAEFAHPzj99jtBT0/R0kX+Jd2 -kPwCU4/T2cHrezwNobrJf010JAvwc52b+U3lWtHxBWeq5KALUVT+BhcCgYEA3wdx -OwVxTf+OBOBcxPPGUcfsKbf9uVTcXFLNRSBbjzRIOR/bIVgUQaBXem2fJJTm1mWN -Yl/U14G5orv9693GKgE5IDAMMrDF7mOsX808o3pcXM04MTAyGmQEDDEO8tgmWzWo -nrYzxe9uBR1tej9IsiEPlD9ZLtWix9C2uV7EcSUCgYBKOrDuMjgSWYxv91BYeOyE -Gf+IbVlqBmOXPg7Ik+MwWioetevxMSJHz0eLyiBHda4E3sc4FB2MIo+AckiG2Ngp -+FiPbTTKPjYJXmds7NeUWRsVsXPSocUactG43VC9BEnrFu/4Pqr9mwsnUuRoAbEi -syx/Z5SgPbZl8RDTc3xyrwKBgBFpB1HQLvQjyvZefV9ymDyyGqF3F3tsQHeEjzmi -OQOI1UqATh7gPVSSK8IG5LF6XjrGWq8fRAI+wjsN6diLy3hj+A2nMoySeCEP7tjb -sKwiVSt5abWNSZv9ysMY4U3bycK9AZjCKHB/LFuB3JX6crZVFl5AQ7oAO2DVzi3S -VAtxAoGALzFZH7o1ZvVJGa23dW7p96G5vgop6Ulp2DLz4Qg6NYIeatZhwX3lls2J -P7ZxmHiECC7zR67xwv5QKjKfg6t/sOKU/bsyp6c3hOWQjcFbWU3AwlO1TeVX9TMG -SmPYcKM+KQ969qKD3aP9MQ+t4FERvlQcBAr0Qun3quN2i3eDkDo= +MIIEogIBAAKCAQEAsDPd7cDWnQHe6wjE+WrpRhD2pM19qnlLwjMfYUBA3gafuCqw +hM2necjupyRpCASJ+HtifgOeCtnf/3wgPKexhn/M5q0Mfm/EmzFVV5Lfe5SG8Sc6 +DvoLklitZIpARl2HyhEgA62GaKUMihnONtBVvx8AR8kar8WtFDzXDJ4o2WEboqi3 +8Van2Tv6CQgsm3XjMGRek4BIlDUNl8qsV2YChrYba/FKhjB0SDhGGn0HYTAVM7Cd +UPxNjBYeMBOfBwR6O5JUM8c6C2fiukawsw15f+Ttgb00y+Uw86/U3VI+9RMOwHn4 +Q8f1ubASakY422FEyEpoe3c0aGPviBa+ron/iQIDAQABAoIBAEEGwy5M7mb/G79t +exP5CqHa/MsRMwFIxlai+z+usMG/fA5BYud/5gCh0MFKRKC63BghoNWUjCzA/1OQ +AW2hDXjvjTTMREIdCVekuzQYdfVreOliaqDAUqjtpP/nrZTKS6Sc8U2qKmJQFvKY +V2wPMrXXwQi9BOY9c4R2d36ml7iw6veYhPj0XHy3spJc3V6k7YmbApOQgWDqRwid +GGnnvDpdD0gAGAOxadCCpV+N9NK+AMSk03Qpcc2ki4THEn2e8Rs1/dH1k5nics/E +cG9VT9pZtvGXjEX7Wo06v0lXsTRWGWLKhHvzfhIb6uWnC/YUR+7Cv8JYRz+RZn98 +bv5lXokCgYEA1iRf3gH8qwvxQjLtaNKRyr8Bheo3tsOLh2tYriWaUTXqeKAd46zI +KcWAKtYWJQenVyFvnsMwKNFvFq/HgJGhKTOvZRwsrTb2wXgxcAleOBO+Ts4Vhb9J +xil8/WcWCKU+GPf8hQOkwVnhv4CxLscCXT2g9zxTpP/JCKmHaucQog8CgYEA0qUC +NBRMh55bjiHaqsSRvr45iwxzNzd8KK5A/xKyScEl+A4HWdqDpZ+8w9YC4GUQClvH +cHn5NpWfq9hrNAXPjBzVGXk+JqFcJM/yPImH+Vg8MupJprwVSHJ1mqQ/MPSpxxhy +iNaWeJX6bhPAgQSOAYbH22uNOGePmMQ8kk3v/OcCgYA7ZzPA3kQ9Hr76Yi5Bmcgf +ugSuJV73MB+QnVKoXH4GcTJt69zev5t3GvaG64SRGSJupTPVksfVSuPKI1DwdXWD +fHb3UW2DT2/8E1+DeNXOMIvmSHzn8TyB4BhwIxyVoWEsg/5k17HogQqCmSyNkV8y +hloUu4NojhwybvTFzvtqOQKBgDL0IVVRt7Vyk/kMrWVziUHXp/m/uDsaG9mHVUee +USxQIYwgcJzGo+OzgSjqIuX+7GNlEhheGO+gP/CEuGHsKeldrBquXl9f1vc8qf8E +0bR6KI20aL6BbrCIp3QR2QtRk6QKgOIi7mEa/moUMxPCc0thPAUSviVvv6eXiINn +gO7vAoGAcvwVy9gDcGTL+4mMjZ07jc/TmQPmOpqosXuDTQZITuovpzY0Nf9KPNJs +0dTuCaO+N5ZjttxIm6L9h/Ah0BN2Ir+JbplJ5uScWldz0MFJXm1wz7KJCRZQpVIO +6SJCLSmh4nZ0TIL8V0ABhaFVQK0qq2z/ASljIF6iC68DBEDfuzY= -----END RSA PRIVATE KEY----- diff --git a/testing/tests/ikev2/reauth-late/evaltest.dat b/testing/tests/ikev2/reauth-late/evaltest.dat index 7f083a05e..c0893df65 100644 --- a/testing/tests/ikev2/reauth-late/evaltest.dat +++ b/testing/tests/ikev2/reauth-late/evaltest.dat @@ -1,7 +1,7 @@ moon::ipsec statusall::rw\[2\].*ESTABLISHED::YES carol::ipsec statusall::home\[2\].*ESTABLISHED::YES carol::cat /var/log/daemon.log::scheduling reauthentication in 2[0-5]s::YES -carol::cat /var/log/daemon.log::received AUTH_LIFETIME of 3600s, reauthentication already scheduled in 2[0-5]s::YES +carol::cat /var/log/daemon.log::received AUTH_LIFETIME of 360[01]s, reauthentication already scheduled in 2[0-5]s::YES carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES diff --git a/testing/tests/ikev2/reauth-late/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/reauth-late/hosts/moon/etc/ipsec.conf index bdd186a04..cb5e86a66 100755 --- a/testing/tests/ikev2/reauth-late/hosts/moon/etc/ipsec.conf +++ b/testing/tests/ikev2/reauth-late/hosts/moon/etc/ipsec.conf @@ -6,8 +6,8 @@ config setup plutostart=no conn %default - ikelifetime=60m - keylife=20m + ikelifetime=3601 + keylife=1200 rekeymargin=0s keyingtries=1 diff --git a/testing/tests/ikev2/rw-pkcs8/description.txt b/testing/tests/ikev2/rw-pkcs8/description.txt new file mode 100644 index 000000000..d5d817f52 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/description.txt @@ -0,0 +1,10 @@ +The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each +to gateway <b>moon</b>. The authentication is based on <b>X.509 certificates</b> +and matching RSA private keys stored in the <b>PKCS#8</b> format. <b>moon</b>'s key +is unencrypted, <b>carol</b>'s key is encrypted with the default PKCS#5 v1.5 +DES algorithm and <b>dave</b>'s key with the PKCS#5 v2.0 3DES algorithm. +<p/> +Upon the successful establishment of the IPsec tunnels, <b>leftfirewall=yes</b> +automatically inserts iptables-based firewall rules that let pass the tunneled traffic. +In order to test both tunnel and firewall, both <b>carol</b> and <b>dave</b> ping +the client <b>alice</b> behind the gateway <b>moon</b>. diff --git a/testing/tests/ikev2/rw-pkcs8/evaltest.dat b/testing/tests/ikev2/rw-pkcs8/evaltest.dat new file mode 100644 index 000000000..06a0f8cda --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/evaltest.dat @@ -0,0 +1,10 @@ +moon::ipsec statusall::rw.*ESTABLISHED::YES +carol::ipsec statusall::home.*ESTABLISHED::YES +dave::ipsec statusall::home.*ESTABLISHED::YES +carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES +dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES +moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES +moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES +moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES +moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES + diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.conf new file mode 100755 index 000000000..bcdb8641b --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.conf @@ -0,0 +1,23 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + +conn home + left=PH_IP_CAROL + leftcert=carolCert.pem + leftid=carol@strongswan.org + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.d/private/carolKey.pem new file mode 100644 index 000000000..15d775dc8 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.d/private/carolKey.pem @@ -0,0 +1,29 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIE6TAbBgkqhkiG9w0BBQMwDgQI+eazNjQUVoACAggABIIEyMUe2rc1ZsQgFwUm +MiU+qAl2g7uzI1Pz6XzgvjZrV5n62XXAbIbG4WP08slkD2VXA5iVTnfI7nj0HEtD +d2eaLU0GKNwmW7eSAXmhwBiUA623Xo0Y/X4eAY9VUfSlVshnNKOsgETQxQhUsKK1 +NXSpXfAjSgd+HDwQ+uvFQQD9WgibO3rIxfuO9+QqwnYXWz/p2bmc128mBibaFxwa +SdVlYhR9l1hhFHN5cdD5AXFsflbLzGVR6gJpArU1m1soOEYp6q314L75KALYAVaY +tQTC6gcPtXRZZvNsg9iRttPKsky0XJF7t5YGIqM4NNu5b534iXATm5Lt9jkrNKqm +3SGD+KDLrk2aIaU9jCgY73Um1MJOls8AzUU0ZqwmAQAYoaZOwMDZ/P0Uw/du3Oaz +O9FbzfPoS46muRZHMDVXEB0Zt8laSjwryeIU26MNye1xEU0aJJRaQQP2Vq8FTGtM +Gi4gR9vdjyBhRE51z0kd5vPc7YkpqJNGB59KHRlHVmozo3v7zjkY/ROsiy1a0Vy/ +6ZkwtS0cnFzFhUBvUefzCsRKSiWWULqGIn3Qb7o+JQYc8vxuEua8DGnEmQEUBRgE +j/YeI8wtObYm+u6eE0lbTopdSkfHu5UzTDYpnYDhW5nwv5ZOKeRBdXyX4BOrITnR +xEsmp34/ql3/C9W1MXkjStaSRiWfbHt35gVlFaJNXZJXtKVOlFgxFxuslrawGI0c +DLhPu1aMfHNc8LlD8cN5W2OQ/jsYlQDDd+n1WPpn+9VuBqSlnDl/mn4/0R7Yy53m ++lgruhfA7S26NG+SxHPXBq8PE052ohDLylKRGEqBTJp2aXNEKKZLrK8I1zbdIx1h +0YAAtERtvqPu2xSvJ7lGuHD+87TlWa54p3H+0UM803RBQUcH5lsNUzQ4lAN/eFgg +7TK2BqRTqWTVm8he0tVY8XJ4dLPLsXxUKb/tiFvtjBdQM7bq0UlTxign8VGZro7v +dKkGqdsEEiFzCnOvDwyjOEG7wUVmO/ejWkuI510U80x/APuOUH0zQOTBhMSrz1Eh +AdWWeSvNuyWyRPNNzlQ4DJd3UKnu4BZu4zobe4imhwCCrkGkfE5FhnyXExA8FppT +2BNe5AmIfI1joEQyRgXm/nAvwvN9pawKfDxg8gmhBLjVfk50tAydWurhrhF6CnBL +4h/hhb+C6HZBbNpmY+O12bDk81unZ8Vvtbkix5n7/371XbaAQN1WYxNaH6SDeT1J +qDRWAZhGPBn7VLVaQ6ZmLB73U8vkcju8r6atWasZTPsZQl2eng9J/5UoL/0Ubri2 +Jlmj/fScAhlK7yM62dVYVwezYtKV8QUcaDmcqO8qhuVCnYlaqu6SO5ApYWkOMzMW +EpvY0SqD6QkfKvT8bVU9GOaNSMaEKUR7NPPgettVcEkg50TeyBRvXvOAexD6qcE0 +NO/sYx9do0WpY4u85DZt3Toper0hchbEmXVHlxh8CKPgUTFVsDQ6AVyrVWrtoY1k +VpJutwWV5sPIxq17bFLTJ7pP2NIvNBvwnDedn5WKNDFu9E2U8vAujVdzlQd/gsJi +JLCreDt+rcmJVBJHMxZC+SpLbR4kNMAe5vwwESVo6wBsxMuyn1b+82C8rum5qbJ9 +RGF8RGrZzrPWbBITPw== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.secrets b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.secrets new file mode 100644 index 000000000..6a2aea811 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: RSA carolKey.pem "nH5ZQEWtku0RJEZ6" diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..3c22edc23 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/carol/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 pkcs8 gmp random x509 revocation hmac xcbc ctr ccm gcm stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.conf b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.conf new file mode 100755 index 000000000..ea8bc92a7 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.conf @@ -0,0 +1,23 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + +conn home + left=PH_IP_DAVE + leftcert=daveCert.pem + leftid=dave@strongswan.org + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.d/private/daveKey.pem b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.d/private/daveKey.pem new file mode 100644 index 000000000..199d78984 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.d/private/daveKey.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIRwFyB7jCGskCAggA +MBQGCCqGSIb3DQMHBAjDqug87twvJwSCBMiBb1Y4B1FxGPGQwAgZd6aE8J6xH4VZ +MNpkm4+MPCVYBvpG1q3I1YcvIw0GcAlLQASGLXEytuVEH5xCUaGdCsa5zVpf+6Ex +i8Oyqf0dbRRafzN+K+jVLBa+higxXESE6jYxBP/auH4v5pcEy+fbljwDauyEP0bF +EgURF5nTsa5c+MTmWho+OMy/1pAuP92XmwLeeBXWuRWs+s3wkBOIe3SerW5MOyMN +mwqqu/6J4RU9VL7kooVE/B0oWJblvBTjeJoKDy5iX/iE2oRqXjihWPXYIhWqeCEB +2QCpZ1/9hEN7FLX87GBD7yivhhQMF/uBnTRIjmgbKmNtwY1+rybz0MUJrXVfS1iE +JYHlo4/cqudjsMjtjhTV9n4FJd9IsuSmZjMHVk3enIyhZ1oliugS25OpWKHnybzj +65cgxVGPTW31o21w/fEqRRR/KzrEaMZiPyO2EEMcKlB7xmEX9cIdvD99OvLMPEuQ +UA2hzRKO+A4roidNUT7yp8yy3BkQGLAr4JYaFINreeD+9BrIFx1jRbG3z8xqxtwh +8P+uR2pyLYaDxeyxkjM7zDV4ax/iV1+L+z3GiC5GnPZEKkpm89MdI7fzeChttVVk +CtpnxR3vxK2HqfcQFrTG5HNldzpAJk/tBrHRcyAnXrKs+XZhpOQ3gYoNY4fGeGYM +c9NyeAUZkqJ1nCfHBAR9bmmCEwZSmhSt5voqZ+zS3DWKG30WtNpYMNEEchtWq8Op +IEimZ341pZOjWqJ396zJ8qJ1XncffC/yAnRsb0xvhS149dwkDyH+17qVyF+V/pyb +5unjg6V9g0yZ9TKyH858sRG8acVXo6NhuxCg0w8mJ4LCxcJSTgDA0lXFQcuTBLlZ +YaXfD/dr60HfyH2ll4b5hlkww9jrg1uNW++FcsCHsZu5DV5QbhyVIYdhyp4dTV/7 +9SJJPmeMacQCNJqg783bpUyVaEecHAg8H/u+Zir0vWdRdpeekO28NLVqgQuPEqzs +Y53RCbjlbilzHud50HHUAqN3fKJK51I1GrjrSeV9xSVnB5psjmOjPvEagGu4kv+s +fu/fEge0HPx9FUA2xJR9u1/8swYsiAugoWxXFJVBSDJh2a4759ftd7b2mid0aX86 +OeJcY164mlLbu3d905Ez5mgVBHXDuk/LRwrvdprw48tqMB0Tv77egKbSeQzyQLD0 +ZhUQFIJ1cBlmFIw2ZdXUVlV2MJcK6XMlFkdyHRBTfiHI1V/Q2QFFLkTb64X3iTHC +Ckow0ibsT76pDCP+Buotfk7gho6WgiojC0URzZPG/KDHUHO173S6Nr23NBpVzxun +lKf5LiAC5LDoJmAx/XouYjh77LZLsi+jhuG3/DnIULZt8aSm5RKGZ6A3VgaaCXhp +tG3kSSCD6gKrYt7FrKHQ1dwPakPaDdOrBtd13823sPth7GMKmbhrC/x4Q768ml/i +Gk7DQoYbRkqi7t66aiYuJASxpYpsUWwO7MYOz2vGxDdskp/AukwnNJTA8e2rL0ki +seqJ2l7+snUXZ4SFJ/D+wfMK2WeQRTJB4hgu7AQyp543mQ+EYZaNMtKIdgQL86q7 +MZVAx5ad82GNtAMgGLyf72bE1mkTK44poT6dob25z7MxFsM7zjadNDzcgBiYdEHq +/8U= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.secrets b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.secrets new file mode 100644 index 000000000..ff6a247f0 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: RSA daveKey.pem "OJlNZBx+80dLh4wC6fw5LmBd" diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/strongswan.conf b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/strongswan.conf new file mode 100644 index 000000000..3c22edc23 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/dave/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 pkcs8 gmp random x509 revocation hmac xcbc ctr ccm gcm stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/ipsec.conf new file mode 100755 index 000000000..274521386 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/ipsec.conf @@ -0,0 +1,22 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + +conn rw + left=PH_IP_MOON + leftcert=moonCert.pem + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + leftfirewall=yes + right=%any + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/ipsec.d/private/moonKey.pem b/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/ipsec.d/private/moonKey.pem new file mode 100644 index 000000000..02045f510 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/ipsec.d/private/moonKey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKL2M91Lu6BYYh +WxWgMS9z9TMSTwszm5rhO7ZIsCtMRo4PAeYw+++SGXt3CPXb/+p+SWKGlm11rPE7 +1eQ3ehgh2C3hAurfmWO0iQQaCw+fdreeIVCqOQIOP6UqZ327h5yYYpHk8VQv4vBJ +TpxclU1PqnWheqe1ZlLxsW773LRml/fQt/UgvJkCBTZZONLNMfK+7TDnYaVsAtnc +gvDN78nUNEe2qY92KK7SrBJ6SpUEg49m51F+XgsGcsgWVHS85on3Om/G48crLEVJ +jdu8CxewSRVgb+lPJWzHd8QsU0Vg/7vlqs3ZRMyNtNKrr4opSvVbA6agGlTXhDCr +eDiXU8KHAgMBAAECggEAIEUH9epqO/p9uf0rqnGvPTa5fAaZpxcC1UgOg/N6NaZd +LhADiXXseskOZ6VKeF6UMqvLyedgeROtPPuafTBDgcNbLzqj+iQlQb9MpEt3pt/v +1pFCqqiGp3eJCQeTjcbLO5cf6gaKhUoXR9wAINbDjB+MvsUw10cJngHP0Osc7/Kw +d70Hqu9JibdVlGFLFqd4iRouSQNp0qlXHd9c0WUzFjioo8lhhKglnrWIyqs7v6uc +D3e2bIMOzw8pTcG2el82t14+CV4keGTxmrIS/b804JJTFsoTw0K0ukZOz5PSqOOe +7iTdY93dk4EBqfS48N6Qdl4cH9pcYuFhzHEnlK6uoQKBgQD4XWCmmQRHkm2hq523 +8JSl1DWxH3DF/vlUGongWJgAEZDP3GUbiiPMv+jnvazSJXdvAWmdBr5a5avEaQ/p +m4H9nzaelzQ3+8ui79vh3G+Difsr5444R/TwUyOyx7a2pMhcoKpyZCdHQ09DWPC6 +8Qqxc/nD8k6WdFcBed3iPGwkjQKBgQDQZpPrXJK21Rb2MLebG5jqORDLxMRCpHec +4W9bCYJchY6k38xNM+6z5N6XGn+l0qFT6ag+ZfdSfKd7k+/CV5YOrdjOW1flkNkY +nlQmUq42d8YjNDo5wdFtvvMGlAbqpJE+66BuCjrzyFOdvUvn2crzzNZUrjl65/qn +K6gj5LAgYwKBgQDvK8TySfKEFe97O6/TPVt4YeYenn9UPBjQNApIQCiIEGJauQuo +vJuDBd/8onx1llzwSfTxoVfYYsnJh78qIHXKzfKkQEmqC9FrI/6j/0pn6o01F3Su +oCSw9e8vsAE023STNqlNJUNp7di7qz+PVqYMgvmoB4REgN50bm4M+lDN1QKBgHsy +2Ok/rcAGEu/xdulsFCcLG0HLDdbz0X5dyu2/nmBB2EThxK4zMD8K4wfi82k9LoAj +1oEk2GPcK0qj9w4lpyEAZvX/C+Q7kAu8tbR+Fl0+y1ROcMlqKfu98X+HDNuz8+WF +eC71P0qUt9G9cV0b5J3iDya6ZGKjNwuShHDLpc9PAoGAMk/6z3BeZ0b3QdJP9qoL +sUqtVcukHrd1jmzA1R9A/qxrSkWc43SvQkKH9gKwYUUgB5tDa46QzeDd/2eTBOnv +3XSi/7/m5OG9EjbDYEE/LSZW4As+PLIXVnZxv3OnIqIi5ehdEJ/ix3yvWVH1ufQX +HHRK+nF/5+kwZIjmq4c0Epg= +-----END PRIVATE KEY----- diff --git a/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..9333bcdf4 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/hosts/moon/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl test-vectors aes des sha1 sha2 md5 pem pkcs1 pkcs8 gmp random x509 revocation hmac xcbc ctr ccm gcm stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/rw-pkcs8/posttest.dat b/testing/tests/ikev2/rw-pkcs8/posttest.dat new file mode 100644 index 000000000..7cebd7f25 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/posttest.dat @@ -0,0 +1,6 @@ +moon::ipsec stop +carol::ipsec stop +dave::ipsec stop +moon::/etc/init.d/iptables stop 2> /dev/null +carol::/etc/init.d/iptables stop 2> /dev/null +dave::/etc/init.d/iptables stop 2> /dev/null diff --git a/testing/tests/ikev2/rw-pkcs8/pretest.dat b/testing/tests/ikev2/rw-pkcs8/pretest.dat new file mode 100644 index 000000000..42e9d7c24 --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/pretest.dat @@ -0,0 +1,9 @@ +moon::/etc/init.d/iptables start 2> /dev/null +carol::/etc/init.d/iptables start 2> /dev/null +dave::/etc/init.d/iptables start 2> /dev/null +moon::ipsec start +carol::ipsec start +dave::ipsec start +carol::sleep 1 +carol::ipsec up home +dave::ipsec up home diff --git a/testing/tests/ikev2/rw-pkcs8/test.conf b/testing/tests/ikev2/rw-pkcs8/test.conf new file mode 100644 index 000000000..70416826e --- /dev/null +++ b/testing/tests/ikev2/rw-pkcs8/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# UML instances used for this test + +# All UML instances that are required for this test +# +UMLHOSTS="alice moon carol winnetou dave" + +# Corresponding block diagram +# +DIAGRAM="a-m-c-w-d.png" + +# UML instances on which tcpdump is to be started +# +TCPDUMPHOSTS="moon" + +# UML instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon carol dave" diff --git a/testing/tests/ikev2/rw-radius-accounting/description.txt b/testing/tests/ikev2/rw-radius-accounting/description.txt new file mode 100644 index 000000000..6d0224cdc --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/description.txt @@ -0,0 +1,14 @@ +The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>. +At the outset the gateway authenticates itself to the client by sending +an IKEv2 <b>RSA signature</b> accompanied by a certificate. +<b>carol</b> then uses the <i>Extensible Authentication Protocol</i> +in association with an <i>MD5</i> challenge and response protocol +(<b>EAP-MD5</b>) to authenticate against the gateway <b>moon</b>. +In addition to her IKEv2 identity <b>carol@strongswan.org</b>, roadwarrior +<b>carol</b> uses the EAP identity <b>carol</b>. +The user password is kept in <b>ipsec.secrets</b> on the client <b>carol</b> +and the gateway forwards all EAP messages to the RADIUS server <b>alice</b>. +<p/> +Since RADIUS accounting is enabled in <b>strongswan.conf</b>, gateway <b>moon</b> +sends user name, connection time and data volume information to the +RADIUS server <b>alice</b>. diff --git a/testing/tests/ikev2/rw-radius-accounting/evaltest.dat b/testing/tests/ikev2/rw-radius-accounting/evaltest.dat new file mode 100644 index 000000000..d23d6360b --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/evaltest.dat @@ -0,0 +1,15 @@ +carol::cat /var/log/daemon.log::authentication of .*moon.strongswan.org.* with RSA signature successful::YES +moon::cat /var/log/daemon.log::received EAP identity .*carol::YES +carol::cat /var/log/daemon.log::server requested EAP_MD5 authentication::YES +carol::cat /var/log/daemon.log::authentication of .*moon.strongswan.org.* with EAP successful::YES +moon::cat /var/log/daemon.log::authentication of .*carol@strongswan.org.* with EAP successful::YES +moon::ipsec statusall::rw-eap.*ESTABLISHED::YES +carol::ipsec statusall::home.*ESTABLISHED::YES +carol::ping -c 5 -s 1392 PH_IP_ALICE::1400 bytes from PH_IP_ALICE::YES +carol::ipsec down home::no output expected::NO +moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES +moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES +alice::cat /var/log/radius/radacct/10.1.0.1/*::User-Name =.*carol::YES +alice::cat /var/log/radius/radacct/10.1.0.1/*::Acct-Output-Octets = 7100::YES +alice::cat /var/log/radius/radacct/10.1.0.1/*::Acct-Input-Octets = 7100::YES + diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/clients.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/clients.conf new file mode 100644 index 000000000..f4e179aa4 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/clients.conf @@ -0,0 +1,4 @@ +client PH_IP_MOON1 { + secret = gv6URkSs + shortname = moon +} diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/eap.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/eap.conf new file mode 100644 index 000000000..623f42904 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/eap.conf @@ -0,0 +1,5 @@ +eap { + default_eap_type = md5 + md5 { + } +} diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/proxy.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/proxy.conf new file mode 100644 index 000000000..783587b55 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/proxy.conf @@ -0,0 +1,5 @@ +realm LOCAL { + type = radius + authhost = LOCAL + accthost = LOCAL +} diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/radiusd.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/radiusd.conf new file mode 100644 index 000000000..1143a0473 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/radiusd.conf @@ -0,0 +1,120 @@ +# radiusd.conf -- FreeRADIUS server configuration file. + +prefix = /usr +exec_prefix = ${prefix} +sysconfdir = /etc +localstatedir = /var +sbindir = ${exec_prefix}/sbin +logdir = ${localstatedir}/log/radius +raddbdir = ${sysconfdir}/raddb +radacctdir = ${logdir}/radacct + +# name of the running server. See also the "-n" command-line option. +name = radiusd + +# Location of config and logfiles. +confdir = ${raddbdir} +run_dir = ${localstatedir}/run/radiusd + +# Should likely be ${localstatedir}/lib/radiusd +db_dir = ${raddbdir} + +# libdir: Where to find the rlm_* modules. +libdir = ${exec_prefix}/lib + +# pidfile: Where to place the PID of the RADIUS server. +pidfile = ${run_dir}/${name}.pid + +# max_request_time: The maximum time (in seconds) to handle a request. +max_request_time = 30 + +# cleanup_delay: The time to wait (in seconds) before cleaning up +cleanup_delay = 5 + +# max_requests: The maximum number of requests which the server keeps +max_requests = 1024 + +# listen: Make the server listen on a particular IP address, and send +listen { + type = auth + ipaddr = PH_IP_ALICE + port = 0 +} + +# This second "listen" section is for listening on the accounting +# port, too. +# +listen { + type = acct + ipaddr = PH_IP_ALICE + port = 0 +} + +# hostname_lookups: Log the names of clients or just their IP addresses +hostname_lookups = no + +# Core dumps are a bad thing. This should only be set to 'yes' +allow_core_dumps = no + +# Regular expressions +regular_expressions = yes +extended_expressions = yes + +# Logging section. The various "log_*" configuration items +log { + destination = files + file = ${logdir}/radius.log + syslog_facility = daemon + stripped_names = no + auth = yes + auth_badpass = yes + auth_goodpass = yes +} + +# The program to execute to do concurrency checks. +checkrad = ${sbindir}/checkrad + +# Security considerations +security { + max_attributes = 200 + reject_delay = 1 + status_server = yes +} + +# PROXY CONFIGURATION +proxy_requests = yes +$INCLUDE proxy.conf + +# CLIENTS CONFIGURATION +$INCLUDE clients.conf + +# THREAD POOL CONFIGURATION +thread pool { + start_servers = 5 + max_servers = 32 + min_spare_servers = 3 + max_spare_servers = 10 + max_requests_per_server = 0 +} + +# MODULE CONFIGURATION +modules { + $INCLUDE ${confdir}/modules/ + $INCLUDE eap.conf + $INCLUDE sql.conf + $INCLUDE sql/mysql/counter.conf +} + +# Instantiation +instantiate { + exec + expr + expiration + logintime +} + +# Policies +$INCLUDE policy.conf + +# Include all enabled virtual hosts +$INCLUDE sites-enabled/ diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/sites-available/default b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/sites-available/default new file mode 100644 index 000000000..2de32a6f2 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/sites-available/default @@ -0,0 +1,43 @@ +authorize { + eap { + ok = return + } + files +} + +authenticate { + eap +} + +preacct { + preprocess + acct_unique + suffix + files +} + +accounting { + detail + unix + radutmp + attr_filter.accounting_response +} + +session { + radutmp +} + +post-auth { + exec + Post-Auth-Type REJECT { + attr_filter.access_reject + } +} + +pre-proxy { +} + +post-proxy { + eap +} + diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/users b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/users new file mode 100644 index 000000000..247b918e3 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/alice/etc/raddb/users @@ -0,0 +1 @@ +carol Cleartext-Password := "Ar3etTnp" diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/ipsec.conf new file mode 100755 index 000000000..5f779d1af --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/ipsec.conf @@ -0,0 +1,24 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn home + left=PH_IP_CAROL + leftnexthop=%direct + leftid=carol@strongswan.org + leftauth=eap + leftfirewall=yes + eap_identity=carol + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + rightauth=pubkey + auto=add diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/ipsec.secrets b/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/ipsec.secrets new file mode 100644 index 000000000..23d79cf2e --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +carol : EAP "Ar3etTnp" diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..fe067d344 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/carol/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac xcbc stroke kernel-netlink socket-default fips-prf eap-md5 eap-identity updown +} diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/init.d/iptables b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/init.d/iptables new file mode 100755 index 000000000..962a418d9 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/init.d/iptables @@ -0,0 +1,88 @@ +#!/sbin/runscript +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +opts="start stop reload" + +depend() { + before net + need logger +} + +start() { + ebegin "Starting firewall" + + # enable IP forwarding + echo 1 > /proc/sys/net/ipv4/ip_forward + + # default policy is DROP + /sbin/iptables -P INPUT DROP + /sbin/iptables -P OUTPUT DROP + /sbin/iptables -P FORWARD DROP + + # allow esp + iptables -A INPUT -i eth0 -p 50 -j ACCEPT + iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT + + # allow IKE + iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT + iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT + + # allow MobIKE + iptables -A INPUT -i eth0 -p udp --sport 4500 --dport 4500 -j ACCEPT + iptables -A OUTPUT -o eth0 -p udp --dport 4500 --sport 4500 -j ACCEPT + + # allow crl fetch from winnetou + iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT + iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT + + # allow RADIUS protocol with alice + iptables -A INPUT -i eth1 -p udp --sport 1812 -s PH_IP_ALICE -j ACCEPT + iptables -A OUTPUT -o eth1 -p udp --dport 1812 -d PH_IP_ALICE -j ACCEPT + + # allow RADIUS accounting protocol with alice + iptables -A INPUT -i eth1 -p udp --sport 1813 -s PH_IP_ALICE -j ACCEPT + iptables -A OUTPUT -o eth1 -p udp --dport 1813 -d PH_IP_ALICE -j ACCEPT + + # allow ssh + iptables -A INPUT -p tcp --dport 22 -j ACCEPT + iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT + + eend $? +} + +stop() { + ebegin "Stopping firewall" + for a in `cat /proc/net/ip_tables_names`; do + /sbin/iptables -F -t $a + /sbin/iptables -X -t $a + + if [ $a == nat ]; then + /sbin/iptables -t nat -P PREROUTING ACCEPT + /sbin/iptables -t nat -P POSTROUTING ACCEPT + /sbin/iptables -t nat -P OUTPUT ACCEPT + elif [ $a == mangle ]; then + /sbin/iptables -t mangle -P PREROUTING ACCEPT + /sbin/iptables -t mangle -P INPUT ACCEPT + /sbin/iptables -t mangle -P FORWARD ACCEPT + /sbin/iptables -t mangle -P OUTPUT ACCEPT + /sbin/iptables -t mangle -P POSTROUTING ACCEPT + elif [ $a == filter ]; then + /sbin/iptables -t filter -P INPUT ACCEPT + /sbin/iptables -t filter -P FORWARD ACCEPT + /sbin/iptables -t filter -P OUTPUT ACCEPT + fi + done + eend $? +} + +reload() { + ebegin "Flushing firewall" + for a in `cat /proc/net/ip_tables_names`; do + /sbin/iptables -F -t $a + /sbin/iptables -X -t $a + done; + eend $? + start +} + diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/ipsec.conf new file mode 100755 index 000000000..11ff84400 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/ipsec.conf @@ -0,0 +1,26 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn rw-eap + left=PH_IP_MOON + leftsubnet=10.1.0.0/16 + leftid=@moon.strongswan.org + leftcert=moonCert.pem + leftauth=pubkey + leftfirewall=yes + rightid=*@strongswan.org + rightsendcert=never + rightauth=eap-radius + eap_identity=%any + right=%any + auto=add diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/ipsec.secrets b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/ipsec.secrets new file mode 100644 index 000000000..e86d6aa5c --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: RSA moonKey.pem diff --git a/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..52927c1fd --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/hosts/moon/etc/strongswan.conf @@ -0,0 +1,12 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac xcbc stroke kernel-netlink socket-default fips-prf eap-radius eap-identity updown + plugins { + eap-radius { + secret = gv6URkSs + server = PH_IP_ALICE + accounting = yes + } + } +} diff --git a/testing/tests/ikev2/rw-radius-accounting/posttest.dat b/testing/tests/ikev2/rw-radius-accounting/posttest.dat new file mode 100644 index 000000000..b1f971402 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/posttest.dat @@ -0,0 +1,7 @@ +carol::ipsec stop +moon::ipsec stop +alice::/etc/init.d/radiusd stop +alice::cat /var/log/radius/radacct/10.1.0.1/* +carol::/etc/init.d/iptables stop 2> /dev/null +moon::/etc/init.d/iptables stop 2> /dev/null + diff --git a/testing/tests/ikev2/rw-radius-accounting/pretest.dat b/testing/tests/ikev2/rw-radius-accounting/pretest.dat new file mode 100644 index 000000000..30c8bd573 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/pretest.dat @@ -0,0 +1,9 @@ +moon::/etc/init.d/iptables start 2> /dev/null +carol::/etc/init.d/iptables start 2> /dev/null +alice::rm /var/log/radius/radacct/10.1.0.1/* +alice::/etc/init.d/radiusd start +moon::ipsec start +carol::ipsec start +carol::sleep 1 +carol::ipsec up home +carol::sleep 1 diff --git a/testing/tests/ikev2/rw-radius-accounting/test.conf b/testing/tests/ikev2/rw-radius-accounting/test.conf new file mode 100644 index 000000000..e0d77b583 --- /dev/null +++ b/testing/tests/ikev2/rw-radius-accounting/test.conf @@ -0,0 +1,26 @@ +#!/bin/bash +# +# This configuration file provides information on the +# UML instances used for this test + +# All UML instances that are required for this test +# +UMLHOSTS="alice carol moon" + +# Corresponding block diagram +# +DIAGRAM="a-m-c.png" + +# UML instances on which tcpdump is to be started +# +TCPDUMPHOSTS="moon" + +# UML instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon carol" + +# UML instances on which FreeRadius is started +# +RADIUSHOSTS="alice" + diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/description.txt b/testing/tests/openssl-ikev2/ecdsa-pkcs8/description.txt new file mode 100644 index 000000000..294a51cc7 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/description.txt @@ -0,0 +1,14 @@ +The hosts <b>carol</b>, <b>dave</b>, and <b>moon</b> use the <b>openssl</b> plugin +based on the <b>OpenSSL</b> library for all cryptographical and X.509 certificate functions. +<p> +The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each +to gateway <b>moon</b>. The authentication is based on <b>ECDSA signatures</b> +using <b>Elliptic Curve certificates</b> and matching EC private keys stored in the <b>PKCS#8</b> +format. <b>moon</b>'s key is unencrypted, <b>carol</b>'s key is encrypted with the default +PKCS#5 v1.5 DES algorithm and <b>dave</b>'s key with the PKCS#5 v2.0 3DES algorithm. +<p/> +Upon the successful establishment of the IPsec tunnels, <b>leftfirewall=yes</b> +automatically inserts iptables-based firewall rules that let pass the tunneled traffic. +In order to test both tunnel and firewall, both <b>carol</b> and <b>dave</b> ping +the client <b>alice</b> behind the gateway <b>moon</b>. + diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/evaltest.dat b/testing/tests/openssl-ikev2/ecdsa-pkcs8/evaltest.dat new file mode 100644 index 000000000..868da5776 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/evaltest.dat @@ -0,0 +1,14 @@ +moon::cat /var/log/daemon.log::authentication of.*carol@strongswan.org.*with ECDSA-256 signature successful::YES +moon::cat /var/log/daemon.log::authentication of.*dave@strongswan.org.*with ECDSA-384 signature successful::YES +carol::cat /var/log/daemon.log::authentication of.*moon.strongswan.org.*with ECDSA-521 signature successful::YES +dave::cat /var/log/daemon.log::authentication of.*moon.strongswan.org.*with ECDSA-521 signature successful::YES +moon::ipsec statusall::rw.*ESTABLISHED::YES +carol::ipsec statusall::home.*ESTABLISHED::YES +dave::ipsec statusall::home.*ESTABLISHED::YES +carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES +dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES +moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES +moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES +moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES +moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES + diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.conf b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.conf new file mode 100755 index 000000000..c75d6b2a1 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.conf @@ -0,0 +1,23 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn home + left=PH_IP_CAROL + leftcert=carolCert.pem + leftid=carol@strongswan.org + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + auto=add diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/cacerts/strongswanCert.pem new file mode 100644 index 000000000..3480a434a --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/cacerts/strongswanCert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICyDCCAiqgAwIBAgIJAPaidX4i76aJMAkGByqGSM49BAEwSDELMAkGA1UEBhMC +Q0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHjAcBgNVBAMTFXN0cm9uZ1N3 +YW4gRUMgUm9vdCBDQTAeFw0wODA2MjIxNDM2MDZaFw0xODA2MjAxNDM2MDZaMEgx +CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQD +ExVzdHJvbmdTd2FuIEVDIFJvb3QgQ0EwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYA +BAEUx1NvjNKzbDHaRPMsqIf/6SbUpzBa78N/WIyF6rYj8e5McAqfTfzUfFJZYoQn +/mbP3VfjOxRuMDjrlfvdgMxwkwFDigWQfHg3CJbS7eQjjO1MrxxIJUtfSTnF29tM +h6IYMdxaZKloCGCOrpmGCGdxD2/KwoX1SA3BlnjaNt7kSTonkqOBujCBtzAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUul35cbYTtWrR3bo2 +t6rSwe6P2NIweAYDVR0jBHEwb4AUul35cbYTtWrR3bo2t6rSwe6P2NKhTKRKMEgx +CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQD +ExVzdHJvbmdTd2FuIEVDIFJvb3QgQ0GCCQD2onV+Iu+miTAJBgcqhkjOPQQBA4GM +ADCBiAJCAL5pU3X6NYWjOYe0cxrah27UxtUDLUNkFG/Ojl+gOH4QB0CKY0HXNyrq +cgba73dXF/U0Cg3Ij/9g4Kd9GgYq0GlSAkIAqgqMKqXni8wbeGMJE2Mn2/8aHM3Q +3flpHSoeNWOe/VzpRviw+VRgA4vbhhKUXBtQSiea77/DXLwOp5w7rkBoEUg= +-----END CERTIFICATE----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/certs/carolCert.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/certs/carolCert.pem new file mode 100644 index 000000000..29709926a --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/certs/carolCert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC7zCCAlGgAwIBAgIBBDAJBgcqhkjOPQQBMEgxCzAJBgNVBAYTAkNIMRkwFwYD +VQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQDExVzdHJvbmdTd2FuIEVDIFJv +b3QgQ0EwHhcNMDgwNjIyMTYyOTE4WhcNMTMwNjIxMTYyOTE4WjBfMQswCQYDVQQG +EwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEWMBQGA1UECxMNRUNEU0Eg +MjU2IGJpdDEdMBsGA1UEAxQUY2Fyb2xAc3Ryb25nc3dhbi5vcmcwWTATBgcqhkjO +PQIBBggqhkjOPQMBBwNCAAQgp/Z/GgzvVCDdVcIYqERml0KroZEaVqiF8uy8dlTS +4mxNs6snDdEWh/LzXTd3NVnCihT2XgHxOk8NrX4hBMMYo4IBFDCCARAwCQYDVR0T +BAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFLdhGhurno1dU2SMx7UGXpa/lgJ9 +MHgGA1UdIwRxMG+AFLpd+XG2E7Vq0d26Nreq0sHuj9jSoUykSjBIMQswCQYDVQQG +EwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEeMBwGA1UEAxMVc3Ryb25n +U3dhbiBFQyBSb290IENBggkA9qJ1fiLvpokwHwYDVR0RBBgwFoEUY2Fyb2xAc3Ry +b25nc3dhbi5vcmcwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5zdHJvbmdz +d2FuLm9yZy9zdHJvbmdzd2FuX2VjLmNybDAJBgcqhkjOPQQBA4GMADCBiAJCATa+ +sBFW3vCx/JgLyxU85F2QuLO0/zdNBhIU0kN7kr1cYBBr8mpbhuNKm6iFe2DsFJZx +ii3DQjwvG46is2Njzi4vAkIA72lPodCDtAFpD/2PUxjzo6xTAFazUejobkdDTUXn +s0f8qIzzeQuTwLbp6pDmR/JGzhAeRvQT82njCo0PJ8Hbz1c= +-----END CERTIFICATE----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/private/carolKey.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/private/carolKey.pem new file mode 100644 index 000000000..5151408c4 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.d/private/carolKey.pem @@ -0,0 +1,6 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIGwMBsGCSqGSIb3DQEFAzAOBAgzSp1guD3Y3wICCAAEgZD3lUKsfeQ6rwQA2Q2U +VIyw2+53Z6kfn2vs9I8M197o4AtunwMJ7N6XY441fzcCbstmZ4HoubcuqCXsw5BA +liVtV0+vnMY6ViJ5OKgzBNGYW39Bu1A5/2NHh0Hsaoop6VPEY67KyhxHBrBrX6fk +Hn5eZyUKHa6NNGK9bWLqR8CjRNYQpg8NlwUIIxuFFTBw9oc= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.secrets b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.secrets new file mode 100644 index 000000000..4e53ef91a --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: ECDSA carolKey.pem "nH5ZQEWtku0RJEZ6" diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/strongswan.conf b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..35c522d0e --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/carol/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl pem pkcs1 pkcs8 openssl revocation random hmac stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.conf b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.conf new file mode 100755 index 000000000..080ce9bce --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.conf @@ -0,0 +1,23 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn home + left=PH_IP_DAVE + leftcert=daveCert.pem + leftid=dave@strongswan.org + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + auto=add diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/cacerts/strongswanCert.pem new file mode 100644 index 000000000..3480a434a --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/cacerts/strongswanCert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICyDCCAiqgAwIBAgIJAPaidX4i76aJMAkGByqGSM49BAEwSDELMAkGA1UEBhMC +Q0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHjAcBgNVBAMTFXN0cm9uZ1N3 +YW4gRUMgUm9vdCBDQTAeFw0wODA2MjIxNDM2MDZaFw0xODA2MjAxNDM2MDZaMEgx +CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQD +ExVzdHJvbmdTd2FuIEVDIFJvb3QgQ0EwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYA +BAEUx1NvjNKzbDHaRPMsqIf/6SbUpzBa78N/WIyF6rYj8e5McAqfTfzUfFJZYoQn +/mbP3VfjOxRuMDjrlfvdgMxwkwFDigWQfHg3CJbS7eQjjO1MrxxIJUtfSTnF29tM +h6IYMdxaZKloCGCOrpmGCGdxD2/KwoX1SA3BlnjaNt7kSTonkqOBujCBtzAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUul35cbYTtWrR3bo2 +t6rSwe6P2NIweAYDVR0jBHEwb4AUul35cbYTtWrR3bo2t6rSwe6P2NKhTKRKMEgx +CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQD +ExVzdHJvbmdTd2FuIEVDIFJvb3QgQ0GCCQD2onV+Iu+miTAJBgcqhkjOPQQBA4GM +ADCBiAJCAL5pU3X6NYWjOYe0cxrah27UxtUDLUNkFG/Ojl+gOH4QB0CKY0HXNyrq +cgba73dXF/U0Cg3Ij/9g4Kd9GgYq0GlSAkIAqgqMKqXni8wbeGMJE2Mn2/8aHM3Q +3flpHSoeNWOe/VzpRviw+VRgA4vbhhKUXBtQSiea77/DXLwOp5w7rkBoEUg= +-----END CERTIFICATE----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/certs/daveCert.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/certs/daveCert.pem new file mode 100644 index 000000000..075d8f1e5 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/certs/daveCert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAmygAwIBAgIBAzAJBgcqhkjOPQQBMEgxCzAJBgNVBAYTAkNIMRkwFwYD +VQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQDExVzdHJvbmdTd2FuIEVDIFJv +b3QgQ0EwHhcNMDgwNjIyMTYxMzU5WhcNMTMwNjIxMTYxMzU5WjBeMQswCQYDVQQG +EwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEWMBQGA1UECxMNRUNEU0Eg +Mzg0IGJpdDEcMBoGA1UEAxQTZGF2ZUBzdHJvbmdzd2FuLm9yZzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABPxEg8AaVNAwCXqg0p21Zc7YzPLA3voAWf233CZJpsjb1w3y +IeTUeIeGU7aLWAyuXgeBsx+lKzWy00LzPELOgK+3ulTHzBZg7s8kMGhwPWfV4JLA +zrso5+i64+Y4wvRCBaOCARMwggEPMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMB0G +A1UdDgQWBBQxJAy8gaP3RNBt1WTD27/IMzANmTB4BgNVHSMEcTBvgBS6XflxthO1 +atHduja3qtLB7o/Y0qFMpEowSDELMAkGA1UEBhMCQ0gxGTAXBgNVBAoTEExpbnV4 +IHN0cm9uZ1N3YW4xHjAcBgNVBAMTFXN0cm9uZ1N3YW4gRUMgUm9vdCBDQYIJAPai +dX4i76aJMB4GA1UdEQQXMBWBE2RhdmVAc3Ryb25nc3dhbi5vcmcwPAYDVR0fBDUw +MzAxoC+gLYYraHR0cDovL2NybC5zdHJvbmdzd2FuLm9yZy9zdHJvbmdzd2FuX2Vj +LmNybDAJBgcqhkjOPQQBA4GLADCBhwJCAZaqaroyGwqd7nb5dVVWjTK8glVzDFJH +ru4F6R+7fDCGEOaFlxf4GRkSrvQQA8vfgo6Md9XjBwq0r+9s3xt5xJjJAkElSo1/ +wyn8KQ3XN07UIaMvPctipq2OgpfteQK/F81CtZ+YCLEQt3xT7NQpriaKwGQxJAQv +g+Z+grJzTppAqpwRpg== +-----END CERTIFICATE----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/private/daveKey.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/private/daveKey.pem new file mode 100644 index 000000000..6555adac1 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.d/private/daveKey.pem @@ -0,0 +1,8 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBBTBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIYdanoOIx6X4CAggA +MBQGCCqGSIb3DQMHBAjoXTbsYeKpJwSBwBRbP2I3UOHWIrQhM7OqdWGt1+phdNy8 +5Xbus6e/DUp8xalohZD/QTZT3QpMEDuqJ0U3OIB01RWUmlPeUBx+NaPvLb/tQCZg +iLwdq5E9otbO9nK9G7NDeV22VigMZhZgtpdKqw7TAqgkzqpGfyM+mcUygiGxWwWC +UyC4G3rxyZVL2zRS/iDpJCIn2kceQk+mu+or3oX5rzzH82b69RQt36gEvd2rX/WU +gHH/XkNXhL0y0yRkVhowKHE2ZwMNTDbM3g== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.secrets b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.secrets new file mode 100644 index 000000000..56f6e6365 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: ECDSA daveKey.pem "OJlNZBx+80dLh4wC6fw5LmBd" diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/strongswan.conf b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/strongswan.conf new file mode 100644 index 000000000..35c522d0e --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/dave/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl pem pkcs1 pkcs8 openssl revocation random hmac stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.conf b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.conf new file mode 100755 index 000000000..c932101d2 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.conf @@ -0,0 +1,22 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + crlcheckinterval=180 + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn rw + left=PH_IP_MOON + leftcert=moonCert.pem + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + leftfirewall=yes + right=%any + auto=add diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/cacerts/strongswanCert.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/cacerts/strongswanCert.pem new file mode 100644 index 000000000..3480a434a --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/cacerts/strongswanCert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICyDCCAiqgAwIBAgIJAPaidX4i76aJMAkGByqGSM49BAEwSDELMAkGA1UEBhMC +Q0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHjAcBgNVBAMTFXN0cm9uZ1N3 +YW4gRUMgUm9vdCBDQTAeFw0wODA2MjIxNDM2MDZaFw0xODA2MjAxNDM2MDZaMEgx +CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQD +ExVzdHJvbmdTd2FuIEVDIFJvb3QgQ0EwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYA +BAEUx1NvjNKzbDHaRPMsqIf/6SbUpzBa78N/WIyF6rYj8e5McAqfTfzUfFJZYoQn +/mbP3VfjOxRuMDjrlfvdgMxwkwFDigWQfHg3CJbS7eQjjO1MrxxIJUtfSTnF29tM +h6IYMdxaZKloCGCOrpmGCGdxD2/KwoX1SA3BlnjaNt7kSTonkqOBujCBtzAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUul35cbYTtWrR3bo2 +t6rSwe6P2NIweAYDVR0jBHEwb4AUul35cbYTtWrR3bo2t6rSwe6P2NKhTKRKMEgx +CzAJBgNVBAYTAkNIMRkwFwYDVQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQD +ExVzdHJvbmdTd2FuIEVDIFJvb3QgQ0GCCQD2onV+Iu+miTAJBgcqhkjOPQQBA4GM +ADCBiAJCAL5pU3X6NYWjOYe0cxrah27UxtUDLUNkFG/Ojl+gOH4QB0CKY0HXNyrq +cgba73dXF/U0Cg3Ij/9g4Kd9GgYq0GlSAkIAqgqMKqXni8wbeGMJE2Mn2/8aHM3Q +3flpHSoeNWOe/VzpRviw+VRgA4vbhhKUXBtQSiea77/DXLwOp5w7rkBoEUg= +-----END CERTIFICATE----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/certs/moonCert.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/certs/moonCert.pem new file mode 100644 index 000000000..5178c7f38 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/certs/moonCert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMDCCApKgAwIBAgIBATAJBgcqhkjOPQQBMEgxCzAJBgNVBAYTAkNIMRkwFwYD +VQQKExBMaW51eCBzdHJvbmdTd2FuMR4wHAYDVQQDExVzdHJvbmdTd2FuIEVDIFJv +b3QgQ0EwHhcNMDgwNjIyMTQ0MzA3WhcNMTMwNjIxMTQ0MzA3WjBeMQswCQYDVQQG +EwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEWMBQGA1UECxMNRUNEU0Eg +NTIxIGJpdDEcMBoGA1UEAxMTbW9vbi5zdHJvbmdzd2FuLm9yZzCBmzAQBgcqhkjO +PQIBBgUrgQQAIwOBhgAEALmnl/PUy9v7Qsc914kdzY+TQ6VY2192oRoa9SkpxXrs +5GnWSJoz3yinpPHdchH0UknKt/C2Ik2k7izDH/Zau5gNAD1PqBrYWtcP+sLnH1G9 +BTibraniAUSpSaDhiWrfTteRNWqkzZI37a6YfKcBZozQcvYMW1co15EwZTptqykX +Eepuo4IBEzCCAQ8wCQYDVR0TBAIwADALBgNVHQ8EBAMCA6gwHQYDVR0OBBYEFDVU +Hzs47lOG0dHsezm6aFqdwJwfMHgGA1UdIwRxMG+AFLpd+XG2E7Vq0d26Nreq0sHu +j9jSoUykSjBIMQswCQYDVQQGEwJDSDEZMBcGA1UEChMQTGludXggc3Ryb25nU3dh +bjEeMBwGA1UEAxMVc3Ryb25nU3dhbiBFQyBSb290IENBggkA9qJ1fiLvpokwHgYD +VR0RBBcwFYITbW9vbi5zdHJvbmdzd2FuLm9yZzA8BgNVHR8ENTAzMDGgL6Athito +dHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW5fZWMuY3JsMAkGByqG +SM49BAEDgYwAMIGIAkIBDgZs1pXvm8SwT9S1m6nIHwuZsJDsDri/PWM6NXdMUXEt +l0p8cfq8PbJlK/0+eLz8Ec1zpWuF5vasFHkVhauHdnECQgEVuYTrlry9gAx7G4kH +mne2yDxTclEDziWxPG4UkZbkGttf9eZlsXmNoX/Z/fojXxMYZaPqM3eOT2h6ezMD +CI9WpQ== +-----END CERTIFICATE----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/private/moonKey.pem b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/private/moonKey.pem new file mode 100644 index 000000000..5c31d677c --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.d/private/moonKey.pem @@ -0,0 +1,8 @@ +-----BEGIN PRIVATE KEY----- +MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBrBxHEGICJRNkhm0H +WfARp+dIzm6Lw7eCbQXNM6jSGL4DVNDVCV42yOKQqifWEcNWxO+wWtBaz91IF5hz +/m4TbOGhgYkDgYYABAC5p5fz1Mvb+0LHPdeJHc2Pk0OlWNtfdqEaGvUpKcV67ORp +1kiaM98op6Tx3XIR9FJJyrfwtiJNpO4swx/2WruYDQA9T6ga2FrXD/rC5x9RvQU4 +m62p4gFEqUmg4Ylq307XkTVqpM2SN+2umHynAWaM0HL2DFtXKNeRMGU6baspFxHq +bg== +-----END PRIVATE KEY----- diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.secrets b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.secrets new file mode 100644 index 000000000..1ef3eccb5 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: ECDSA moonKey.pem diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/strongswan.conf b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..35c522d0e --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/hosts/moon/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl pem pkcs1 pkcs8 openssl revocation random hmac stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/posttest.dat b/testing/tests/openssl-ikev2/ecdsa-pkcs8/posttest.dat new file mode 100644 index 000000000..7cebd7f25 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/posttest.dat @@ -0,0 +1,6 @@ +moon::ipsec stop +carol::ipsec stop +dave::ipsec stop +moon::/etc/init.d/iptables stop 2> /dev/null +carol::/etc/init.d/iptables stop 2> /dev/null +dave::/etc/init.d/iptables stop 2> /dev/null diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/pretest.dat b/testing/tests/openssl-ikev2/ecdsa-pkcs8/pretest.dat new file mode 100644 index 000000000..42e9d7c24 --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/pretest.dat @@ -0,0 +1,9 @@ +moon::/etc/init.d/iptables start 2> /dev/null +carol::/etc/init.d/iptables start 2> /dev/null +dave::/etc/init.d/iptables start 2> /dev/null +moon::ipsec start +carol::ipsec start +dave::ipsec start +carol::sleep 1 +carol::ipsec up home +dave::ipsec up home diff --git a/testing/tests/openssl-ikev2/ecdsa-pkcs8/test.conf b/testing/tests/openssl-ikev2/ecdsa-pkcs8/test.conf new file mode 100644 index 000000000..70416826e --- /dev/null +++ b/testing/tests/openssl-ikev2/ecdsa-pkcs8/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# UML instances used for this test + +# All UML instances that are required for this test +# +UMLHOSTS="alice moon carol winnetou dave" + +# Corresponding block diagram +# +DIAGRAM="a-m-c-w-d.png" + +# UML instances on which tcpdump is to be started +# +TCPDUMPHOSTS="moon" + +# UML instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon carol dave" diff --git a/testing/tests/openssl-ikev2/rw-eap-tls-only/evaltest.dat b/testing/tests/openssl-ikev2/rw-eap-tls-only/evaltest.dat index dad834ca6..41ebec307 100644 --- a/testing/tests/openssl-ikev2/rw-eap-tls-only/evaltest.dat +++ b/testing/tests/openssl-ikev2/rw-eap-tls-only/evaltest.dat @@ -1,5 +1,5 @@ carol::cat /var/log/daemon.log::server requested EAP_TLS authentication::YES -carol::cat /var/log/daemon.log::negotiated TLS version TLS 1.2 with suite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256::YES +carol::cat /var/log/daemon.log::negotiated TLS 1.2 using suite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256::YES carol::cat /var/log/daemon.log::allow mutual EAP-only authentication::YES carol::cat /var/log/daemon.log::authentication of 'C=CH, O=Linux strongSwan, OU=ECDSA 521 bit, CN=moon.strongswan.org' with EAP successful::YES moon::cat /var/log/daemon.log::authentication of 'C=CH, O=Linux strongSwan, OU=ECDSA 256 bit, CN=carol@strongswan.org' with EAP successful::YES diff --git a/testing/tests/tnc/tnccs-11-radius/description.txt b/testing/tests/tnc/tnccs-11-radius/description.txt index 46ed5f584..83e5b96f3 100644 --- a/testing/tests/tnc/tnccs-11-radius/description.txt +++ b/testing/tests/tnc/tnccs-11-radius/description.txt @@ -7,7 +7,7 @@ At the outset the gateway authenticates itself to the clients by sending an IKEv The strong EAP-TTLS tunnel protects the ensuing weak client authentication based on <b>EAP-MD5</b>. In a next step the EAP-TNC protocol is used within the EAP-TTLS tunnel to determine the health of <b>carol</b> and <b>dave</b> via the <b>IF-TNCCS 1.1</b> client-server interface. -The IMC and IMV communicate are using the <b>IF-M</b> protocol defined by <b>RFC 5792 PA-TNC</b>. +The communication between IMCs and IMVs is based on the <b>IF-M</b> protocol defined by <b>RFC 5792 PA-TNC</b>. <p> <b>carol</b> passes the health test and <b>dave</b> fails. Based on these measurements the clients are connected by gateway <b>moon</b> to the "rw-allow" and "rw-isolate" subnets, respectively. diff --git a/testing/tests/tnc/tnccs-20-pdp/description.txt b/testing/tests/tnc/tnccs-20-pdp/description.txt new file mode 100644 index 000000000..a178211e1 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/description.txt @@ -0,0 +1,12 @@ +The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each to the policy enforcement +point <b>moon</b>. At the outset the gateway authenticates itself to the clients by sending an IKEv2 +<b>RSA signature</b> accompanied by a certificate. <b>carol</b> and <b>dave</b> then set up an +<b>EAP-TTLS</b> tunnel each via gateway <b>moon</b> to the policy decision point <b>alice</b> +authenticated by an X.509 AAA certificate. The strong EAP-TTLS tunnel protects the ensuing weak +client authentication based on <b>EAP-MD5</b>. In a next step the EAP-TNC protocol is used within +the EAP-TTLS tunnel to determine the health of <b>carol</b> and <b>dave</b> via the <b>IF-TNCCS 2.0</b> +client-server interface defined by <b>RFC 5793 PB-TNC</b>. The communication between IMCs and IMVs +is based on the <b>IF-M</b> protocol defined by <b>RFC 5792 PA-TNC</b>. +<p> +<b>carol</b> passes the health test and <b>dave</b> fails. Based on these measurements the clients +are connected by gateway <b>moon</b> to the "rw-allow" and "rw-isolate" subnets, respectively. diff --git a/testing/tests/tnc/tnccs-20-pdp/evaltest.dat b/testing/tests/tnc/tnccs-20-pdp/evaltest.dat new file mode 100644 index 000000000..ab78a9b76 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/evaltest.dat @@ -0,0 +1,19 @@ +carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with RSA signature successful::YES +carol::cat /var/log/daemon.log::PB-TNC access recommendation is .*Access Allowed::YES +carol::cat /var/log/daemon.log::EAP method EAP_TTLS succeeded, MSK established ::YES +carol::cat /var/log/daemon.log::CHILD_SA home{1} established.*TS 192.168.0.100/32 === 10.1.0.0/28::YES +dave::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with RSA signature successful::YES +dave::cat /var/log/daemon.log::PB-TNC access recommendation is .*Quarantined::YES +dave::cat /var/log/daemon.log::EAP method EAP_TTLS succeeded, MSK established ::YES +dave::cat /var/log/daemon.log::CHILD_SA home{1} established.*TS 192.168.0.200/32 === 10.1.0.16/28::YES +moon::cat /var/log/daemon.log::received RADIUS attribute Filter-Id: 'allow'::YES +moon::cat /var/log/daemon.log::authentication of 'carol@strongswan.org' with EAP successful::YES +moon::cat /var/log/daemon.log::received RADIUS attribute Filter-Id: 'isolate'::YES +moon::cat /var/log/daemon.log::authentication of 'dave@strongswan.org' with EAP successful::YES +moon::ipsec statusall::rw-allow.*10.1.0.0/28 === 192.168.0.100/32::YES +moon::ipsec statusall::rw-isolate.*10.1.0.16/28 === 192.168.0.200/32::YES +carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_seq=1::YES +carol::ping -c 1 PH_IP_VENUS::64 bytes from PH_IP_ALICE: icmp_seq=1::NO +dave::ping -c 1 PH_IP_VENUS::64 bytes from PH_IP_VENUS: icmp_seq=1::YES +dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_VENUS: icmp_seq=1::NO + diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.conf new file mode 100755 index 000000000..bdba8d32d --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.conf @@ -0,0 +1,10 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + plutostart=no + charondebug="tnc 3, imv 3" + +conn aaa + leftcert=aaaCert.pem + leftid=aaa.strongswan.org + auto=add diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.d/certs/aaaCert.pem b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.d/certs/aaaCert.pem new file mode 100644 index 000000000..6aeb0c0b1 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.d/certs/aaaCert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIBIjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ +MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS +b290IENBMB4XDTEwMDgwNDA4Mzg0MVoXDTE1MDgwMzA4Mzg0MVowRTELMAkGA1UE +BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEmFhYS5z +dHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2R +RcAYdZ/jOhHBSjrLDYT1OhRJ2mXjyuSbWyJQogF9c6sY8W2GhTC4e1gNThZM9+Pm +Vzs0R39kzxsmOFhuTfwIhavMzvkWJ7945WDvTpuo2teK4fTtfix3iuyycVXywa7W +Uum6vZb4uwNoFsZtlYSUFs+app/1VC3X8vEFvP9p//KW2fwbJ6PzR1XN/8AibxoF +AnfqAXUenRQ1Xs/07/xF4bkZ5MUNTFTo5H+BAc49lAC16TarSTPnX1D925kIGxni +wePHlIZrCYQTFr003+YNUehVvUxyv0NuIwlxFPokFPLDkQWk6SDvD87FW5IJ06cg +EbrCFjcIR9/2vIepJd8CAwEAAaOCARkwggEVMAkGA1UdEwQCMAAwCwYDVR0PBAQD +AgOoMB0GA1UdDgQWBBQS5lPpgsOE14sz7JGZimSmSbZOeDBtBgNVHSMEZjBkgBRd +p91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoT +EExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIB +ADAdBgNVHREEFjAUghJhYWEuc3Ryb25nc3dhbi5vcmcwEwYDVR0lBAwwCgYIKwYB +BQUHAwEwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5zdHJvbmdzd2FuLm9y +Zy9zdHJvbmdzd2FuLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAqM2eqrsJmAop2roa +yNeJt8317sdAll8TvDf+s4EeCtcpDT0cIX5vCumpL6E7nV9NWWDazGCAOkwWDPpp +iuq6R0Js8r0MbyIUbVgOe3xIOqLKd9YW0sb1IwfR/zvWcPUjnUHlqfRH7gdiR4G2 +bWIvKenl3hOQege/XnJNPUwzxeVX7k/qPivOk4I3pLnBjTRtFQdweHM95ex7Fk/d +HoeWjw5q3MxS3ZwXpKQxZvWU5SDkkc2NJ0/0sm+wca8NC86cXkGqcLFEgJo2l3Dr +EpZgxIhllub0M88PU7dQrDmy8OQ5j0fhayB1xpVO+REn3norclXZ2yrl4uz0eWR4 +v42sww== +-----END CERTIFICATE----- diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.d/private/aaaKey.pem b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.d/private/aaaKey.pem new file mode 100644 index 000000000..da8cdb051 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.d/private/aaaKey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArZFFwBh1n+M6EcFKOssNhPU6FEnaZePK5JtbIlCiAX1zqxjx +bYaFMLh7WA1OFkz34+ZXOzRHf2TPGyY4WG5N/AiFq8zO+RYnv3jlYO9Om6ja14rh +9O1+LHeK7LJxVfLBrtZS6bq9lvi7A2gWxm2VhJQWz5qmn/VULdfy8QW8/2n/8pbZ +/Bsno/NHVc3/wCJvGgUCd+oBdR6dFDVez/Tv/EXhuRnkxQ1MVOjkf4EBzj2UALXp +NqtJM+dfUP3bmQgbGeLB48eUhmsJhBMWvTTf5g1R6FW9THK/Q24jCXEU+iQU8sOR +BaTpIO8PzsVbkgnTpyARusIWNwhH3/a8h6kl3wIDAQABAoIBAQCJDzatQqNf5uds +Ld6YHtBGNf/vFYLJAuCtNaD5sAK+enpkmgXMH3X9yzBbj+Yh5hW6eaJYtiffiZOi +NMQ50KD0bSZhTBIE0GIC6Uz5BwBkGyr1Gk7kQsZoBt5Fm4O0A0a+8a/3secU2MWV +IxUZDGANmYOJ3O3HUstuiCDoA0gDyDt44n0RWOhKrPQmTP6vTItd/14Zi1Pg9ez3 +Mej/ulDmVV1R474EwUXbLLPBjP3vk++SLukWn4iWUeeHgDHSn0b/T5csUcH0kQMI +aYRU2FOoCPZpRxyTr9aZxcHhr5EhQSCg7zc8u0IjpTFm8kZ4uN+60777w1A/FH5X +YHq+yqVBAoGBANy6zM0egvyWQaX4YeoML65393iXt9OXW3uedMbmWc9VJ0bH7qdq +b4X5Xume8yY1/hF8nh7aC1npfVjdBuDse0iHJ/eBGfCJ2VoC6/ZoCzBD7q0Qn2If +/Sr/cbtQNTDkROT75hAo6XbewPGt7RjynH8sNmtclsZ0yyXHx0ml90tlAoGBAMlN +P4ObM0mgP2NMPeDFqUBnHVj/h/KGS9PKrqpsvFOUm5lxJNRIxbEBavWzonphRX1X +V83RICgCiWDAnqUaPfHh9mVBlyHCTWxrrnu3M9qbr5vZMFTyYiMoLxSfTmW5Qk8t +cArqBDowQbiaKJE9fHv+32Q0IYRhJFVcxZRdQXHzAoGALRBmJ6qHC5KRrJTdSK9c +PL55Y8F14lkQcFiVdtYol8/GyQigjMWKJ0wWOJQfCDoVuPQ8RAg4MQ8ebDoT4W/m +a5RMcJeG+Djsixf1nMT5I816uRKft6TYRyMH0To64dR4zFcxTTNNFtu7gJwFwAYo +NT6NjbXFgpbtsrTq1vpvVpECgYA0ldlhp8leEl58sg34CaqNCGLCPP5mfG6ShP/b +xUvtCYUcMFJOojQCaTxnsuVe0so0U/y750VfLkp029yVhKVp6n1TNi8kwn03NWn/ +J3yEPudA7xuRFUBNrtGdsX/pUtvfkx8RutAf4ztH3f1683Txb0MsCfI3gqjbI8D5 +YOMXwQKBgAJnMfPslZIg6jOpBCo6RjdwvjZyPXXyn4dcCyW//2+olPdWnuu+HRCZ +SkAWB7lSRLSvDZARHb63k+gwSl8lmwrSM53nDwaRdTKjhK2BFWsAKJNOhrOUQqJu +EXvH4R1NrqOkPqLoG5Iw3XFUh5lQGKvKkU28W6Weolj2saljbW2b +-----END RSA PRIVATE KEY----- diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.secrets b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.secrets new file mode 100644 index 000000000..96b9a8dd5 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/ipsec.secrets @@ -0,0 +1,6 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: RSA aaaKey.pem + +carol@strongswan.org : EAP "Ar3etTnp" +dave@strongswan.org : EAP "W7R0g3do" diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/strongswan.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/strongswan.conf new file mode 100644 index 000000000..b3769c7d9 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/strongswan.conf @@ -0,0 +1,33 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac stroke eap-identity eap-ttls eap-md5 eap-tnc tnc-pdp tnc-imv tnc-tnccs tnccs-20 + plugins { + eap-ttls { + phase2_method = md5 + phase2_piggyback = yes + phase2_tnc = yes + } + eap-tnc { + protocol = tnccs-2.0 + } + tnc-pdp { + server = aaa.strongswan.org + secret = gv6URkSs + } + } +} + +libimcv { + debug_level = 3 + plugins { + imv-test { + rounds = 1 + } + imv-scanner { + closed_port_policy = yes + tcp_ports = 22 + udp_ports = 500 4500 + } + } +} diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/tnc_config b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/tnc_config new file mode 100644 index 000000000..da732f68b --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/alice/etc/tnc_config @@ -0,0 +1,4 @@ +#IMV configuration file for strongSwan client + +IMV "Test" /usr/local/lib/ipsec/imcvs/imv-test.so +IMV "Scanner" /usr/local/lib/ipsec/imcvs/imv-scanner.so diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/ipsec.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/ipsec.conf new file mode 100755 index 000000000..a639b0426 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/ipsec.conf @@ -0,0 +1,24 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + plutostart=no + charondebug="tnc 3, imc 3" + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn home + left=PH_IP_CAROL + leftid=carol@strongswan.org + leftauth=eap + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + rightauth=pubkey + aaa_identity="C=CH, O=Linux strongSwan, CN=aaa.strongswan.org" + auto=add diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/ipsec.secrets b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/ipsec.secrets new file mode 100644 index 000000000..74942afda --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +carol@strongswan.org : EAP "Ar3etTnp" diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/strongswan.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..2f9a6d0b7 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/strongswan.conf @@ -0,0 +1,18 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac stroke kernel-netlink socket-default eap-identity eap-md5 eap-ttls eap-tnc tnc-imc tnc-tnccs tnccs-20 updown + plugins { + eap-tnc { + protocol = tnccs-2.0 + } + } +} + +libimcv { + plugins { + imc-test { + command = allow + } + } +} diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/tnc_config b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/tnc_config new file mode 100644 index 000000000..6166552f5 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/carol/etc/tnc_config @@ -0,0 +1,4 @@ +#IMC configuration file for strongSwan client + +IMC "Test" /usr/local/lib/ipsec/imcvs/imc-test.so +IMC "Scanner" /usr/local/lib/ipsec/imcvs/imc-scanner.so diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/ipsec.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/ipsec.conf new file mode 100755 index 000000000..5da78b4ab --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/ipsec.conf @@ -0,0 +1,24 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + plutostart=no + charondebug="tnc 3, imc 3" + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn home + left=PH_IP_DAVE + leftid=dave@strongswan.org + leftauth=eap + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + rightauth=pubkey + aaa_identity="C=CH, O=Linux strongSwan, CN=aaa.strongswan.org" + auto=add diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/ipsec.secrets b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/ipsec.secrets new file mode 100644 index 000000000..5496df7ad --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +dave@strongswan.org : EAP "W7R0g3do" diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/strongswan.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/strongswan.conf new file mode 100644 index 000000000..050d41b9f --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/strongswan.conf @@ -0,0 +1,18 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac stroke kernel-netlink socket-default eap-identity eap-md5 eap-ttls eap-tnc tnc-imc tnc-tnccs tnccs-20 updown + plugins { + eap-tnc { + protocol = tnccs-2.0 + } + } +} + +libimcv { + plugins { + imc-test { + command = isolate + } + } +} diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/tnc_config b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/tnc_config new file mode 100644 index 000000000..6166552f5 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/dave/etc/tnc_config @@ -0,0 +1,4 @@ +#IMC configuration file for strongSwan client + +IMC "Test" /usr/local/lib/ipsec/imcvs/imc-test.so +IMC "Scanner" /usr/local/lib/ipsec/imcvs/imc-scanner.so diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/init.d/iptables b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/init.d/iptables new file mode 100755 index 000000000..56587b2e8 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/init.d/iptables @@ -0,0 +1,84 @@ +#!/sbin/runscript +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +opts="start stop reload" + +depend() { + before net + need logger +} + +start() { + ebegin "Starting firewall" + + # enable IP forwarding + echo 1 > /proc/sys/net/ipv4/ip_forward + + # default policy is DROP + /sbin/iptables -P INPUT DROP + /sbin/iptables -P OUTPUT DROP + /sbin/iptables -P FORWARD DROP + + # allow esp + iptables -A INPUT -i eth0 -p 50 -j ACCEPT + iptables -A OUTPUT -o eth0 -p 50 -j ACCEPT + + # allow IKE + iptables -A INPUT -i eth0 -p udp --sport 500 --dport 500 -j ACCEPT + iptables -A OUTPUT -o eth0 -p udp --dport 500 --sport 500 -j ACCEPT + + # allow MobIKE + iptables -A INPUT -i eth0 -p udp --sport 4500 --dport 4500 -j ACCEPT + iptables -A OUTPUT -o eth0 -p udp --dport 4500 --sport 4500 -j ACCEPT + + # allow crl fetch from winnetou + iptables -A INPUT -i eth0 -p tcp --sport 80 -s PH_IP_WINNETOU -j ACCEPT + iptables -A OUTPUT -o eth0 -p tcp --dport 80 -d PH_IP_WINNETOU -j ACCEPT + + # allow RADIUS protocol with alice + iptables -A INPUT -i eth1 -p udp --sport 1812 -s PH_IP_ALICE -j ACCEPT + iptables -A OUTPUT -o eth1 -p udp --dport 1812 -d PH_IP_ALICE -j ACCEPT + + # allow ssh + iptables -A INPUT -p tcp --dport 22 -j ACCEPT + iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT + + eend $? +} + +stop() { + ebegin "Stopping firewall" + for a in `cat /proc/net/ip_tables_names`; do + /sbin/iptables -F -t $a + /sbin/iptables -X -t $a + + if [ $a == nat ]; then + /sbin/iptables -t nat -P PREROUTING ACCEPT + /sbin/iptables -t nat -P POSTROUTING ACCEPT + /sbin/iptables -t nat -P OUTPUT ACCEPT + elif [ $a == mangle ]; then + /sbin/iptables -t mangle -P PREROUTING ACCEPT + /sbin/iptables -t mangle -P INPUT ACCEPT + /sbin/iptables -t mangle -P FORWARD ACCEPT + /sbin/iptables -t mangle -P OUTPUT ACCEPT + /sbin/iptables -t mangle -P POSTROUTING ACCEPT + elif [ $a == filter ]; then + /sbin/iptables -t filter -P INPUT ACCEPT + /sbin/iptables -t filter -P FORWARD ACCEPT + /sbin/iptables -t filter -P OUTPUT ACCEPT + fi + done + eend $? +} + +reload() { + ebegin "Flushing firewall" + for a in `cat /proc/net/ip_tables_names`; do + /sbin/iptables -F -t $a + /sbin/iptables -X -t $a + done; + eend $? + start +} + diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/ipsec.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/ipsec.conf new file mode 100755 index 000000000..33dcdcfb0 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/ipsec.conf @@ -0,0 +1,35 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + strictcrlpolicy=no + plutostart=no + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + +conn rw-allow + rightgroups=allow + leftsubnet=10.1.0.0/28 + also=rw-eap + auto=add + +conn rw-isolate + rightgroups=isolate + leftsubnet=10.1.0.16/28 + also=rw-eap + auto=add + +conn rw-eap + left=PH_IP_MOON + leftcert=moonCert.pem + leftid=@moon.strongswan.org + leftauth=pubkey + leftfirewall=yes + rightauth=eap-radius + rightid=*@strongswan.org + rightsendcert=never + right=%any diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/ipsec.secrets b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/ipsec.secrets new file mode 100644 index 000000000..e86d6aa5c --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/ipsec.secrets @@ -0,0 +1,3 @@ +# /etc/ipsec.secrets - strongSwan IPsec secrets file + +: RSA moonKey.pem diff --git a/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/strongswan.conf b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..d298c17ad --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/hosts/moon/etc/strongswan.conf @@ -0,0 +1,14 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 revocation hmac stroke kernel-netlink socket-default eap-radius updown + multiple_authentication=no + plugins { + eap-radius { + secret = gv6URkSs + #server = PH_IP6_ALICE + server = PH_IP_ALICE + filter_id = yes + } + } +} diff --git a/testing/tests/tnc/tnccs-20-pdp/posttest.dat b/testing/tests/tnc/tnccs-20-pdp/posttest.dat new file mode 100644 index 000000000..16218f385 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/posttest.dat @@ -0,0 +1,7 @@ +moon::ipsec stop +carol::ipsec stop +dave::ipsec stop +alice::ipsec stop +moon::/etc/init.d/iptables stop 2> /dev/null +carol::/etc/init.d/iptables stop 2> /dev/null +dave::/etc/init.d/iptables stop 2> /dev/null diff --git a/testing/tests/tnc/tnccs-20-pdp/pretest.dat b/testing/tests/tnc/tnccs-20-pdp/pretest.dat new file mode 100644 index 000000000..9b9d6b699 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/pretest.dat @@ -0,0 +1,14 @@ +moon::/etc/init.d/iptables start 2> /dev/null +carol::/etc/init.d/iptables start 2> /dev/null +dave::/etc/init.d/iptables start 2> /dev/null +alice::cat /etc/tnc_config +carol::cat /etc/tnc_config +dave::cat /etc/tnc_config +alice::ipsec start +moon::ipsec start +carol::ipsec start +dave::ipsec start +carol::sleep 1 +carol::ipsec up home +dave::ipsec up home +dave::sleep 1 diff --git a/testing/tests/tnc/tnccs-20-pdp/test.conf b/testing/tests/tnc/tnccs-20-pdp/test.conf new file mode 100644 index 000000000..400628531 --- /dev/null +++ b/testing/tests/tnc/tnccs-20-pdp/test.conf @@ -0,0 +1,26 @@ +#!/bin/bash +# +# This configuration file provides information on the +# UML instances used for this test + +# All UML instances that are required for this test +# +UMLHOSTS="alice venus moon carol winnetou dave" + +# Corresponding block diagram +# +DIAGRAM="a-v-m-c-w-d.png" + +# UML instances on which tcpdump is to be started +# +TCPDUMPHOSTS="moon" + +# UML instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon carol dave alice" + +# UML instances on which FreeRadius is started +# +RADIUSHOSTS= + diff --git a/testing/tests/tnc/tnccs-20/hosts/carol/etc/strongswan.conf b/testing/tests/tnc/tnccs-20/hosts/carol/etc/strongswan.conf index 78eaf0e6f..50d7af66b 100644 --- a/testing/tests/tnc/tnccs-20/hosts/carol/etc/strongswan.conf +++ b/testing/tests/tnc/tnccs-20/hosts/carol/etc/strongswan.conf @@ -14,6 +14,7 @@ libimcv { plugins { imc-test { command = allow + additional_ids = 2 } } } diff --git a/testing/tests/tnc/tnccs-20/hosts/dave/etc/strongswan.conf b/testing/tests/tnc/tnccs-20/hosts/dave/etc/strongswan.conf index 2e56fb165..b67541c3c 100644 --- a/testing/tests/tnc/tnccs-20/hosts/dave/etc/strongswan.conf +++ b/testing/tests/tnc/tnccs-20/hosts/dave/etc/strongswan.conf @@ -17,6 +17,7 @@ libimcv { plugins { imc-test { command = isolate + additional_ids = 1 } } } |