Skip to content

Commit

Permalink
tcti-mssim: Replace liburiparser with custom key/value pair parser.
Browse files Browse the repository at this point in the history
This removes our use of liburiparser with a custom key / value pair
parser. The parser is implemented in the key-value-parse module under
the util directory. The parser is designed to extract a series of key
/ value pairs where each key and value are separated by the '='
character and each pair is separated by the ',' character. The parser
is composed of three parts:

1) The 'parse_key_value' function is used to extract key /value pairs
separated by the '=' character. This function modifies the string by
using the 'strok_r' function to extract the key and value. A reference
to each is then returned to the caller using the key_value_t structure.

2) The 'parse_key_value_string' function is used to extract each key /
value pair parsing the provided string on the ',' character using the
same method as the 'parse_key_value' function. Each string containing a
key / value pair is then passed to the 'parse_key_value' function to
extract the individual components.

3) Finally the 'parse_key_value_string' function is passed a function
pointer conforming to the 'KeyValueFunc' type. This function is invoked
for each key / value pair extracted and is passed a reference to the
key_value_t structure from the previous step. It is also passed a void
pointer to some caller provided data structure which allows the callback
to do something with the key / value pairs. For the purposes of the
mssim TCTI we simply identify valid / invalid keys and store their
values in a data structure.

Once the parser is done extracting data from the provided string the
mssim TCTI will either return an error indicating the configuration
string was invalid, or continue initializing the TCTI based on the
provided data. If a NULL configuration string is provided defaults are
used.

Additionally this commit:
1) Removes the check for liburiparser from the autoconf file.
2) Updates the .travis.yml file to no longer install liburiparser as a
build dependency.
3) Adds unit tests for the functions described above.
4) Updates existing tests and test infrastructure to use configuration
strings in the new format.
5) Updates the man page for the Tss2_Tcti_Mssim_Init fucntion to
describe the new configuration string format.
6) Updates the default configuration string to use 'localhost' instead
of a raw IPv4 address to make the library friendly to platforms that
only support IPv6.

Signed-off-by: Philip Tricca <philip.b.tricca@intel.com>
  • Loading branch information
flihp committed Apr 24, 2018
1 parent f517ee5 commit e394cff
Show file tree
Hide file tree
Showing 13 changed files with 592 additions and 134 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ addons:
- autoconf-archive
- cmake
- libgcrypt20-dev
- liburiparser-dev
- realpath
- lcov
- libssl-dev
Expand Down
5 changes: 5 additions & 0 deletions Makefile-test.am
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ TESTS_UNIT = \
test/unit/CopyCommandHeader \
test/unit/GetNumHandles \
test/unit/io \
test/unit/key-value-parse \
test/unit/tcti-device \
test/unit/tcti-mssim \
test/unit/UINT8-marshal \
Expand Down Expand Up @@ -211,6 +212,10 @@ test_unit_io_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil)
test_unit_io_LDFLAGS = -Wl,--wrap=connect,--wrap=read,--wrap=socket,--wrap=write
test_unit_io_SOURCES = test/unit/io.c

test_unit_key_value_parse_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS)
test_unit_key_value_parse_LDADD = $(CMOCKA_LIBS) $(libutil)
test_unit_key_value_parse_SOURCES = test/unit/key-value-parse.c

test_unit_CommonPreparePrologue_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS)
test_unit_CommonPreparePrologue_LDFLAGS = -Wl,--unresolved-symbols=ignore-all
test_unit_CommonPreparePrologue_LDADD = $(CMOCKA_LIBS) $(libtss2_sys)
Expand Down
3 changes: 0 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ AS_IF([test "x$enable_unit" != xno],
[AC_MSG_ERROR([cmocka_err])])])
AM_CONDITIONAL([UNIT], [test "x$enable_unit" != xno])

# Uriparser library required by simulator TCTI library.
PKG_CHECK_MODULES([URIPARSER],[liburiparser])

AC_ARG_ENABLE([esapi],
[AS_HELP_STRING([--enable-esapi],
[build the esapi layer (default is yes)])],
Expand Down
30 changes: 20 additions & 10 deletions man/Tss2_Tcti_Mssim_Init.3.in
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,26 @@ function in the section titled
The
.I conf
parameter is a C string used to configure the TCTI context. This
configuration string is a URI with the IP address and port used to connect
to an instance of the Microsoft TPM2 simulator. The URI scheme used is the
non-standard
.I tcp
scheme. If a NULL
configuration string is a series of key / value pairs that specify the host
and port used to connect to an instance of the Microsoft TPM2 simulator. The
keys and values are separated by the '=' character, while each key / value
pair is separated by the ',' character.

The only keys supported in the
.I conf
string are
.B host
and
.B port.
The host may be an IPv4 address, an IPv6 address, or a host name. The port
must be a valid uint16_t in string form. If a NULL
.I conf
string is provided then the default of
.I tcp://127.0.0.1:2321/
is used. If the URI provided omits the port component then the default port
of 2321 is used.
string is provided by the caller then the default of
"host=localhost,port=2321" is used. If either
.B host
or
.B port
are omitted then their respective default value will be used.
.sp
Once initialized, the TCTI context returned exposes the Trusted Computing
Group (TCG) defined API for the lowest level communication with the TPM.
Expand Down Expand Up @@ -104,7 +114,7 @@ TCTI initialization fragment:
TSS2_RC rc;
TSS2_TCTI_CONTEXT *tcti_context;
size_t size;
const char *conf = "tcp://127.0.0.1:2321/"
const char *conf = "host=localhost,port=2321"

rc = Tss2_Tcti_Mssim_Init (NULL, &size, NULL);
if (rc != TSS2_RC_SUCCESS) {
Expand Down
2 changes: 1 addition & 1 deletion src/tss2-esys/esys_tcti_default.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct {
.description = "Access to /dev/tpmrm0" },
{ .init = Tss2_Tcti_Device_Init, .conf = "/dev/tpm0",
.description = "Access to /dev/tpm0" },
{ .init = Tss2_Tcti_Mssim_Init, .conf = "tcp://127.0.0.1:2321",
{ .init = Tss2_Tcti_Mssim_Init, .conf = "host=localhost,port=2321",
.description = "Access to Mssim-simulator for tcp://localhost:2321" },
};

Expand Down
143 changes: 67 additions & 76 deletions src/tss2-tcti/tcti-mssim.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,15 @@
#include <inttypes.h>
#include <unistd.h>

#include <uriparser/Uri.h>

#include "tss2_mu.h"
#include "tss2_tcti_mssim.h"

#include "tcti-mssim.h"
#include "tcti-common.h"
#include "util/key-value-parse.h"
#define LOGMODULE tcti
#include "util/log.h"

#define TCTI_SOCKET_DEFAULT_CONF "tcp://127.0.0.1:2321"
#define TCTI_SOCKET_DEFAULT_PORT 2321

/*
* This function wraps the "up-cast" of the opaque TCTI context type to the
* type for the mssim TCTI context. The only safeguard we have to ensure this
Expand Down Expand Up @@ -453,71 +449,38 @@ string_to_port (char port_str[6])
return port;
}
/*
* This function extracts the hostname and port part of the provided conf
* string (which is really just a URI). The hostname parameter is an output
* buffer that must be large enough to hold the hostname. HOST_NAME_MAX is
* probably a good size. The 'port' parameter is an output parameter where
* we store the port from the URI after we convert it to a uint16.
* If the URI does not contain a port number then the contents of the 'port'
* parameter will not be changed.
* This function returns TSS2_RC_SUCCESS when the 'hostname' and 'port' have
* been populated successfully. On failure it will return
* TSS2_TCTI_RC_BAD_VALUE to indicate that the provided conf string contains
* values that we can't parse or are invalid.
* This function is a callback conforming to the KeyValueFunc prototype. It
* is called by the key-value-parse module for each key / value pair extracted
* from the configuration string. Its sole purpose is to identify valid keys
* from the conf string and to store their corresponding values in the
* mssim_conf_t structure which is passed through the 'user_data' parameter.
*/
TSS2_RC
conf_str_to_host_port (
const char *conf,
char *hostname,
uint16_t *port)
mssim_kv_callback (const key_value_t *key_value,
void *user_data)
{
UriParserStateA state;
UriUriA uri;
/* maximum 5 digits in uint16_t + 1 for \0 */
char port_str[6] = { 0 };
size_t range;
TSS2_RC rc = TSS2_RC_SUCCESS;

state.uri = &uri;
if (uriParseUriA (&state, conf) != URI_SUCCESS) {
LOG_WARNING ("Failed to parse provided conf string: %s", conf);
rc = TSS2_TCTI_RC_BAD_VALUE;
goto out;
}

/* extract host & domain name / fqdn */
range = uri.hostText.afterLast - uri.hostText.first;
if (range > HOST_NAME_MAX) {
LOG_WARNING ("Provided conf string has hostname that exceeds "
"HOST_NAME_MAX.");
rc = TSS2_TCTI_RC_BAD_VALUE;
goto out;
}
strncpy (hostname, uri.hostText.first, range);
mssim_conf_t *mssim_conf = (mssim_conf_t*)user_data;

/* extract port number */
range = uri.portText.afterLast - uri.portText.first;
if (range > 5) {
LOG_WARNING ("conf string contains invalid port.");
rc = TSS2_TCTI_RC_BAD_VALUE;
goto out;
} else if (range == 0) {
LOG_INFO ("conf string does not contain a port.");
goto out;
LOG_TRACE ("key_value: 0x%" PRIxPTR " and user_data: 0x%" PRIxPTR,
(uintptr_t)key_value, (uintptr_t)user_data);
if (key_value == NULL || user_data == NULL) {
LOG_WARNING ("%s passed NULL parameter", __func__);
return TSS2_TCTI_RC_GENERAL_FAILURE;
}

strncpy (port_str, uri.portText.first, range);
*port = string_to_port (port_str);
if (*port == 0) {
LOG_WARNING ("Provided conf string contains invalid port: 0");
rc = TSS2_TCTI_RC_BAD_VALUE;
goto out;
LOG_DEBUG ("key: %s / value: %s\n", key_value->key, key_value->value);
if (strcmp (key_value->key, "host") == 0) {
mssim_conf->host = key_value->value;
return TSS2_RC_SUCCESS;
} else if (strcmp (key_value->key, "port") == 0) {
mssim_conf->port = string_to_port (key_value->value);
if (mssim_conf->port == 0) {
return TSS2_TCTI_RC_BAD_VALUE;
}
return TSS2_RC_SUCCESS;
} else {
return TSS2_TCTI_RC_BAD_VALUE;
}
out:
uriFreeUriMembersA (&uri);
return rc;
}

void
tcti_mssim_init_context_data (
TSS2_TCTI_COMMON_CONTEXT *tcti_common)
Expand Down Expand Up @@ -548,12 +511,11 @@ Tss2_Tcti_Mssim_Init (
TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = (TSS2_TCTI_MSSIM_CONTEXT*)tctiContext;
TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_mssim_down_cast (tcti_mssim);
TSS2_RC rc;
const char *uri_str = conf != NULL ? conf : TCTI_SOCKET_DEFAULT_CONF;
char hostname[HOST_NAME_MAX + 1] = { 0 };
uint16_t port = TCTI_SOCKET_DEFAULT_PORT;
char *conf_copy = NULL;
mssim_conf_t mssim_conf = MSSIM_CONF_DEFAULT_INIT;

LOG_TRACE ("tctiContext: 0x%" PRIxPTR ", size: 0x%" PRIxPTR ", conf: %s",
(uintptr_t)tctiContext, (uintptr_t)size, uri_str);
(uintptr_t)tctiContext, (uintptr_t)size, conf);
if (size == NULL) {
return TSS2_TCTI_RC_BAD_VALUE;
}
Expand All @@ -562,17 +524,41 @@ Tss2_Tcti_Mssim_Init (
return TSS2_RC_SUCCESS;
}

rc = conf_str_to_host_port (uri_str, hostname, &port);
if (rc != TSS2_RC_SUCCESS) {
return rc;
if (conf != NULL) {
LOG_TRACE ("conf is not NULL");
if (strlen (conf) > TCTI_MSSIM_CONF_MAX) {
LOG_WARNING ("Provided conf string exceeds maximum of %u",
TCTI_MSSIM_CONF_MAX);
return TSS2_TCTI_RC_BAD_VALUE;
}
conf_copy = strdup (conf);
if (conf_copy == NULL) {
LOG_ERROR ("Failed to allocate buffer: %s", strerror (errno));
rc = TSS2_TCTI_RC_GENERAL_FAILURE;
goto fail_out;
}
LOG_DEBUG ("Dup'd conf string to: 0x%" PRIxPTR,
(uintptr_t)conf_copy);
rc = parse_key_value_string (conf_copy,
mssim_kv_callback,
&mssim_conf);
if (rc != TSS2_RC_SUCCESS) {
goto fail_out;
}
}
LOG_DEBUG ("Initializing mssim TCTI with host: %s, port: %" PRIu16,
mssim_conf.host, mssim_conf.port);

rc = socket_connect (hostname, port, &tcti_mssim->tpm_sock);
rc = socket_connect (mssim_conf.host,
mssim_conf.port,
&tcti_mssim->tpm_sock);
if (rc != TSS2_RC_SUCCESS) {
return rc;
goto fail_out;
}

rc = socket_connect (hostname, port + 1, &tcti_mssim->platform_sock);
rc = socket_connect (mssim_conf.host,
mssim_conf.port + 1,
&tcti_mssim->platform_sock);
if (rc != TSS2_RC_SUCCESS) {
goto fail_out;
}
Expand All @@ -583,22 +569,27 @@ Tss2_Tcti_Mssim_Init (
goto fail_out;
}

if (conf_copy != NULL) {
free (conf_copy);
}
return TSS2_RC_SUCCESS;

fail_out:
if (conf_copy != NULL) {
free (conf_copy);
}
socket_close (&tcti_mssim->tpm_sock);
socket_close (&tcti_mssim->platform_sock);

return TSS2_TCTI_RC_IO_ERROR;
return rc;
}

/* public info structure */
const TSS2_TCTI_INFO tss2_tcti_info = {
.version = TCTI_VERSION,
.name = "tcti-socket",
.description = "TCTI module for communication with the Microsoft TPM2 Simulator.",
.config_help = "Connection URI in the form tcp://ip_address[:port]. " \
"Default is: TCTI_SOCKET_DEFAULT.",
.config_help = "Key / value string in the form \"host=localhost,port=2321\".",
.init = Tss2_Tcti_Mssim_Init,
};

Expand Down
19 changes: 19 additions & 0 deletions src/tss2-tcti/tcti-mssim.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,30 @@
#ifndef TCTI_MSSIM_H
#define TCTI_MSSIM_H

#include <limits.h>

#include "tcti-common.h"
#include "util/io.h"

/*
* longest possible conf string:
* HOST_NAME_MAX + max char uint16 (5) + strlen ("host=,port=") (11)
*/
#define TCTI_MSSIM_CONF_MAX (HOST_NAME_MAX + 16)
#define TCTI_MSSIM_DEFAULT_HOST "localhost"
#define TCTI_MSSIM_DEFAULT_PORT 2321
#define MSSIM_CONF_DEFAULT_INIT { \
.host = TCTI_MSSIM_DEFAULT_HOST, \
.port = TCTI_MSSIM_DEFAULT_PORT, \
}

#define TCTI_MSSIM_MAGIC 0xf05b04cd9f02728dULL

typedef struct {
char *host;
uint16_t port;
} mssim_conf_t;

typedef struct {
TSS2_TCTI_COMMON_CONTEXT common;
SOCKET platform_sock;
Expand Down
Loading

0 comments on commit e394cff

Please sign in to comment.