From 889c7531c96bb28c18d4f12d310bc749d4b48202 Mon Sep 17 00:00:00 2001 From: Elms Date: Wed, 9 Mar 2022 12:49:51 -0800 Subject: [PATCH 1/5] tpm: mqtt example Uses mosquitto to demonstrate --- tpm/mqtt/Makefile | 3 + tpm/mqtt/README | 14 + tpm/mqtt/build.sh | 35 ++ tpm/mqtt/mosquitto.conf | 1000 ++++++++++++++++++++++++++++++++++++ tpm/mqtt/mqtt_tpm_simple.c | 796 ++++++++++++++++++++++++++++ tpm/mqtt/run.sh | 94 ++++ 6 files changed, 1942 insertions(+) create mode 100644 tpm/mqtt/Makefile create mode 100644 tpm/mqtt/README create mode 100755 tpm/mqtt/build.sh create mode 100644 tpm/mqtt/mosquitto.conf create mode 100644 tpm/mqtt/mqtt_tpm_simple.c create mode 100755 tpm/mqtt/run.sh diff --git a/tpm/mqtt/Makefile b/tpm/mqtt/Makefile new file mode 100644 index 00000000..049ac293 --- /dev/null +++ b/tpm/mqtt/Makefile @@ -0,0 +1,3 @@ + +mqtt_tpm_simple: mqtt_tpm_simple.c + gcc $^ -g -o $@ -I inst/include -L inst/lib -lwolfssl -lwolftpm -lwolfmqtt diff --git a/tpm/mqtt/README b/tpm/mqtt/README new file mode 100644 index 00000000..0fb436bb --- /dev/null +++ b/tpm/mqtt/README @@ -0,0 +1,14 @@ +## network callback + +## TPM certificate + + +## crypto callback + +## check if key is valid + + +### mosquitto TLS example +`mosquitto -c mosquitto.conf` +`mosquitto_sub -d -p 18883 -t blah --cafile certs/ca-cert.pem -h 127.0.0.1` +`mosquitto_pub -d -p 18883 -t blah --cafile certs/ca-cert.pem -h 127.0.0.1 -m hola` diff --git a/tpm/mqtt/build.sh b/tpm/mqtt/build.sh new file mode 100755 index 00000000..5686fd31 --- /dev/null +++ b/tpm/mqtt/build.sh @@ -0,0 +1,35 @@ +#!/usr/bin/bash + +set -e + +REPO_DIR=../../.. +INST_DIR=$(dirname $(realpath $0))/inst + +if [ "$1" != "" ]; then + REPO_DIR=$1 +fi + +if [ "$2" != "" ]; then + INST_DIR=$2 +fi + +echo "Building wolfSSL with prefix $INST_DIR" +pushd ${REPO_DIR}/wolfssl +./autogen.sh +./configure --prefix=$INST_DIR --enable-wolftpm --enable-debug +make install +popd + +echo "Building wolfTPM with prefix $INST_DIR" +pushd ${REPO_DIR}/wolftpm +./autogen.sh +./configure --prefix=$INST_DIR --enable-swtpm --enable-debug +make install +popd + +echo "Building wolfMQTT with prefix $INST_DIR" +pushd ${REPO_DIR}/wolfmqtt +./autogen.sh +./configure --prefix=$INST_DIR --enable-debug +make install +popd diff --git a/tpm/mqtt/mosquitto.conf b/tpm/mqtt/mosquitto.conf new file mode 100644 index 00000000..a2aa968b --- /dev/null +++ b/tpm/mqtt/mosquitto.conf @@ -0,0 +1,1000 @@ +# Config file for mosquitto +# +# See mosquitto.conf(5) for more information. +# +# Default values are shown, uncomment to change. +# +# Use the # character to indicate a comment, but only if it is the +# very first character on the line. + +# ================================================================= +# General configuration +# ================================================================= + +# Use per listener security settings. +# +# It is recommended this option be set before any other options. +# +# If this option is set to true, then all authentication and access control +# options are controlled on a per listener basis. The following options are +# affected: +# +# password_file acl_file psk_file auth_plugin auth_opt_* allow_anonymous +# auto_id_prefix allow_zero_length_clientid +# +# Note that if set to true, then a durable client (i.e. with clean session set +# to false) that has disconnected will use the ACL settings defined for the +# listener that it was most recently connected to. +# +# The default behaviour is for this to be set to false, which maintains the +# setting behaviour from previous versions of mosquitto. +#per_listener_settings false + + +# If a client is subscribed to multiple subscriptions that overlap, e.g. foo/# +# and foo/+/baz , then MQTT expects that when the broker receives a message on +# a topic that matches both subscriptions, such as foo/bar/baz, then the client +# should only receive the message once. +# Mosquitto keeps track of which clients a message has been sent to in order to +# meet this requirement. The allow_duplicate_messages option allows this +# behaviour to be disabled, which may be useful if you have a large number of +# clients subscribed to the same set of topics and are very concerned about +# minimising memory usage. +# It can be safely set to true if you know in advance that your clients will +# never have overlapping subscriptions, otherwise your clients must be able to +# correctly deal with duplicate messages even when then have QoS=2. +#allow_duplicate_messages false + +# This option controls whether a client is allowed to connect with a zero +# length client id or not. This option only affects clients using MQTT v3.1.1 +# and later. If set to false, clients connecting with a zero length client id +# are disconnected. If set to true, clients will be allocated a client id by +# the broker. This means it is only useful for clients with clean session set +# to true. +#allow_zero_length_clientid true + +# If allow_zero_length_clientid is true, this option allows you to set a prefix +# to automatically generated client ids to aid visibility in logs. +# Defaults to 'auto-' +#auto_id_prefix auto- + +# This option affects the scenario when a client subscribes to a topic that has +# retained messages. It is possible that the client that published the retained +# message to the topic had access at the time they published, but that access +# has been subsequently removed. If check_retain_source is set to true, the +# default, the source of a retained message will be checked for access rights +# before it is republished. When set to false, no check will be made and the +# retained message will always be published. This affects all listeners. +#check_retain_source true + +# QoS 1 and 2 messages will be allowed inflight per client until this limit +# is exceeded. Defaults to 0. (No maximum) +# See also max_inflight_messages +#max_inflight_bytes 0 + +# The maximum number of QoS 1 and 2 messages currently inflight per +# client. +# This includes messages that are partway through handshakes and +# those that are being retried. Defaults to 20. Set to 0 for no +# maximum. Setting to 1 will guarantee in-order delivery of QoS 1 +# and 2 messages. +#max_inflight_messages 20 + +# For MQTT v5 clients, it is possible to have the server send a "server +# keepalive" value that will override the keepalive value set by the client. +# This is intended to be used as a mechanism to say that the server will +# disconnect the client earlier than it anticipated, and that the client should +# use the new keepalive value. The max_keepalive option allows you to specify +# that clients may only connect with keepalive less than or equal to this +# value, otherwise they will be sent a server keepalive telling them to use +# max_keepalive. This only applies to MQTT v5 clients. The maximum value +# allowable is 65535. Do not set below 10. +#max_keepalive 65535 + +# For MQTT v5 clients, it is possible to have the server send a "maximum packet +# size" value that will instruct the client it will not accept MQTT packets +# with size greater than max_packet_size bytes. This applies to the full MQTT +# packet, not just the payload. Setting this option to a positive value will +# set the maximum packet size to that number of bytes. If a client sends a +# packet which is larger than this value, it will be disconnected. This applies +# to all clients regardless of the protocol version they are using, but v3.1.1 +# and earlier clients will of course not have received the maximum packet size +# information. Defaults to no limit. Setting below 20 bytes is forbidden +# because it is likely to interfere with ordinary client operation, even with +# very small payloads. +#max_packet_size 0 + +# QoS 1 and 2 messages above those currently in-flight will be queued per +# client until this limit is exceeded. Defaults to 0. (No maximum) +# See also max_queued_messages. +# If both max_queued_messages and max_queued_bytes are specified, packets will +# be queued until the first limit is reached. +#max_queued_bytes 0 + +# The maximum number of QoS 1 and 2 messages to hold in a queue per client +# above those that are currently in-flight. Defaults to 100. Set +# to 0 for no maximum (not recommended). +# See also queue_qos0_messages. +# See also max_queued_bytes. +#max_queued_messages 100 +# +# This option sets the maximum number of heap memory bytes that the broker will +# allocate, and hence sets a hard limit on memory use by the broker. Memory +# requests that exceed this value will be denied. The effect will vary +# depending on what has been denied. If an incoming message is being processed, +# then the message will be dropped and the publishing client will be +# disconnected. If an outgoing message is being sent, then the individual +# message will be dropped and the receiving client will be disconnected. +# Defaults to no limit. +#memory_limit 0 + +# This option sets the maximum publish payload size that the broker will allow. +# Received messages that exceed this size will not be accepted by the broker. +# The default value is 0, which means that all valid MQTT messages are +# accepted. MQTT imposes a maximum payload size of 268435455 bytes. +#message_size_limit 0 + +# This option allows persistent clients (those with clean session set to false) +# to be removed if they do not reconnect within a certain time frame. +# +# This is a non-standard option in MQTT V3.1 but allowed in MQTT v3.1.1. +# +# Badly designed clients may set clean session to false whilst using a randomly +# generated client id. This leads to persistent clients that will never +# reconnect. This option allows these clients to be removed. +# +# The expiration period should be an integer followed by one of h d w m y for +# hour, day, week, month and year respectively. For example +# +# persistent_client_expiration 2m +# persistent_client_expiration 14d +# persistent_client_expiration 1y +# +# The default if not set is to never expire persistent clients. +#persistent_client_expiration + +# Write process id to a file. Default is a blank string which means +# a pid file shouldn't be written. +# This should be set to /var/run/mosquitto.pid if mosquitto is +# being run automatically on boot with an init script and +# start-stop-daemon or similar. +#pid_file + +# Set to true to queue messages with QoS 0 when a persistent client is +# disconnected. These messages are included in the limit imposed by +# max_queued_messages and max_queued_bytes +# Defaults to false. +# This is a non-standard option for the MQTT v3.1 spec but is allowed in +# v3.1.1. +#queue_qos0_messages false + +# Set to false to disable retained message support. If a client publishes a +# message with the retain bit set, it will be disconnected if this is set to +# false. +#retain_available true + +# Disable Nagle's algorithm on client sockets. This has the effect of reducing +# latency of individual messages at the potential cost of increasing the number +# of packets being sent. +#set_tcp_nodelay false + +# Time in seconds between updates of the $SYS tree. +# Set to 0 to disable the publishing of the $SYS tree. +#sys_interval 10 + +# The MQTT specification requires that the QoS of a message delivered to a +# subscriber is never upgraded to match the QoS of the subscription. Enabling +# this option changes this behaviour. If upgrade_outgoing_qos is set true, +# messages sent to a subscriber will always match the QoS of its subscription. +# This is a non-standard option explicitly disallowed by the spec. +#upgrade_outgoing_qos false + +# When run as root, drop privileges to this user and its primary +# group. +# Set to root to stay as root, but this is not recommended. +# If run as a non-root user, this setting has no effect. +# Note that on Windows this has no effect and so mosquitto should +# be started by the user you wish it to run as. +#user mosquitto + +# ================================================================= +# Default listener +# ================================================================= + +# IP address/hostname to bind the default listener to. If not +# given, the default listener will not be bound to a specific +# address and so will be accessible to all network interfaces. +# bind_address ip-address/host name +#bind_address + + +# Port to use for the default listener. +#port 1883 +port 18883 + +# Bind the listener to a specific interface. This is similar to +# bind_address above but is useful when an interface has multiple addresses or +# the address may change. It is valid to use this with the bind_address option, +# but take care that the interface you are binding to contains the address you +# are binding to, otherwise you will not be able to connect. +# Example: bind_interface eth0 +bind_interface lo + +# When a listener is using the websockets protocol, it is possible to serve +# http data as well. Set http_dir to a directory which contains the files you +# wish to serve. If this option is not specified, then no normal http +# connections will be possible. +#http_dir + +# The maximum number of client connections to allow. This is +# a per listener setting. +# Default is -1, which means unlimited connections. +# Note that other process limits mean that unlimited connections +# are not really possible. Typically the default maximum number of +# connections possible is around 1024. +#max_connections -1 + +# Choose the protocol to use when listening. +# This can be either mqtt or websockets. +# Websockets support is currently disabled by default at compile time. +# Certificate based TLS may be used with websockets, except that +# only the cafile, certfile, keyfile and ciphers options are supported. +#protocol mqtt + +# Set use_username_as_clientid to true to replace the clientid that a client +# connected with with its username. This allows authentication to be tied to +# the clientid, which means that it is possible to prevent one client +# disconnecting another by using the same clientid. +# If a client connects with no username it will be disconnected as not +# authorised when this option is set to true. +# Do not use in conjunction with clientid_prefixes. +# See also use_identity_as_username. +#use_username_as_clientid + +# ----------------------------------------------------------------- +# Certificate based SSL/TLS support +# ----------------------------------------------------------------- +# The following options can be used to enable SSL/TLS support for +# this listener. Note that the recommended port for MQTT over TLS +# is 8883, but this must be set manually. +# +# See also the mosquitto-tls man page. + +# At least one of cafile or capath must be defined. They both +# define methods of accessing the PEM encoded Certificate +# Authority certificates that have signed your server certificate +# and that you wish to trust. +# cafile defines the path to a file containing the CA certificates. +# capath defines a directory that will be searched for files +# containing the CA certificates. For capath to work correctly, the +# certificate files must have ".crt" as the file ending and you must run +# "openssl rehash " each time you add/remove a certificate. +#cafile +#capath +#cafile tmp_certs_and_keys/ca-cert.pem +#cafile /work/wolf/wolfssl/certs/client-cert.pem +#capath tmp_certs_and_keys +#cafile tmp_certs_and_keys/ca-rsa-cert.pem +cafile tmp_certs_and_keys/ca-list.pem + +# Path to the PEM encoded server certificate. +#certfile +certfile tmp_certs_and_keys/server-cert.pem + +# Path to the PEM encoded keyfile. +#keyfile +keyfile tmp_certs_and_keys/server-key.pem + + +# If you have require_certificate set to true, you can create a certificate +# revocation list file to revoke access to particular client certificates. If +# you have done this, use crlfile to point to the PEM encoded revocation file. +#crlfile + +# If you wish to control which encryption ciphers are used, use the ciphers +# option. The list of available ciphers can be obtained using the "openssl +# ciphers" command and should be provided in the same format as the output of +# that command. +# If unset defaults to DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH +#ciphers DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH + +# To allow the use of ephemeral DH key exchange, which provides forward +# security, the listener must load DH parameters. This can be specified with +# the dhparamfile option. The dhparamfile can be generated with the command +# e.g. "openssl dhparam -out dhparam.pem 2048" +#dhparamfile + +# By default a TLS enabled listener will operate in a similar fashion to a +# https enabled web server, in that the server has a certificate signed by a CA +# and the client will verify that it is a trusted certificate. The overall aim +# is encryption of the network traffic. By setting require_certificate to true, +# the client must provide a valid certificate in order for the network +# connection to proceed. This allows access to the broker to be controlled +# outside of the mechanisms provided by MQTT. +#require_certificate false +require_certificate true + +# This option defines the version of the TLS protocol to use for this listener. +# The default value allows all of v1.3, v1.2 and v1.1. The valid values are +# tlsv1.3 tlsv1.2 and tlsv1.1. +#tls_version +tls_version tlsv1.2 + +# If require_certificate is true, you may set use_identity_as_username to true +# to use the CN value from the client certificate as a username. If this is +# true, the password_file option will not be used for this listener. +# This takes priority over use_subject_as_username. +# See also use_subject_as_username. +#use_identity_as_username false + +# If require_certificate is true, you may set use_subject_as_username to true +# to use the complete subject value from the client certificate as a username. +# If this is true, the password_file option will not be used for this listener. +# See also use_identity_as_username +#use_subject_as_username false + +# ----------------------------------------------------------------- +# Pre-shared-key based SSL/TLS support +# ----------------------------------------------------------------- +# The following options can be used to enable PSK based SSL/TLS support for +# this listener. Note that the recommended port for MQTT over TLS is 8883, but +# this must be set manually. +# +# See also the mosquitto-tls man page and the "Certificate based SSL/TLS +# support" section. Only one of certificate or PSK encryption support can be +# enabled for any listener. + +# The psk_hint option enables pre-shared-key support for this listener and also +# acts as an identifier for this listener. The hint is sent to clients and may +# be used locally to aid authentication. The hint is a free form string that +# doesn't have much meaning in itself, so feel free to be creative. +# If this option is provided, see psk_file to define the pre-shared keys to be +# used or create a security plugin to handle them. +#psk_hint + +# When using PSK, the encryption ciphers used will be chosen from the list of +# available PSK ciphers. If you want to control which ciphers are available, +# use the "ciphers" option. The list of available ciphers can be obtained +# using the "openssl ciphers" command and should be provided in the same format +# as the output of that command. +#ciphers + +# Set use_identity_as_username to have the psk identity sent by the client used +# as its username. Authentication will be carried out using the PSK rather than +# the MQTT username/password and so password_file will not be used for this +# listener. +#use_identity_as_username false + + +# ================================================================= +# Extra listeners +# ================================================================= + +# Listen on a port/ip address combination. By using this variable +# multiple times, mosquitto can listen on more than one port. If +# this variable is used and neither bind_address nor port given, +# then the default listener will not be started. +# The port number to listen on must be given. Optionally, an ip +# address or host name may be supplied as a second argument. In +# this case, mosquitto will attempt to bind the listener to that +# address and so restrict access to the associated network and +# interface. By default, mosquitto will listen on all interfaces. +# Note that for a websockets listener it is not possible to bind to a host +# name. +# listener port-number [ip address/host name] +#listener + +# Bind the listener to a specific interface. This is similar to +# the [ip address/host name] part of the listener definition, but is useful +# when an interface has multiple addresses or the address may change. It is +# valid to use this with the [ip address/host name] part of the listener +# definition, but take care that the interface you are binding to contains the +# address you are binding to, otherwise you will not be able to connect. +# Only available on Linux and requires elevated privileges. +# +# Example: bind_interface eth0 +#bind_interface + +# When a listener is using the websockets protocol, it is possible to serve +# http data as well. Set http_dir to a directory which contains the files you +# wish to serve. If this option is not specified, then no normal http +# connections will be possible. +#http_dir + +# The maximum number of client connections to allow. This is +# a per listener setting. +# Default is -1, which means unlimited connections. +# Note that other process limits mean that unlimited connections +# are not really possible. Typically the default maximum number of +# connections possible is around 1024. +#max_connections -1 + +# The listener can be restricted to operating within a topic hierarchy using +# the mount_point option. This is achieved be prefixing the mount_point string +# to all topics for any clients connected to this listener. This prefixing only +# happens internally to the broker; the client will not see the prefix. +#mount_point + +# Choose the protocol to use when listening. +# This can be either mqtt or websockets. +# Certificate based TLS may be used with websockets, except that only the +# cafile, certfile, keyfile and ciphers options are supported. +#protocol mqtt + +# Set use_username_as_clientid to true to replace the clientid that a client +# connected with with its username. This allows authentication to be tied to +# the clientid, which means that it is possible to prevent one client +# disconnecting another by using the same clientid. +# If a client connects with no username it will be disconnected as not +# authorised when this option is set to true. +# Do not use in conjunction with clientid_prefixes. +# See also use_identity_as_username. +#use_username_as_clientid + +# Change the websockets headers size. This is a global option, it is not +# possible to set per listener. This option sets the size of the buffer used in +# the libwebsockets library when reading HTTP headers. If you are passing large +# header data such as cookies then you may need to increase this value. If left +# unset, or set to 0, then the default of 1024 bytes will be used. +#websockets_headers_size + +# ----------------------------------------------------------------- +# Certificate based SSL/TLS support +# ----------------------------------------------------------------- +# The following options can be used to enable certificate based SSL/TLS support +# for this listener. Note that the recommended port for MQTT over TLS is 8883, +# but this must be set manually. +# +# See also the mosquitto-tls man page and the "Pre-shared-key based SSL/TLS +# support" section. Only one of certificate or PSK encryption support can be +# enabled for any listener. + +# At least one of cafile or capath must be defined to enable certificate based +# TLS encryption. They both define methods of accessing the PEM encoded +# Certificate Authority certificates that have signed your server certificate +# and that you wish to trust. +# cafile defines the path to a file containing the CA certificates. +# capath defines a directory that will be searched for files +# containing the CA certificates. For capath to work correctly, the +# certificate files must have ".crt" as the file ending and you must run +# "openssl rehash " each time you add/remove a certificate. +#cafile +#capath + +# Path to the PEM encoded server certificate. +#certfile + +# Path to the PEM encoded keyfile. +#keyfile + + +# If you wish to control which encryption ciphers are used, use the ciphers +# option. The list of available ciphers can be optained using the "openssl +# ciphers" command and should be provided in the same format as the output of +# that command. +#ciphers + +# If you have require_certificate set to true, you can create a certificate +# revocation list file to revoke access to particular client certificates. If +# you have done this, use crlfile to point to the PEM encoded revocation file. +#crlfile + +# To allow the use of ephemeral DH key exchange, which provides forward +# security, the listener must load DH parameters. This can be specified with +# the dhparamfile option. The dhparamfile can be generated with the command +# e.g. "openssl dhparam -out dhparam.pem 2048" +#dhparamfile + +# By default an TLS enabled listener will operate in a similar fashion to a +# https enabled web server, in that the server has a certificate signed by a CA +# and the client will verify that it is a trusted certificate. The overall aim +# is encryption of the network traffic. By setting require_certificate to true, +# the client must provide a valid certificate in order for the network +# connection to proceed. This allows access to the broker to be controlled +# outside of the mechanisms provided by MQTT. +#require_certificate false + +# If require_certificate is true, you may set use_identity_as_username to true +# to use the CN value from the client certificate as a username. If this is +# true, the password_file option will not be used for this listener. +#use_identity_as_username false + +# ----------------------------------------------------------------- +# Pre-shared-key based SSL/TLS support +# ----------------------------------------------------------------- +# The following options can be used to enable PSK based SSL/TLS support for +# this listener. Note that the recommended port for MQTT over TLS is 8883, but +# this must be set manually. +# +# See also the mosquitto-tls man page and the "Certificate based SSL/TLS +# support" section. Only one of certificate or PSK encryption support can be +# enabled for any listener. + +# The psk_hint option enables pre-shared-key support for this listener and also +# acts as an identifier for this listener. The hint is sent to clients and may +# be used locally to aid authentication. The hint is a free form string that +# doesn't have much meaning in itself, so feel free to be creative. +# If this option is provided, see psk_file to define the pre-shared keys to be +# used or create a security plugin to handle them. +#psk_hint + +# When using PSK, the encryption ciphers used will be chosen from the list of +# available PSK ciphers. If you want to control which ciphers are available, +# use the "ciphers" option. The list of available ciphers can be optained +# using the "openssl ciphers" command and should be provided in the same format +# as the output of that command. +#ciphers + +# Set use_identity_as_username to have the psk identity sent by the client used +# as its username. Authentication will be carried out using the PSK rather than +# the MQTT username/password and so password_file will not be used for this +# listener. +#use_identity_as_username false + + +# ================================================================= +# Persistence +# ================================================================= + +# If persistence is enabled, save the in-memory database to disk +# every autosave_interval seconds. If set to 0, the persistence +# database will only be written when mosquitto exits. See also +# autosave_on_changes. +# Note that writing of the persistence database can be forced by +# sending mosquitto a SIGUSR1 signal. +#autosave_interval 1800 + +# If true, mosquitto will count the number of subscription changes, retained +# messages received and queued messages and if the total exceeds +# autosave_interval then the in-memory database will be saved to disk. +# If false, mosquitto will save the in-memory database to disk by treating +# autosave_interval as a time in seconds. +#autosave_on_changes false + +# Save persistent message data to disk (true/false). +# This saves information about all messages, including +# subscriptions, currently in-flight messages and retained +# messages. +# retained_persistence is a synonym for this option. +#persistence false + +# The filename to use for the persistent database, not including +# the path. +#persistence_file mosquitto.db + +# Location for persistent database. Must include trailing / +# Default is an empty string (current directory). +# Set to e.g. /var/lib/mosquitto/ if running as a proper service on Linux or +# similar. +#persistence_location + + +# ================================================================= +# Logging +# ================================================================= + +# Places to log to. Use multiple log_dest lines for multiple +# logging destinations. +# Possible destinations are: stdout stderr syslog topic file +# +# stdout and stderr log to the console on the named output. +# +# syslog uses the userspace syslog facility which usually ends up +# in /var/log/messages or similar. +# +# topic logs to the broker topic '$SYS/broker/log/', +# where severity is one of D, E, W, N, I, M which are debug, error, +# warning, notice, information and message. Message type severity is used by +# the subscribe/unsubscribe log_types and publishes log messages to +# $SYS/broker/log/M/susbcribe or $SYS/broker/log/M/unsubscribe. +# +# The file destination requires an additional parameter which is the file to be +# logged to, e.g. "log_dest file /var/log/mosquitto.log". The file will be +# closed and reopened when the broker receives a HUP signal. Only a single file +# destination may be configured. +# +# Note that if the broker is running as a Windows service it will default to +# "log_dest none" and neither stdout nor stderr logging is available. +# Use "log_dest none" if you wish to disable logging. +#log_dest stderr +log_dest stderr + +# Types of messages to log. Use multiple log_type lines for logging +# multiple types of messages. +# Possible types are: debug, error, warning, notice, information, +# none, subscribe, unsubscribe, websockets, all. +# Note that debug type messages are for decoding the incoming/outgoing +# network packets. They are not logged in "topics". +log_type error +log_type warning +log_type notice +log_type information + + +# If set to true, client connection and disconnection messages will be included +# in the log. +#connection_messages true + +# If using syslog logging (not on Windows), messages will be logged to the +# "daemon" facility by default. Use the log_facility option to choose which of +# local0 to local7 to log to instead. The option value should be an integer +# value, e.g. "log_facility 5" to use local5. +#log_facility + +# If set to true, add a timestamp value to each log message. +#log_timestamp true + +# Set the format of the log timestamp. If left unset, this is the number of +# seconds since the Unix epoch. +# This is a free text string which will be passed to the strftime function. To +# get an ISO 8601 datetime, for example: +# log_timestamp_format %Y-%m-%dT%H:%M:%S +#log_timestamp_format + +# Change the websockets logging level. This is a global option, it is not +# possible to set per listener. This is an integer that is interpreted by +# libwebsockets as a bit mask for its lws_log_levels enum. See the +# libwebsockets documentation for more details. "log_type websockets" must also +# be enabled. +#websockets_log_level 0 + + +# ================================================================= +# Security +# ================================================================= + +# If set, only clients that have a matching prefix on their +# clientid will be allowed to connect to the broker. By default, +# all clients may connect. +# For example, setting "secure-" here would mean a client "secure- +# client" could connect but another with clientid "mqtt" couldn't. +#clientid_prefixes + +# Boolean value that determines whether clients that connect +# without providing a username are allowed to connect. If set to +# false then a password file should be created (see the +# password_file option) to control authenticated client access. +# +# Defaults to true if no other security options are set. If `password_file` or +# `psk_file` is set, or if an authentication plugin is loaded which implements +# username/password or TLS-PSK checks, then `allow_anonymous` defaults to +# false. +# +#allow_anonymous true + +# ----------------------------------------------------------------- +# Default authentication and topic access control +# ----------------------------------------------------------------- + +# Control access to the broker using a password file. This file can be +# generated using the mosquitto_passwd utility. If TLS support is not compiled +# into mosquitto (it is recommended that TLS support should be included) then +# plain text passwords are used, in which case the file should be a text file +# with lines in the format: +# username:password +# The password (and colon) may be omitted if desired, although this +# offers very little in the way of security. +# +# See the TLS client require_certificate and use_identity_as_username options +# for alternative authentication options. If an auth_plugin is used as well as +# password_file, the auth_plugin check will be made first. +#password_file + +# Access may also be controlled using a pre-shared-key file. This requires +# TLS-PSK support and a listener configured to use it. The file should be text +# lines in the format: +# identity:key +# The key should be in hexadecimal format without a leading "0x". +# If an auth_plugin is used as well, the auth_plugin check will be made first. +#psk_file + +# Control access to topics on the broker using an access control list +# file. If this parameter is defined then only the topics listed will +# have access. +# If the first character of a line of the ACL file is a # it is treated as a +# comment. +# Topic access is added with lines of the format: +# +# topic [read|write|readwrite] +# +# The access type is controlled using "read", "write" or "readwrite". This +# parameter is optional (unless contains a space character) - if not +# given then the access is read/write. can contain the + or # +# wildcards as in subscriptions. +# +# The first set of topics are applied to anonymous clients, assuming +# allow_anonymous is true. User specific topic ACLs are added after a +# user line as follows: +# +# user +# +# The username referred to here is the same as in password_file. It is +# not the clientid. +# +# +# If is also possible to define ACLs based on pattern substitution within the +# topic. The patterns available for substition are: +# +# %c to match the client id of the client +# %u to match the username of the client +# +# The substitution pattern must be the only text for that level of hierarchy. +# +# The form is the same as for the topic keyword, but using pattern as the +# keyword. +# Pattern ACLs apply to all users even if the "user" keyword has previously +# been given. +# +# If using bridges with usernames and ACLs, connection messages can be allowed +# with the following pattern: +# pattern write $SYS/broker/connection/%c/state +# +# pattern [read|write|readwrite] +# +# Example: +# +# pattern write sensor/%u/data +# +# If an auth_plugin is used as well as acl_file, the auth_plugin check will be +# made first. +#acl_file + +# ----------------------------------------------------------------- +# External authentication and topic access plugin options +# ----------------------------------------------------------------- + +# External authentication and access control can be supported with the +# auth_plugin option. This is a path to a loadable plugin. See also the +# auth_opt_* options described below. +# +# The auth_plugin option can be specified multiple times to load multiple +# plugins. The plugins will be processed in the order that they are specified +# here. If the auth_plugin option is specified alongside either of +# password_file or acl_file then the plugin checks will be made first. +# +#auth_plugin + +# If the auth_plugin option above is used, define options to pass to the +# plugin here as described by the plugin instructions. All options named +# using the format auth_opt_* will be passed to the plugin, for example: +# +# auth_opt_db_host +# auth_opt_db_port +# auth_opt_db_username +# auth_opt_db_password + + +# ================================================================= +# Bridges +# ================================================================= + +# A bridge is a way of connecting multiple MQTT brokers together. +# Create a new bridge using the "connection" option as described below. Set +# options for the bridges using the remaining parameters. You must specify the +# address and at least one topic to subscribe to. +# +# Each connection must have a unique name. +# +# The address line may have multiple host address and ports specified. See +# below in the round_robin description for more details on bridge behaviour if +# multiple addresses are used. Note that if you use an IPv6 address, then you +# are required to specify a port. +# +# The direction that the topic will be shared can be chosen by +# specifying out, in or both, where the default value is out. +# The QoS level of the bridged communication can be specified with the next +# topic option. The default QoS level is 0, to change the QoS the topic +# direction must also be given. +# +# The local and remote prefix options allow a topic to be remapped when it is +# bridged to/from the remote broker. This provides the ability to place a topic +# tree in an appropriate location. +# +# For more details see the mosquitto.conf man page. +# +# Multiple topics can be specified per connection, but be careful +# not to create any loops. +# +# If you are using bridges with cleansession set to false (the default), then +# you may get unexpected behaviour from incoming topics if you change what +# topics you are subscribing to. This is because the remote broker keeps the +# subscription for the old topic. If you have this problem, connect your bridge +# with cleansession set to true, then reconnect with cleansession set to false +# as normal. +#connection +#address [:] [[:]] +#topic [[[out | in | both] qos-level] local-prefix remote-prefix] + + +# If a bridge has topics that have "out" direction, the default behaviour is to +# send an unsubscribe request to the remote broker on that topic. This means +# that changing a topic direction from "in" to "out" will not keep receiving +# incoming messages. Sending these unsubscribe requests is not always +# desirable, setting bridge_attempt_unsubscribe to false will disable sending +# the unsubscribe request. +#bridge_attempt_unsubscribe true + +# Set the version of the MQTT protocol to use with for this bridge. Can be one +# of mqttv311 or mqttv11. Defaults to mqttv311. +#bridge_protocol_version mqttv311 + +# Set the clean session variable for this bridge. +# When set to true, when the bridge disconnects for any reason, all +# messages and subscriptions will be cleaned up on the remote +# broker. Note that with cleansession set to true, there may be a +# significant amount of retained messages sent when the bridge +# reconnects after losing its connection. +# When set to false, the subscriptions and messages are kept on the +# remote broker, and delivered when the bridge reconnects. +#cleansession false + +# Set the amount of time a bridge using the lazy start type must be idle before +# it will be stopped. Defaults to 60 seconds. +#idle_timeout 60 + +# Set the keepalive interval for this bridge connection, in +# seconds. +#keepalive_interval 60 + +# Set the clientid to use on the local broker. If not defined, this defaults to +# 'local.'. If you are bridging a broker to itself, it is important +# that local_clientid and clientid do not match. +#local_clientid + +# If set to true, publish notification messages to the local and remote brokers +# giving information about the state of the bridge connection. Retained +# messages are published to the topic $SYS/broker/connection//state +# unless the notification_topic option is used. +# If the message is 1 then the connection is active, or 0 if the connection has +# failed. +# This uses the last will and testament feature. +#notifications true + +# Choose the topic on which notification messages for this bridge are +# published. If not set, messages are published on the topic +# $SYS/broker/connection//state +#notification_topic + +# Set the client id to use on the remote end of this bridge connection. If not +# defined, this defaults to 'name.hostname' where name is the connection name +# and hostname is the hostname of this computer. +# This replaces the old "clientid" option to avoid confusion. "clientid" +# remains valid for the time being. +#remote_clientid + +# Set the password to use when connecting to a broker that requires +# authentication. This option is only used if remote_username is also set. +# This replaces the old "password" option to avoid confusion. "password" +# remains valid for the time being. +#remote_password + +# Set the username to use when connecting to a broker that requires +# authentication. +# This replaces the old "username" option to avoid confusion. "username" +# remains valid for the time being. +#remote_username + +# Set the amount of time a bridge using the automatic start type will wait +# until attempting to reconnect. +# This option can be configured to use a constant delay time in seconds, or to +# use a backoff mechanism based on "Decorrelated Jitter", which adds a degree +# of randomness to when the restart occurs. +# +# Set a constant timeout of 20 seconds: +# restart_timeout 20 +# +# Set backoff with a base (start value) of 10 seconds and a cap (upper limit) of +# 60 seconds: +# restart_timeout 10 30 +# +# Defaults to jitter with a base of 5 and cap of 30 +#restart_timeout 5 30 + +# If the bridge has more than one address given in the address/addresses +# configuration, the round_robin option defines the behaviour of the bridge on +# a failure of the bridge connection. If round_robin is false, the default +# value, then the first address is treated as the main bridge connection. If +# the connection fails, the other secondary addresses will be attempted in +# turn. Whilst connected to a secondary bridge, the bridge will periodically +# attempt to reconnect to the main bridge until successful. +# If round_robin is true, then all addresses are treated as equals. If a +# connection fails, the next address will be tried and if successful will +# remain connected until it fails +#round_robin false + +# Set the start type of the bridge. This controls how the bridge starts and +# can be one of three types: automatic, lazy and once. Note that RSMB provides +# a fourth start type "manual" which isn't currently supported by mosquitto. +# +# "automatic" is the default start type and means that the bridge connection +# will be started automatically when the broker starts and also restarted +# after a short delay (30 seconds) if the connection fails. +# +# Bridges using the "lazy" start type will be started automatically when the +# number of queued messages exceeds the number set with the "threshold" +# parameter. It will be stopped automatically after the time set by the +# "idle_timeout" parameter. Use this start type if you wish the connection to +# only be active when it is needed. +# +# A bridge using the "once" start type will be started automatically when the +# broker starts but will not be restarted if the connection fails. +#start_type automatic + +# Set the number of messages that need to be queued for a bridge with lazy +# start type to be restarted. Defaults to 10 messages. +# Must be less than max_queued_messages. +#threshold 10 + +# If try_private is set to true, the bridge will attempt to indicate to the +# remote broker that it is a bridge not an ordinary client. If successful, this +# means that loop detection will be more effective and that retained messages +# will be propagated correctly. Not all brokers support this feature so it may +# be necessary to set try_private to false if your bridge does not connect +# properly. +#try_private true + +# ----------------------------------------------------------------- +# Certificate based SSL/TLS support +# ----------------------------------------------------------------- +# Either bridge_cafile or bridge_capath must be defined to enable TLS support +# for this bridge. +# bridge_cafile defines the path to a file containing the +# Certificate Authority certificates that have signed the remote broker +# certificate. +# bridge_capath defines a directory that will be searched for files containing +# the CA certificates. For bridge_capath to work correctly, the certificate +# files must have ".crt" as the file ending and you must run "openssl rehash +# " each time you add/remove a certificate. +#bridge_cafile +#bridge_capath + + +# If the remote broker has more than one protocol available on its port, e.g. +# MQTT and WebSockets, then use bridge_alpn to configure which protocol is +# requested. Note that WebSockets support for bridges is not yet available. +#bridge_alpn + +# When using certificate based encryption, bridge_insecure disables +# verification of the server hostname in the server certificate. This can be +# useful when testing initial server configurations, but makes it possible for +# a malicious third party to impersonate your server through DNS spoofing, for +# example. Use this option in testing only. If you need to resort to using this +# option in a production environment, your setup is at fault and there is no +# point using encryption. +#bridge_insecure false + +# Path to the PEM encoded client certificate, if required by the remote broker. +#bridge_certfile + +# Path to the PEM encoded client private key, if required by the remote broker. +#bridge_keyfile + +# ----------------------------------------------------------------- +# PSK based SSL/TLS support +# ----------------------------------------------------------------- +# Pre-shared-key encryption provides an alternative to certificate based +# encryption. A bridge can be configured to use PSK with the bridge_identity +# and bridge_psk options. These are the client PSK identity, and pre-shared-key +# in hexadecimal format with no "0x". Only one of certificate and PSK based +# encryption can be used on one +# bridge at once. +#bridge_identity +#bridge_psk + + +# ================================================================= +# External config files +# ================================================================= + +# External configuration files may be included by using the +# include_dir option. This defines a directory that will be searched +# for config files. All files that end in '.conf' will be loaded as +# a configuration file. It is best to have this as the last option +# in the main file. This option will only be processed from the main +# configuration file. The directory specified must not contain the +# main configuration file. +# Files within include_dir will be loaded sorted in case-sensitive +# alphabetical order, with capital letters ordered first. If this option is +# given multiple times, all of the files from the first instance will be +# processed before the next instance. See the man page for examples. +#include_dir diff --git a/tpm/mqtt/mqtt_tpm_simple.c b/tpm/mqtt/mqtt_tpm_simple.c new file mode 100644 index 00000000..4691fa3f --- /dev/null +++ b/tpm/mqtt/mqtt_tpm_simple.c @@ -0,0 +1,796 @@ +/* mqttsimple.c + * + * Copyright (C) 2006-2022 wolfSSL Inc. + * + * This file is part of wolfMQTT. + * + * wolfMQTT 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. + * + * wolfMQTT 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Standalone Example */ + +#include "wolfmqtt/mqtt_client.h" +#include "wolftpm/options.h" +#include "wolftpm/tpm2.h" +#include "wolftpm/tpm2_wrap.h" +//#include "mqttsimple.h" + +/* Requires BSD Style Socket */ + +#include +#include +#include +#include +#include + +/* Configuration */ +#define MQTT_HOST "127.0.0.1" +#define MQTT_QOS MQTT_QOS_0 +#define MQTT_KEEP_ALIVE_SEC 60 +#define MQTT_CMD_TIMEOUT_MS 30000 +#define MQTT_CON_TIMEOUT_MS 5000 +#define MQTT_CLIENT_ID "WolfMQTTClientSimple" +#define MQTT_TOPIC_NAME "wolfMQTT/example/testTopic" +#define MQTT_PUBLISH_MSG "Test Publish" +#define MQTT_USERNAME NULL +#define MQTT_PASSWORD NULL + +#define MQTT_USE_TLS 1 +#define MQTT_PORT 18883 + +#define MQTT_MAX_PACKET_SZ 1024 +#define INVALID_SOCKET_FD -1 +#define PRINT_BUFFER_SIZE 80 + +/* Local Variables */ +static MqttClient mClient; +static MqttNet mNetwork; +static int mSockFd = INVALID_SOCKET_FD; +static byte mSendBuf[MQTT_MAX_PACKET_SZ]; +static byte mReadBuf[MQTT_MAX_PACKET_SZ]; +static volatile word16 mPacketIdLast; + +static int gContinue = 1; + +/* Local Functions */ + +/* msg_new on first data callback */ +/* msg_done on last data callback */ +/* msg->total_len: Payload total length */ +/* msg->buffer: Payload buffer */ +/* msg->buffer_len: Payload buffer length */ +/* msg->buffer_pos: Payload buffer position */ +static int mqtt_message_cb(MqttClient *client, MqttMessage *msg, + byte msg_new, byte msg_done) +{ + byte buf[PRINT_BUFFER_SIZE+1]; + word32 len; + + (void)client; + + if (msg_new) { + /* Determine min size to dump */ + len = msg->topic_name_len; + if (len > PRINT_BUFFER_SIZE) { + len = PRINT_BUFFER_SIZE; + } + XMEMCPY(buf, msg->topic_name, len); + buf[len] = '\0'; /* Make sure its null terminated */ + + /* Print incoming message */ + PRINTF("MQTT Message: Topic %s, Qos %d, Len %u", + buf, msg->qos, msg->total_len); + } + + /* Print message payload */ + len = msg->buffer_len; + if (len > PRINT_BUFFER_SIZE) { + len = PRINT_BUFFER_SIZE; + } + XMEMCPY(buf, msg->buffer, len); + buf[len] = '\0'; /* Make sure its null terminated */ + PRINTF("Payload (%d - %d): %s", + msg->buffer_pos, msg->buffer_pos + len, buf); + + if (msg_done) { + PRINTF("MQTT Message: Done"); + } + + if(XMEMCMP(buf, "exit", 4)==0) { + PRINTF("MQTT EXITING"); + gContinue=0; + } + + /* Return negative to terminate publish processing */ + return MQTT_CODE_SUCCESS; +} + +static void setup_timeout(struct timeval* tv, int timeout_ms) +{ + tv->tv_sec = timeout_ms / 1000; + tv->tv_usec = (timeout_ms % 1000) * 1000; + + /* Make sure there is a minimum value specified */ + if (tv->tv_sec < 0 || (tv->tv_sec == 0 && tv->tv_usec <= 0)) { + tv->tv_sec = 0; + tv->tv_usec = 100; + } +} + +static int socket_get_error(int sockFd) +{ + int so_error = 0; + socklen_t len = sizeof(so_error); + getsockopt(sockFd, SOL_SOCKET, SO_ERROR, &so_error, &len); + return so_error; +} + +static int mqtt_net_connect(void *context, const char* host, word16 port, + int timeout_ms) +{ + int rc; + int sockFd, *pSockFd = (int*)context; + struct sockaddr_in addr; + struct addrinfo *result = NULL; + struct addrinfo hints; + + if (pSockFd == NULL) { + return MQTT_CODE_ERROR_BAD_ARG; + } + + (void)timeout_ms; + + /* get address */ + XMEMSET(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + XMEMSET(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + + rc = getaddrinfo(host, NULL, &hints, &result); + if (rc >= 0 && result != NULL) { + struct addrinfo* res = result; + + /* prefer ip4 addresses */ + while (res) { + if (res->ai_family == AF_INET) { + result = res; + break; + } + res = res->ai_next; + } + if (result->ai_family == AF_INET) { + addr.sin_port = htons(port); + addr.sin_family = AF_INET; + addr.sin_addr = + ((struct sockaddr_in*)(result->ai_addr))->sin_addr; + } + else { + rc = -1; + } + freeaddrinfo(result); + } + if (rc < 0) { + return MQTT_CODE_ERROR_NETWORK; + } + + sockFd = socket(addr.sin_family, SOCK_STREAM, 0); + if (sockFd < 0) { + return MQTT_CODE_ERROR_NETWORK; + } + + /* Start connect */ + rc = connect(sockFd, (struct sockaddr*)&addr, sizeof(addr)); + if (rc < 0) { + PRINTF("NetConnect: Error %d (Sock Err %d)", + rc, socket_get_error(*pSockFd)); + close(sockFd); + return MQTT_CODE_ERROR_NETWORK; + } + + /* save socket number to context */ + *pSockFd = sockFd; + + return MQTT_CODE_SUCCESS; +} + +static int mqtt_net_read(void *context, byte* buf, int buf_len, int timeout_ms) +{ + int rc; + int *pSockFd = (int*)context; + int bytes = 0; + struct timeval tv; + + if (pSockFd == NULL) { + return MQTT_CODE_ERROR_BAD_ARG; + } + + /* Setup timeout */ + setup_timeout(&tv, timeout_ms); + setsockopt(*pSockFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); + + /* Loop until buf_len has been read, error or timeout */ + while (bytes < buf_len) { + rc = (int)recv(*pSockFd, &buf[bytes], buf_len - bytes, 0); + if (rc < 0) { + rc = socket_get_error(*pSockFd); + if (rc == 0) + break; /* timeout */ + PRINTF("NetRead: Error %d", rc); + return MQTT_CODE_ERROR_NETWORK; + } + bytes += rc; /* Data */ + } + + if (bytes == 0) { + return MQTT_CODE_ERROR_TIMEOUT; + } + + return bytes; +} + +static int mqtt_net_write(void *context, const byte* buf, int buf_len, + int timeout_ms) +{ + int rc; + int *pSockFd = (int*)context; + struct timeval tv; + + if (pSockFd == NULL) { + return MQTT_CODE_ERROR_BAD_ARG; + } + + /* Setup timeout */ + setup_timeout(&tv, timeout_ms); + setsockopt(*pSockFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); + + rc = (int)send(*pSockFd, buf, buf_len, 0); + if (rc < 0) { + PRINTF("NetWrite: Error %d (Sock Err %d)", + rc, socket_get_error(*pSockFd)); + return MQTT_CODE_ERROR_NETWORK; + } + + return rc; +} + +static int mqtt_net_disconnect(void *context) +{ + int *pSockFd = (int*)context; + + if (pSockFd == NULL) { + return MQTT_CODE_ERROR_BAD_ARG; + } + + close(*pSockFd); + *pSockFd = INVALID_SOCKET_FD; + + return MQTT_CODE_SUCCESS; +} + +static int mqtt_tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store) +{ + char buffer[WOLFSSL_MAX_ERROR_SZ]; + PRINTF("MQTT TLS Verify Callback: PreVerify %d, Error %d (%s)", + preverify, store->error, store->error != 0 ? + wolfSSL_ERR_error_string(store->error, buffer) : "none"); + PRINTF(" Subject's domain name is %s", store->domain); + + if (store->error != 0) { + /* Allowing to continue */ + /* Should check certificate and return 0 if not okay */ + PRINTF(" Allowing cert anyways"); + } + + return 1; +} + + +/* from certs/dummy-ecc.pem (as DER) */ +static const unsigned char DUMMY_ECC_KEY[] = { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x05, 0x0F, 0xEA, 0xB6, 0x2C, 0x7C, + 0xD3, 0x3C, 0x66, 0x3D, 0x6B, 0x44, 0xD5, 0x8A, 0xD4, 0x1C, 0xF6, 0x2A, 0x35, + 0x49, 0xB2, 0x36, 0x7D, 0xEC, 0xD4, 0xB3, 0x9A, 0x2B, 0x4F, 0x71, 0xC8, 0xD3, + 0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0xA1, + 0x44, 0x03, 0x42, 0x00, 0x04, 0x43, 0x98, 0xF7, 0x33, 0x77, 0xB4, 0x55, 0x02, + 0xF1, 0xF3, 0x79, 0x97, 0x67, 0xED, 0xB5, 0x3A, 0x7A, 0xE1, 0x7C, 0xC6, 0xA8, + 0x23, 0x8B, 0x3A, 0x68, 0x42, 0xDD, 0x68, 0x4F, 0x48, 0x6F, 0x2D, 0x9A, 0x7C, + 0x47, 0x20, 0x1F, 0x13, 0x69, 0x71, 0x05, 0x42, 0x5B, 0x9F, 0x23, 0x7D, 0xE0, + 0xA6, 0x5D, 0xD4, 0x11, 0x44, 0xB1, 0x91, 0x66, 0x50, 0xC0, 0x2C, 0x8C, 0x71, + 0x35, 0x0E, 0x28, 0xB4 +}; + +/* from certs/dummy-rsa.pem (as DER) */ +static const unsigned char DUMMY_RSA_KEY[] = { + 0x30, 0x82, 0x04, 0xA3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xCF, + 0xDD, 0xB2, 0x17, 0x49, 0xEB, 0xBF, 0xFB, 0xC5, 0x19, 0x13, 0x63, 0x86, 0x49, + 0xBC, 0xFE, 0x8E, 0xED, 0x21, 0x6E, 0x53, 0x18, 0x9C, 0x41, 0xD5, 0xEC, 0x12, + 0x31, 0xF0, 0xF9, 0x90, 0x08, 0x15, 0x68, 0x2F, 0x00, 0x9C, 0xAC, 0x36, 0x28, + 0xF6, 0xD8, 0x50, 0xA0, 0xD4, 0x7C, 0xDF, 0xE7, 0x0F, 0xE1, 0x36, 0xD1, 0xDD, + 0xC0, 0x2B, 0xF0, 0x3D, 0xC9, 0xF0, 0x5B, 0xE4, 0x76, 0x48, 0x91, 0xF0, 0x92, + 0x29, 0x82, 0x75, 0x7F, 0x0B, 0x41, 0x39, 0x77, 0x52, 0xCD, 0x1F, 0x30, 0xA3, + 0xC3, 0x79, 0x92, 0xBD, 0x0A, 0x7F, 0x16, 0xB2, 0x06, 0xFD, 0x49, 0xC5, 0x4D, + 0x34, 0x26, 0xDB, 0x49, 0x06, 0xDB, 0x49, 0x63, 0xB6, 0xE5, 0xA4, 0xEC, 0xC0, + 0x6D, 0x24, 0xF1, 0x82, 0x0F, 0x83, 0x1B, 0xB1, 0x0D, 0xA3, 0x8B, 0x6A, 0x39, + 0x39, 0xB6, 0xB3, 0xA3, 0xE1, 0x77, 0x69, 0x8C, 0xC7, 0x83, 0xE1, 0xBE, 0x9E, + 0xF9, 0xB7, 0xDB, 0xDF, 0xF8, 0x98, 0x7C, 0x9D, 0xC8, 0x72, 0x78, 0xBF, 0x13, + 0x62, 0x27, 0xA1, 0xBF, 0x4B, 0x2B, 0x04, 0x18, 0xCD, 0x2C, 0x10, 0x7E, 0xA5, + 0x33, 0x08, 0xD4, 0x49, 0xF1, 0xEC, 0x99, 0x6F, 0x2E, 0x0B, 0xB4, 0xD3, 0xB3, + 0xC2, 0x20, 0x02, 0xE9, 0x3A, 0xA1, 0xB3, 0x81, 0x9B, 0x0C, 0x02, 0xB0, 0xDE, + 0x9E, 0xEF, 0x0A, 0x47, 0x6E, 0xFA, 0xDB, 0x4D, 0x13, 0x1E, 0x1F, 0xD2, 0x7B, + 0xC6, 0x48, 0xE8, 0x27, 0xDE, 0xBC, 0x8D, 0x4C, 0x60, 0x5A, 0x71, 0xB5, 0xC3, + 0x7F, 0xFC, 0x7C, 0x28, 0xC1, 0x99, 0xF2, 0x7A, 0x3B, 0xCD, 0x6A, 0x76, 0xFE, + 0xA8, 0x9B, 0xDD, 0x03, 0x1E, 0xEB, 0xB4, 0x9D, 0x70, 0x5C, 0x7A, 0x1F, 0xB6, + 0x12, 0xEC, 0xCD, 0xAC, 0x6A, 0xCD, 0x2C, 0x25, 0x53, 0xEF, 0x34, 0xD5, 0xC5, + 0x97, 0x14, 0xD4, 0xB2, 0x86, 0x03, 0x5F, 0x89, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x82, 0x01, 0x00, 0x5D, 0x9E, 0xBF, 0x10, 0x48, 0x25, 0xDB, 0x00, 0xFD, + 0x43, 0x8E, 0xFC, 0xFB, 0x45, 0x88, 0xCE, 0xA9, 0xF6, 0xD9, 0x60, 0xC4, 0x22, + 0x48, 0x76, 0x4A, 0x70, 0x19, 0xBD, 0xCE, 0x87, 0xC8, 0x3C, 0x2B, 0xD0, 0x11, + 0xA3, 0x57, 0xED, 0x24, 0x33, 0x8D, 0x01, 0xDE, 0x46, 0xA1, 0x8D, 0x60, 0x96, + 0xC4, 0x0B, 0x2E, 0x52, 0x95, 0x6A, 0x71, 0x1F, 0xB1, 0xE4, 0x9A, 0xD1, 0xF8, + 0x72, 0xE1, 0xBA, 0x81, 0x3C, 0x83, 0x5F, 0x93, 0xA5, 0xD5, 0x9E, 0xD9, 0xD0, + 0x09, 0x46, 0x03, 0x6F, 0x37, 0xC2, 0xD9, 0xA5, 0xA2, 0x68, 0xF0, 0xD6, 0x7A, + 0xF6, 0x34, 0xEC, 0x1D, 0xE5, 0xE8, 0xC0, 0x3B, 0x71, 0x87, 0x9A, 0x0A, 0x52, + 0xD3, 0xD4, 0x58, 0x54, 0x9D, 0x52, 0x4B, 0x1A, 0x4E, 0xF6, 0xC7, 0x99, 0x18, + 0x44, 0x49, 0x4D, 0x88, 0x59, 0x1F, 0xCA, 0x4E, 0xDC, 0x57, 0xB7, 0x1D, 0x9D, + 0xDF, 0x59, 0x91, 0xD9, 0x2E, 0xE0, 0x54, 0xAA, 0x4E, 0x8F, 0x92, 0x82, 0x85, + 0x70, 0xF9, 0x93, 0x90, 0x3A, 0x30, 0xCD, 0xB3, 0x73, 0x81, 0x93, 0xE7, 0xF9, + 0x1F, 0xF6, 0xA9, 0xA9, 0xD4, 0xAE, 0x89, 0x0E, 0x38, 0x11, 0x61, 0xF7, 0xF7, + 0xDC, 0x9B, 0x99, 0x4B, 0xFE, 0xC0, 0x71, 0x78, 0x53, 0x18, 0x0F, 0x23, 0xA9, + 0x11, 0xA0, 0xAA, 0x57, 0xEE, 0x39, 0xAA, 0xEA, 0x2A, 0x7A, 0x8D, 0x12, 0x69, + 0x2C, 0x82, 0x4D, 0xA0, 0xE5, 0x1C, 0xB3, 0x69, 0x9D, 0xA1, 0x30, 0xA3, 0x40, + 0xFA, 0x86, 0x40, 0xD3, 0x8B, 0xF9, 0xAF, 0x98, 0x7D, 0x17, 0x07, 0xA3, 0x29, + 0xE2, 0x57, 0xEF, 0x47, 0xCF, 0x81, 0x22, 0x4D, 0x47, 0x63, 0xA4, 0x2F, 0x1A, + 0x8F, 0xC3, 0x26, 0x1F, 0xF6, 0xC5, 0x81, 0xFF, 0x14, 0xA9, 0x87, 0x56, 0x18, + 0x8A, 0x18, 0xFD, 0x37, 0xC3, 0x4B, 0x8E, 0xE0, 0x6B, 0x2C, 0x07, 0x4B, 0x05, + 0x02, 0x81, 0x81, 0x00, 0xED, 0x51, 0x06, 0x91, 0xB8, 0x94, 0x5E, 0x17, 0x9B, + 0x22, 0x25, 0xEF, 0x23, 0x76, 0x61, 0x26, 0xFA, 0xAC, 0xEE, 0xC1, 0x99, 0x8E, + 0x55, 0x38, 0x85, 0xD2, 0x15, 0x06, 0x6E, 0xBB, 0x45, 0xBB, 0xFE, 0x5F, 0xF7, + 0xD2, 0xA4, 0x41, 0x15, 0x24, 0x67, 0x8E, 0xA2, 0x6B, 0xBA, 0xAA, 0x28, 0x84, + 0x22, 0x63, 0xEE, 0xA8, 0xA0, 0xD0, 0xEA, 0x47, 0x8C, 0xAC, 0x4E, 0x98, 0x18, + 0x8A, 0xF2, 0x19, 0x76, 0x50, 0x9D, 0xFE, 0xD1, 0x59, 0xC3, 0xC1, 0x23, 0x3B, + 0x31, 0x73, 0xC7, 0x71, 0x3E, 0x94, 0xC8, 0x6D, 0x7F, 0xBA, 0x30, 0xF2, 0x4C, + 0x1A, 0x7E, 0x74, 0x52, 0x78, 0xA0, 0xAB, 0x69, 0x0C, 0x44, 0x59, 0xD0, 0xB0, + 0xFE, 0x2F, 0xE8, 0xC2, 0x18, 0xE7, 0x24, 0x8B, 0x73, 0xDF, 0x4F, 0x40, 0x92, + 0x0C, 0x8C, 0x6C, 0x92, 0x27, 0xBC, 0x3F, 0x5B, 0x79, 0x44, 0xC1, 0x32, 0xCC, + 0xA2, 0xB7, 0x02, 0x81, 0x81, 0x00, 0xE0, 0x3B, 0x1C, 0xC4, 0xC4, 0x69, 0x0D, + 0x6B, 0x57, 0x19, 0xB7, 0x59, 0x18, 0x92, 0xB2, 0x09, 0x39, 0x66, 0x97, 0xD1, + 0x18, 0xDE, 0x6B, 0x5F, 0xC5, 0x9B, 0x11, 0x47, 0x1E, 0xEA, 0xE3, 0xAC, 0x36, + 0x2B, 0x30, 0x99, 0x81, 0x00, 0x3D, 0x39, 0x41, 0x03, 0x90, 0x77, 0xDE, 0x4A, + 0xE1, 0x48, 0xDF, 0x98, 0x86, 0x03, 0x3B, 0xEA, 0xAF, 0xC8, 0xF6, 0xD7, 0x4F, + 0xE6, 0xAE, 0x70, 0xF2, 0x3D, 0xBB, 0xF2, 0x63, 0xB9, 0x2D, 0x3C, 0x08, 0xB3, + 0x10, 0x9E, 0x97, 0x6C, 0x8D, 0x28, 0x34, 0xAE, 0xDA, 0xD9, 0xA1, 0x8E, 0x3A, + 0x51, 0x7A, 0xA1, 0x14, 0x3F, 0xFB, 0xEA, 0x3B, 0xB4, 0x93, 0xAA, 0x14, 0x7A, + 0xB4, 0xD7, 0xCA, 0x7B, 0x61, 0xAF, 0xF5, 0x87, 0x1A, 0x64, 0xA9, 0x3E, 0x3C, + 0x7A, 0xDD, 0x11, 0x7F, 0x01, 0x2D, 0xA6, 0x91, 0xED, 0x3D, 0x28, 0x9C, 0x67, + 0xC2, 0x5C, 0xCF, 0xBF, 0x02, 0x81, 0x81, 0x00, 0xCE, 0x0C, 0x59, 0xCD, 0xD0, + 0x1B, 0x52, 0x0E, 0xE0, 0xED, 0x27, 0x4E, 0x98, 0xD5, 0xC1, 0xC8, 0x9C, 0x41, + 0xE6, 0x13, 0x46, 0x06, 0x24, 0xCC, 0x2C, 0xB4, 0x98, 0xF8, 0xBA, 0xCF, 0xF2, + 0xDE, 0x25, 0x20, 0xA2, 0x05, 0xCC, 0x03, 0x8E, 0x1D, 0xCB, 0xA4, 0x36, 0x35, + 0x9F, 0x1E, 0xFA, 0x8A, 0xAF, 0x69, 0x60, 0xE0, 0x1C, 0xB1, 0x07, 0x99, 0x13, + 0xF4, 0xCF, 0x50, 0x93, 0x8E, 0xA0, 0x61, 0xA7, 0x2E, 0x9B, 0xDF, 0x91, 0x59, + 0x84, 0xF3, 0x7E, 0x69, 0x78, 0xA8, 0x73, 0xF4, 0x49, 0x47, 0xD9, 0x35, 0xE9, + 0x7E, 0x79, 0xDD, 0x06, 0x62, 0xC2, 0x84, 0xB0, 0xCE, 0x77, 0x82, 0x1C, 0x75, + 0x40, 0x2B, 0x53, 0x5D, 0x39, 0x75, 0xD3, 0x7C, 0x23, 0x2F, 0x1D, 0xB5, 0xCE, + 0xE7, 0x86, 0xE2, 0x23, 0x6C, 0xAD, 0xC7, 0xDE, 0xA6, 0x8D, 0x75, 0xDD, 0x30, + 0x4F, 0x98, 0x07, 0x49, 0x51, 0xC5, 0x02, 0x81, 0x80, 0x46, 0x19, 0x34, 0xBD, + 0x2E, 0xC9, 0xC8, 0xB0, 0x2D, 0xE2, 0x94, 0x36, 0xFE, 0x3F, 0x9D, 0xF8, 0xD4, + 0x41, 0x06, 0x65, 0x0F, 0xE9, 0x38, 0x98, 0x10, 0x26, 0x92, 0x18, 0x31, 0xCA, + 0x2C, 0xB2, 0xC1, 0x9C, 0x6E, 0xED, 0x0E, 0x2F, 0x0C, 0xF4, 0xC1, 0x26, 0x64, + 0x1B, 0x95, 0x1A, 0xC3, 0xA3, 0x0C, 0x83, 0x9A, 0x21, 0x98, 0xB1, 0x9D, 0x92, + 0xAD, 0xD8, 0x51, 0xDA, 0x43, 0xDE, 0x7B, 0x5C, 0x61, 0x4D, 0x3D, 0x6F, 0xBE, + 0x7C, 0x6E, 0x1B, 0xCC, 0xAE, 0x47, 0x98, 0x5F, 0xE8, 0x99, 0xCF, 0xB0, 0x0B, + 0x29, 0x3E, 0x55, 0x6C, 0xF3, 0x71, 0x37, 0xEB, 0x68, 0xCD, 0xA9, 0x2C, 0xA2, + 0x9D, 0x21, 0x19, 0xDB, 0x3F, 0x3A, 0xC5, 0xA7, 0x9C, 0x62, 0x9D, 0x81, 0xDA, + 0xC6, 0x2D, 0xF6, 0xAA, 0x52, 0x42, 0x0D, 0xFA, 0x48, 0x53, 0x32, 0x7B, 0x80, + 0x0B, 0x1A, 0x1A, 0x35, 0xE0, 0xDD, 0xF1, 0x02, 0x81, 0x80, 0x76, 0x46, 0xB9, + 0x57, 0x91, 0x3F, 0x64, 0x5D, 0x42, 0x37, 0x70, 0x9D, 0x44, 0x38, 0x09, 0x09, + 0x42, 0x3E, 0x2E, 0x8A, 0x7A, 0xA4, 0x57, 0x4B, 0x81, 0x95, 0x65, 0x47, 0x3C, + 0xF3, 0x77, 0x54, 0xE3, 0x7D, 0xEC, 0x06, 0xC9, 0x26, 0xAB, 0xDD, 0x66, 0x73, + 0x54, 0x86, 0x31, 0x26, 0x75, 0x5B, 0x84, 0xAB, 0xD2, 0xA2, 0x6A, 0x9B, 0x6E, + 0xDD, 0x45, 0xAE, 0x81, 0x49, 0x12, 0x8D, 0x03, 0x1C, 0x1B, 0x6B, 0x5B, 0x37, + 0xFA, 0xE7, 0x05, 0x9F, 0xBD, 0x66, 0xDD, 0x6C, 0xD7, 0x16, 0x0D, 0xCC, 0x64, + 0x19, 0xC2, 0xCD, 0xC3, 0xA9, 0xED, 0x70, 0xFA, 0x75, 0xD8, 0x41, 0xF7, 0xC6, + 0x84, 0xE8, 0x40, 0xF0, 0xE5, 0x93, 0x88, 0xE2, 0x4E, 0x4F, 0xE4, 0x5F, 0xDF, + 0x53, 0xAB, 0xA7, 0x06, 0xDC, 0x64, 0x7E, 0x51, 0xE8, 0x7E, 0x1C, 0x33, 0x9F, + 0xBF, 0x5E, 0x58, 0xBC, 0x7D, 0xA3, 0x80, 0x84 +}; + + +/* Function checks key to see if its the "dummy" key */ +static inline int myTpmCheckKey(wc_CryptoInfo* info, TpmCryptoDevCtx* ctx) +{ + int ret = 0; + +#ifndef NO_RSA + if (info && info->pk.type == WC_PK_TYPE_RSA) { + byte e[sizeof(word32)], e2[sizeof(word32)]; + byte n[WOLFTPM2_WRAP_RSA_KEY_BITS/8], n2[WOLFTPM2_WRAP_RSA_KEY_BITS/8]; + word32 eSz = sizeof(e), e2Sz = sizeof(e); + word32 nSz = sizeof(n), n2Sz = sizeof(n); + RsaKey rsakey; + word32 idx = 0; + + /* export the raw public RSA portion */ + ret = wc_RsaFlattenPublicKey(info->pk.rsa.key, e, &eSz, n, &nSz); + if (ret == 0) { + /* load the modulus for the dummy key */ + ret = wc_InitRsaKey(&rsakey, NULL); + if (ret == 0) { + ret = wc_RsaPrivateKeyDecode(DUMMY_RSA_KEY, &idx, &rsakey, + (word32)sizeof(DUMMY_RSA_KEY)); + if (ret == 0) { + ret = wc_RsaFlattenPublicKey(&rsakey, e2, &e2Sz, n2, &n2Sz); + } + wc_FreeRsaKey(&rsakey); + } + } + + if (ret == 0 && XMEMCMP(n, n2, nSz) == 0) { + #ifdef DEBUG_WOLFTPM + printf("Detected dummy key, so using TPM RSA key handle\n"); + #endif + ret = 1; + } + } +#endif +#if defined(HAVE_ECC) + if (info && info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + byte qx[WOLFTPM2_WRAP_ECC_KEY_BITS/8], qx2[WOLFTPM2_WRAP_ECC_KEY_BITS/8]; + byte qy[WOLFTPM2_WRAP_ECC_KEY_BITS/8], qy2[WOLFTPM2_WRAP_ECC_KEY_BITS/8]; + word32 qxSz = sizeof(qx), qx2Sz = sizeof(qx2); + word32 qySz = sizeof(qy), qy2Sz = sizeof(qy2); + ecc_key eccKey; + word32 idx = 0; + + /* export the raw public ECC portion */ + ret = wc_ecc_export_public_raw(info->pk.eccsign.key, qx, &qxSz, qy, &qySz); + if (ret == 0) { + /* load the ECC public x/y for the dummy key */ + ret = wc_ecc_init(&eccKey); + if (ret == 0) { + ret = wc_EccPrivateKeyDecode(DUMMY_ECC_KEY, &idx, &eccKey, + (word32)sizeof(DUMMY_ECC_KEY)); + if (ret == 0) { + ret = wc_ecc_export_public_raw(&eccKey, qx2, &qx2Sz, qy2, &qy2Sz); + } + wc_ecc_free(&eccKey); + } + } + + if (ret == 0 && XMEMCMP(qx, qx2, qxSz) == 0 && + XMEMCMP(qy, qy2, qySz) == 0) { + #ifdef DEBUG_WOLFTPM + printf("Detected dummy key, so using TPM ECC key handle\n"); + #endif + ret = 1; + } + } +#endif + (void)info; + (void)ctx; + + /* non-zero return code means its a "dummy" key (not valid) and the + provided TPM handle will be used, not the wolf public key info */ + return ret; +} + + +static int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key) +{ + int rc = 0; +#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) + XFILE fp = NULL; + size_t fileSz = 0; + size_t bytes_read = 0; + byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; + int pubAreaSize; + + XMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB)); + + fp = XFOPEN(filename, "rb"); + if (fp != XBADFILE) { + XFSEEK(fp, 0, XSEEK_END); + fileSz = XFTELL(fp); + XREWIND(fp); + if (fileSz > sizeof(key->priv) + sizeof(key->pub)) { + printf("File size check failed\n"); + rc = BUFFER_E; goto exit; + } + printf("Reading %d bytes from %s\n", (int)fileSz, filename); + + bytes_read = XFREAD(&key->pub.size, 1, sizeof(key->pub.size), fp); + if (bytes_read != sizeof(key->pub.size)) { + printf("Read %zu, expected size marker of %zu bytes\n", + bytes_read, sizeof(key->pub.size)); + goto exit; + } + fileSz -= bytes_read; + + bytes_read = XFREAD(pubAreaBuffer, 1, sizeof(UINT16) + key->pub.size, fp); + if (bytes_read != sizeof(UINT16) + key->pub.size) { + printf("Read %zu, expected public blob %zu bytes\n", + bytes_read, sizeof(UINT16) + key->pub.size); + goto exit; + } + fileSz -= bytes_read; /* Reminder bytes for private key part */ + + /* Decode the byte stream into a publicArea structure ready for use */ + rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer, + (word32)sizeof(pubAreaBuffer), &pubAreaSize); + if (rc != TPM_RC_SUCCESS) return rc; + #ifdef DEBUG_WOLFTPM + TPM2_PrintPublicArea(&key->pub); + #endif + + if (fileSz > 0) { + printf("Reading the private part of the key\n"); + bytes_read = XFREAD(&key->priv, 1, fileSz, fp); + if (bytes_read != fileSz) { + printf("Read %zu, expected private blob %zu bytes\n", + bytes_read, fileSz); + goto exit; + } + rc = 0; /* success */ + } + + /* sanity check the sizes */ + if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size)) || + key->priv.size > sizeof(key->priv.buffer)) { + printf("Struct size check failed (pub %d, priv %d)\n", + key->pub.size, key->priv.size); + rc = BUFFER_E; + } + } + else { + rc = BUFFER_E; + printf("File %s not found!\n", filename); + printf("Keys can be generated by running:\n" + " ./examples/keygen/keygen rsa_test_blob.raw -rsa -t\n" + " ./examples/keygen/keygen ecc_test_blob.raw -ecc -t\n"); + } + +exit: + if (fp) + XFCLOSE(fp); +#else + (void)filename; + (void)key; +#endif /* !NO_FILESYSTEM && !NO_WRITE_TEMP_FILES */ + return rc; +} + +TpmCryptoDevCtx tpmCtx; +WOLFTPM2_DEV dev; +WOLFTPM2_KEY storageKey; +WOLFTPM2_KEY key; +WOLFTPM2_KEYBLOB keyblob; +static const char gStorageKeyAuth[] = "ThisIsMyStorageKeyAuth"; +static const char gKeyAuth[] = "ThisIsMyKeyAuth"; + +/* Use this callback to setup TLS certificates and verify callbacks */ +static int mqtt_tls_cb(MqttClient* client) +{ + int rc = WOLFSSL_FAILURE; + TPM_ALG_ID alg = TPM_ALG_RSA; + + int tpmDevId; + + rc = readKeyBlob("tmp_certs_and_keys/rsa_test_blob.raw", &keyblob); + //rc = readKeyBlob("ecc_test_blob.raw", &keyblob); + + /* Use highest available and allow downgrade. If wolfSSL is built with + * old TLS support, it is possible for a server to force a downgrade to + * an insecure version. */ + client->tls.ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + if (client->tls.ctx) { + wolfSSL_CTX_set_verify(client->tls.ctx, WOLFSSL_VERIFY_PEER, + mqtt_tls_verify_cb); + + /* default to success */ + rc = WOLFSSL_SUCCESS; + + // TODO: Add cert and private key here + + /* Initi TPM */ + rc = wolfTPM2_Init(&dev, NULL, NULL); + if (rc != 0) { + PRINTF("TPM init failed\n"); + return rc; + } + + tpmCtx.rsaKey = &key; + tpmCtx.checkKeyCb = myTpmCheckKey; /* detects if using "dummy" key */ + tpmCtx.storageKey = &storageKey; + + rc = wolfTPM2_SetCryptoDevCb(&dev, wolfTPM2_CryptoDevCb, &tpmCtx, &tpmDevId); + if (rc != 0) { + PRINTF("wolfTPM2_SetCryptoDevCb failed\n"); + return rc; + } + + //TODO: load key + rc = wolfTPM2_CreateSRK(&dev, &storageKey, alg, + (byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1); + if (rc != 0) goto exit; + + rc = wolfTPM2_LoadKey(&dev, &keyblob, &storageKey.handle); + if (rc != TPM_RC_SUCCESS) { + printf("wolfTPM2_LoadKey failed\n"); + goto exit; + } + printf("Loaded key to 0x%x\n", (word32)keyblob.handle.hndl); + + //set auth + key.handle = keyblob.handle; + key.pub = keyblob.pub; + key.handle.auth.size = sizeof(gKeyAuth)-1; + XMEMCPY(key.handle.auth.buffer, gKeyAuth, key.handle.auth.size); + + /* Setup DevID */ + wolfSSL_CTX_SetDevId(client->tls.ctx, tpmDevId); + + + printf("Loading RSA dummy key\n"); + + /* Private key is on TPM and crypto dev callbacks are used */ + /* TLS client (mutual auth) requires a dummy key loaded (workaround) */ + if (wolfSSL_CTX_use_PrivateKey_buffer(client->tls.ctx, DUMMY_RSA_KEY, + sizeof(DUMMY_RSA_KEY), WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { + printf("Failed to set key!\r\n"); + goto exit; + } + + // load certificate + rc = wolfSSL_CTX_use_certificate_file(client->tls.ctx, + "tmp_certs_and_keys/client-rsa-cert.pem", + WOLFSSL_FILETYPE_PEM); + + } + + exit: + PRINTF("MQTT TLS Setup (%d)", rc); + + return rc; +} + +static word16 mqtt_get_packetid(void) +{ + /* Check rollover */ + if (mPacketIdLast >= MAX_PACKET_ID) { + mPacketIdLast = 0; + } + + return ++mPacketIdLast; +} + +/* Public Function */ +int mqttsimple_test(void) +{ + int rc = 0; + MqttObject mqttObj; + MqttTopic topics[1]; + + /* Initialize MQTT client */ + XMEMSET(&mNetwork, 0, sizeof(mNetwork)); + mNetwork.connect = mqtt_net_connect; + mNetwork.read = mqtt_net_read; + mNetwork.write = mqtt_net_write; + mNetwork.disconnect = mqtt_net_disconnect; + mNetwork.context = &mSockFd; + rc = MqttClient_Init(&mClient, &mNetwork, mqtt_message_cb, + mSendBuf, sizeof(mSendBuf), mReadBuf, sizeof(mReadBuf), + MQTT_CON_TIMEOUT_MS); + if (rc != MQTT_CODE_SUCCESS) { + goto exit; + } + PRINTF("MQTT Init Success"); + + /* Connect to broker */ + rc = MqttClient_NetConnect(&mClient, MQTT_HOST, MQTT_PORT, + MQTT_CON_TIMEOUT_MS, MQTT_USE_TLS, mqtt_tls_cb); + if (rc != MQTT_CODE_SUCCESS) { + goto exit; + } + PRINTF("MQTT Network Connect Success: Host %s, Port %d, UseTLS %d", + MQTT_HOST, MQTT_PORT, MQTT_USE_TLS); + + /* Send Connect and wait for Ack */ + XMEMSET(&mqttObj, 0, sizeof(mqttObj)); + mqttObj.connect.keep_alive_sec = MQTT_KEEP_ALIVE_SEC; + mqttObj.connect.client_id = MQTT_CLIENT_ID; + mqttObj.connect.username = MQTT_USERNAME; + mqttObj.connect.password = MQTT_PASSWORD; + rc = MqttClient_Connect(&mClient, &mqttObj.connect); + if (rc != MQTT_CODE_SUCCESS) { + goto exit; + } + PRINTF("MQTT Broker Connect Success: ClientID %s, Username %s, Password %s", + MQTT_CLIENT_ID, + (MQTT_USERNAME == NULL) ? "Null" : MQTT_USERNAME, + (MQTT_PASSWORD == NULL) ? "Null" : MQTT_PASSWORD); + + /* Subscribe and wait for Ack */ + XMEMSET(&mqttObj, 0, sizeof(mqttObj)); + topics[0].topic_filter = MQTT_TOPIC_NAME; + topics[0].qos = MQTT_QOS; + mqttObj.subscribe.packet_id = mqtt_get_packetid(); + mqttObj.subscribe.topic_count = sizeof(topics) / sizeof(MqttTopic); + mqttObj.subscribe.topics = topics; + rc = MqttClient_Subscribe(&mClient, &mqttObj.subscribe); + if (rc != MQTT_CODE_SUCCESS) { + goto exit; + } + PRINTF("MQTT Subscribe Success: Topic %s, QoS %d", + MQTT_TOPIC_NAME, MQTT_QOS); + + /* Publish */ + XMEMSET(&mqttObj, 0, sizeof(mqttObj)); + mqttObj.publish.qos = MQTT_QOS; + mqttObj.publish.topic_name = MQTT_TOPIC_NAME; + mqttObj.publish.packet_id = mqtt_get_packetid(); + mqttObj.publish.buffer = (byte*)MQTT_PUBLISH_MSG; + mqttObj.publish.total_len = XSTRLEN(MQTT_PUBLISH_MSG); + rc = MqttClient_Publish(&mClient, &mqttObj.publish); + if (rc != MQTT_CODE_SUCCESS) { + goto exit; + } + PRINTF("MQTT Publish: Topic %s, Qos %d, Message %s", + mqttObj.publish.topic_name, mqttObj.publish.qos, mqttObj.publish.buffer); + + /* Wait for messages */ + while (gContinue) { + rc = MqttClient_WaitMessage_ex(&mClient, &mqttObj, MQTT_CMD_TIMEOUT_MS); + + if (rc == MQTT_CODE_ERROR_TIMEOUT) { + /* send keep-alive ping */ + rc = MqttClient_Ping_ex(&mClient, &mqttObj.ping); + if (rc != MQTT_CODE_SUCCESS) { + break; + } + PRINTF("MQTT Keep-Alive Ping"); + } + else if (rc != MQTT_CODE_SUCCESS) { + break; + } + } + +exit: + if (rc != MQTT_CODE_SUCCESS) { + PRINTF("MQTT Error %d: %s", rc, MqttClient_ReturnCodeToString(rc)); + } + return rc; +} + +int main(int argc, char** argv) +{ + int rc = -1; + (void)argc; + (void)argv; + wolfSSL_Debugging_ON(); + rc = mqttsimple_test(); + + + if(storageKey.handle.hndl) { + wolfTPM2_UnloadHandle(&dev, &storageKey.handle); + } + if (key.handle.hndl) { + wolfTPM2_UnloadHandle(&dev, &key.handle); + } + + return (rc == 0) ? 0 : EXIT_FAILURE; +} diff --git a/tpm/mqtt/run.sh b/tpm/mqtt/run.sh new file mode 100755 index 00000000..b6bba899 --- /dev/null +++ b/tpm/mqtt/run.sh @@ -0,0 +1,94 @@ +#!/usr/bin/bash + +WOLFSSL=../../../wolfssl +WOLFTPM=../../../wolftpm + +set -e +set -x + +TPM_SERVER_REDIR="&> /dev/null" +MOSQUITTO_REDIR="" +MOSQUITTO_PUB_REDIR="&> /dev/null" +CLIENT_REDIR="" +use_tmux=false +#use_tmux=true + +if ${use_tmux} && which tmux > /dev/null ; then + echo "Using tmux" + TMUX_SESSION=mqtt-tpm + tmux new-session -d -s "${TMUX_SESSION}" + + TPM_SERVER_REDIR="2>&1 | tmux split-window -dI -p 10 -t \"${TMUX_SESSION}:\"" + MOSQUITTO_REDIR="2>&1 | tmux split-window -dI -p 10 -t \"${TMUX_SESSION}:\"" + CLIENT_REDIR="2>&1 | tmux split-window -dI -b -h -f -e \"LD_LIBRARY_PATH=$PWD/inst/lib\" -p 33 -t \"${TMUX_SESSION}:\"" + MOSQUITTO_PUB_REDIR="2>&1 | tmux split-window -dI -h -p 50 -t \"${TMUX_SESSION}:\"" +fi + +# start simulator (clean state) +eval ${WOLFTPM}/ibmswtpm2/src/tpm_server -rm ${TPM_SERVER_REDIR} & + + +#generate TPM key, csr, and certs +pushd ${WOLFTPM} +# clean certs +./certs/certreq.sh clean +# generate key +./examples/keygen/keygen +# generate csr +./examples/csr/csr +# sign csr +./certs/certreq.sh +popd + +# copy ca cert, wrapped blob, and client cert locally +src_files=( \ + ${WOLFSSL}/certs/ca-cert.pem \ + ${WOLFSSL}/certs/server-cert.pem \ + ${WOLFSSL}/certs/server-key.pem \ + ${WOLFSSL}/certs/client-ca.pem \ + ${WOLFSSL}/certs/client-cert.pem \ + ${WOLFSSL}/certs/client-key.pem \ + ${WOLFTPM}/certs/ca-rsa-cert.pem \ + ${WOLFTPM}/rsa_test_blob.raw \ + ${WOLFTPM}/certs/client-rsa-cert.pem \ + ) + +mkdir -p tmp_certs_and_keys/ +cp -v ${src_files[*]} tmp_certs_and_keys/ + +# concatenate CA, TPM CA, and client CA to be used by mosquitto +cat tmp_certs_and_keys/ca-cert.pem \ + tmp_certs_and_keys/ca-rsa-cert.pem \ + tmp_certs_and_keys/client-ca.pem \ + > tmp_certs_and_keys/ca-list.pem + +# start server +eval mosquitto -v -c mosquitto.conf ${MOSQUITTO_REDIR} & +mosq_pid=$! + +sleep 5 +#start client +export LD_LIBRARY_PATH=$PWD/inst/lib +eval ./mqtt_tpm_simple ${CLIENT_REDIR} & + +sleep 5 +#publish message +eval mosquitto_pub -d -h 127.0.0.1 -p 18883 \ + --cafile tmp_certs_and_keys/ca-cert.pem \ + --cert tmp_certs_and_keys/client-cert.pem \ + --key tmp_certs_and_keys/client-key.pem \ + -t wolfMQTT/example/testTopic -m "Hola!" ${MOSQUITTO_PUB_REDIR} + +sleep 5 +#publish message to exit +eval mosquitto_pub -d -h 127.0.0.1 -p 18883 \ + --cafile tmp_certs_and_keys/ca-cert.pem \ + --cert tmp_certs_and_keys/client-cert.pem \ + --key tmp_certs_and_keys/client-key.pem \ + -t wolfMQTT/example/testTopic -m exit ${MOSQUITTO_PUB_REDIR} + + +sleep 5 + +pkill -9 -x -u $EUID tpm_server +pkill -9 -x -u $EUID mosquitto From ff80c0cca7f6107d1ed22101f0a32c2171926003 Mon Sep 17 00:00:00 2001 From: Elms Date: Fri, 13 May 2022 10:08:02 -0700 Subject: [PATCH 2/5] tpm: Add windows curl and mqtt examples --- tpm/mqtt/mqtt_tpm_simple.c | 89 +++-- tpm/windows/README | 10 + tpm/windows/curl_mqtt/curl_mqtt.vcxproj | 148 +++++++++ tpm/windows/curl_mqtt/curl_tpm.cpp | 411 ++++++++++++++++++++++++ tpm/windows/mqtt_tpm/mqtt_tpm.vcxproj | 156 +++++++++ tpm/windows/tpm-examples.sln | 47 +++ 6 files changed, 835 insertions(+), 26 deletions(-) create mode 100644 tpm/windows/README create mode 100644 tpm/windows/curl_mqtt/curl_mqtt.vcxproj create mode 100644 tpm/windows/curl_mqtt/curl_tpm.cpp create mode 100644 tpm/windows/mqtt_tpm/mqtt_tpm.vcxproj create mode 100644 tpm/windows/tpm-examples.sln diff --git a/tpm/mqtt/mqtt_tpm_simple.c b/tpm/mqtt/mqtt_tpm_simple.c index 4691fa3f..46300e97 100644 --- a/tpm/mqtt/mqtt_tpm_simple.c +++ b/tpm/mqtt/mqtt_tpm_simple.c @@ -21,20 +21,36 @@ /* Standalone Example */ -#include "wolfmqtt/mqtt_client.h" -#include "wolftpm/options.h" -#include "wolftpm/tpm2.h" -#include "wolftpm/tpm2_wrap.h" -//#include "mqttsimple.h" +#ifdef _WIN32 +#include +#include -/* Requires BSD Style Socket */ +#pragma comment(lib, "ws2_32.lib") -#include +#define CLOSE_SOCKET(sock) closesocket(sock) + +#else +/* Requires BSD Style Socket */ #include #include #include #include +#define CLOSE_SOCKET(sock) close(sock) +#endif + +#include + +#include + +#include "wolfmqtt/mqtt_client.h" +#ifndef WOLFTPM_USER_SETTINGS +#include "wolftpm/options.h" +#endif +#include "wolftpm/tpm2.h" +#include "wolftpm/tpm2_wrap.h" + + /* Configuration */ #define MQTT_HOST "127.0.0.1" #define MQTT_QOS MQTT_QOS_0 @@ -57,7 +73,7 @@ /* Local Variables */ static MqttClient mClient; static MqttNet mNetwork; -static int mSockFd = INVALID_SOCKET_FD; +static SOCKET mSockFd = INVALID_SOCKET_FD; static byte mSendBuf[MQTT_MAX_PACKET_SZ]; static byte mReadBuf[MQTT_MAX_PACKET_SZ]; static volatile word16 mPacketIdLast; @@ -129,23 +145,38 @@ static void setup_timeout(struct timeval* tv, int timeout_ms) } } -static int socket_get_error(int sockFd) +static int socket_get_error(SOCKET sockFd) { +#ifdef _WIN32 + return WSAGetLastError(); +#else int so_error = 0; socklen_t len = sizeof(so_error); getsockopt(sockFd, SOL_SOCKET, SO_ERROR, &so_error, &len); return so_error; +#endif } static int mqtt_net_connect(void *context, const char* host, word16 port, int timeout_ms) { int rc; - int sockFd, *pSockFd = (int*)context; + SOCKET sockFd, *pSockFd = (SOCKET*)context; struct sockaddr_in addr; struct addrinfo *result = NULL; struct addrinfo hints; + { + WORD wVersionRequested; + WSADATA wsaData; + int err; + + /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ + wVersionRequested = MAKEWORD(2, 2); + + err = WSAStartup(wVersionRequested, &wsaData); + } + if (pSockFd == NULL) { return MQTT_CODE_ERROR_BAD_ARG; } @@ -198,7 +229,7 @@ static int mqtt_net_connect(void *context, const char* host, word16 port, if (rc < 0) { PRINTF("NetConnect: Error %d (Sock Err %d)", rc, socket_get_error(*pSockFd)); - close(sockFd); + CLOSE_SOCKET(sockFd); return MQTT_CODE_ERROR_NETWORK; } @@ -213,6 +244,7 @@ static int mqtt_net_read(void *context, byte* buf, int buf_len, int timeout_ms) int rc; int *pSockFd = (int*)context; int bytes = 0; + struct timeval tv; if (pSockFd == NULL) { @@ -276,7 +308,7 @@ static int mqtt_net_disconnect(void *context) return MQTT_CODE_ERROR_BAD_ARG; } - close(*pSockFd); + CLOSE_SOCKET(*pSockFd); *pSockFd = INVALID_SOCKET_FD; return MQTT_CODE_SUCCESS; @@ -533,9 +565,6 @@ static int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key) rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer, (word32)sizeof(pubAreaBuffer), &pubAreaSize); if (rc != TPM_RC_SUCCESS) return rc; - #ifdef DEBUG_WOLFTPM - TPM2_PrintPublicArea(&key->pub); - #endif if (fileSz > 0) { printf("Reading the private part of the key\n"); @@ -590,9 +619,12 @@ static int mqtt_tls_cb(MqttClient* client) int tpmDevId; - rc = readKeyBlob("tmp_certs_and_keys/rsa_test_blob.raw", &keyblob); - //rc = readKeyBlob("ecc_test_blob.raw", &keyblob); - +#ifdef WOLFSSL_RSA + rc = readKeyBlob("rsa_test_blob.raw", &keyblob); +#else + rc = readKeyBlob("ecc_test_blob.raw", &keyblob); +#endif + /* Use highest available and allow downgrade. If wolfSSL is built with * old TLS support, it is possible for a server to force a downgrade to * an insecure version. */ @@ -601,12 +633,16 @@ static int mqtt_tls_cb(MqttClient* client) wolfSSL_CTX_set_verify(client->tls.ctx, WOLFSSL_VERIFY_PEER, mqtt_tls_verify_cb); +#if 0 /* Example how to enable CRL and OCSP */ + wolfSSL_CTX_EnableCRL(client->tls.ctx, WOLFSSL_CRL_CHECKALL); + wolfSSL_CTX_EnableOCSP(client->tls.ctx, WOLFSSL_OCSP_CHECKALL); + wolfSSL_CTX_EnableOCSPStapling(client->tls.ctx); +#endif + /* default to success */ rc = WOLFSSL_SUCCESS; - // TODO: Add cert and private key here - - /* Initi TPM */ + /* Initialize TPM */ rc = wolfTPM2_Init(&dev, NULL, NULL); if (rc != 0) { PRINTF("TPM init failed\n"); @@ -623,7 +659,7 @@ static int mqtt_tls_cb(MqttClient* client) return rc; } - //TODO: load key + /* load SRK and tpm key */ rc = wolfTPM2_CreateSRK(&dev, &storageKey, alg, (byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1); if (rc != 0) goto exit; @@ -635,7 +671,7 @@ static int mqtt_tls_cb(MqttClient* client) } printf("Loaded key to 0x%x\n", (word32)keyblob.handle.hndl); - //set auth + /* set authentication */ key.handle = keyblob.handle; key.pub = keyblob.pub; key.handle.auth.size = sizeof(gKeyAuth)-1; @@ -655,9 +691,9 @@ static int mqtt_tls_cb(MqttClient* client) goto exit; } - // load certificate + /* load certificate */ rc = wolfSSL_CTX_use_certificate_file(client->tls.ctx, - "tmp_certs_and_keys/client-rsa-cert.pem", + "client-rsa-cert.pem", WOLFSSL_FILETYPE_PEM); } @@ -744,7 +780,7 @@ int mqttsimple_test(void) mqttObj.publish.topic_name = MQTT_TOPIC_NAME; mqttObj.publish.packet_id = mqtt_get_packetid(); mqttObj.publish.buffer = (byte*)MQTT_PUBLISH_MSG; - mqttObj.publish.total_len = XSTRLEN(MQTT_PUBLISH_MSG); + mqttObj.publish.total_len = (word32)XSTRLEN(MQTT_PUBLISH_MSG); rc = MqttClient_Publish(&mClient, &mqttObj.publish); if (rc != MQTT_CODE_SUCCESS) { goto exit; @@ -781,6 +817,7 @@ int main(int argc, char** argv) int rc = -1; (void)argc; (void)argv; + wolfSSL_Debugging_ON(); rc = mqttsimple_test(); diff --git a/tpm/windows/README b/tpm/windows/README new file mode 100644 index 00000000..f99a923f --- /dev/null +++ b/tpm/windows/README @@ -0,0 +1,10 @@ + +1. `mkdir certs` +2. Generate csr using wolfTPM `csr.exe` +3. Process csr to generate certificate `client-rsa-cert.pem` +4. Open solution `tpm-examples/tpm-examples.sln` +5. Set host `MQTT_HOST` in `mqtt_tpm_simple.c` +6. For `curl_tpm`, copy server CA cert to ca-cert.pem or change path setting `CURLOPT_CAINFO` +7. Build solution + +After successfully building the example is ready to be run. \ No newline at end of file diff --git a/tpm/windows/curl_mqtt/curl_mqtt.vcxproj b/tpm/windows/curl_mqtt/curl_mqtt.vcxproj new file mode 100644 index 00000000..2bf5d6ee --- /dev/null +++ b/tpm/windows/curl_mqtt/curl_mqtt.vcxproj @@ -0,0 +1,148 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {e1a43ef4-8f19-449a-880a-aa04efe3b227} + curlmqtt + 10.0 + curl_tpm + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/tpm/windows/curl_mqtt/curl_tpm.cpp b/tpm/windows/curl_mqtt/curl_tpm.cpp new file mode 100644 index 00000000..ebbae289 --- /dev/null +++ b/tpm/windows/curl_mqtt/curl_tpm.cpp @@ -0,0 +1,411 @@ +/* OpenSSL specific */ + +#include +#ifndef WOLFTPM_USER_SETTINGS +#include +#endif +#include +#include + +#include +#include + + +TpmCryptoDevCtx tpmCtx; +WOLFTPM2_DEV dev; +WOLFTPM2_KEY storageKey; +WOLFTPM2_KEY key; +WOLFTPM2_KEYBLOB keyblob; +static const char gStorageKeyAuth[] = "ThisIsMyStorageKeyAuth"; +static const char gKeyAuth[] = "ThisIsMyKeyAuth"; + + +/* from certs/dummy-ecc.pem (as DER) */ +static const unsigned char DUMMY_ECC_KEY[] = { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x05, 0x0F, 0xEA, 0xB6, 0x2C, 0x7C, + 0xD3, 0x3C, 0x66, 0x3D, 0x6B, 0x44, 0xD5, 0x8A, 0xD4, 0x1C, 0xF6, 0x2A, 0x35, + 0x49, 0xB2, 0x36, 0x7D, 0xEC, 0xD4, 0xB3, 0x9A, 0x2B, 0x4F, 0x71, 0xC8, 0xD3, + 0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0xA1, + 0x44, 0x03, 0x42, 0x00, 0x04, 0x43, 0x98, 0xF7, 0x33, 0x77, 0xB4, 0x55, 0x02, + 0xF1, 0xF3, 0x79, 0x97, 0x67, 0xED, 0xB5, 0x3A, 0x7A, 0xE1, 0x7C, 0xC6, 0xA8, + 0x23, 0x8B, 0x3A, 0x68, 0x42, 0xDD, 0x68, 0x4F, 0x48, 0x6F, 0x2D, 0x9A, 0x7C, + 0x47, 0x20, 0x1F, 0x13, 0x69, 0x71, 0x05, 0x42, 0x5B, 0x9F, 0x23, 0x7D, 0xE0, + 0xA6, 0x5D, 0xD4, 0x11, 0x44, 0xB1, 0x91, 0x66, 0x50, 0xC0, 0x2C, 0x8C, 0x71, + 0x35, 0x0E, 0x28, 0xB4 +}; + +/* from certs/dummy-rsa.pem (as DER) */ +static const unsigned char DUMMY_RSA_KEY[] = { + 0x30, 0x82, 0x04, 0xA3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xCF, + 0xDD, 0xB2, 0x17, 0x49, 0xEB, 0xBF, 0xFB, 0xC5, 0x19, 0x13, 0x63, 0x86, 0x49, + 0xBC, 0xFE, 0x8E, 0xED, 0x21, 0x6E, 0x53, 0x18, 0x9C, 0x41, 0xD5, 0xEC, 0x12, + 0x31, 0xF0, 0xF9, 0x90, 0x08, 0x15, 0x68, 0x2F, 0x00, 0x9C, 0xAC, 0x36, 0x28, + 0xF6, 0xD8, 0x50, 0xA0, 0xD4, 0x7C, 0xDF, 0xE7, 0x0F, 0xE1, 0x36, 0xD1, 0xDD, + 0xC0, 0x2B, 0xF0, 0x3D, 0xC9, 0xF0, 0x5B, 0xE4, 0x76, 0x48, 0x91, 0xF0, 0x92, + 0x29, 0x82, 0x75, 0x7F, 0x0B, 0x41, 0x39, 0x77, 0x52, 0xCD, 0x1F, 0x30, 0xA3, + 0xC3, 0x79, 0x92, 0xBD, 0x0A, 0x7F, 0x16, 0xB2, 0x06, 0xFD, 0x49, 0xC5, 0x4D, + 0x34, 0x26, 0xDB, 0x49, 0x06, 0xDB, 0x49, 0x63, 0xB6, 0xE5, 0xA4, 0xEC, 0xC0, + 0x6D, 0x24, 0xF1, 0x82, 0x0F, 0x83, 0x1B, 0xB1, 0x0D, 0xA3, 0x8B, 0x6A, 0x39, + 0x39, 0xB6, 0xB3, 0xA3, 0xE1, 0x77, 0x69, 0x8C, 0xC7, 0x83, 0xE1, 0xBE, 0x9E, + 0xF9, 0xB7, 0xDB, 0xDF, 0xF8, 0x98, 0x7C, 0x9D, 0xC8, 0x72, 0x78, 0xBF, 0x13, + 0x62, 0x27, 0xA1, 0xBF, 0x4B, 0x2B, 0x04, 0x18, 0xCD, 0x2C, 0x10, 0x7E, 0xA5, + 0x33, 0x08, 0xD4, 0x49, 0xF1, 0xEC, 0x99, 0x6F, 0x2E, 0x0B, 0xB4, 0xD3, 0xB3, + 0xC2, 0x20, 0x02, 0xE9, 0x3A, 0xA1, 0xB3, 0x81, 0x9B, 0x0C, 0x02, 0xB0, 0xDE, + 0x9E, 0xEF, 0x0A, 0x47, 0x6E, 0xFA, 0xDB, 0x4D, 0x13, 0x1E, 0x1F, 0xD2, 0x7B, + 0xC6, 0x48, 0xE8, 0x27, 0xDE, 0xBC, 0x8D, 0x4C, 0x60, 0x5A, 0x71, 0xB5, 0xC3, + 0x7F, 0xFC, 0x7C, 0x28, 0xC1, 0x99, 0xF2, 0x7A, 0x3B, 0xCD, 0x6A, 0x76, 0xFE, + 0xA8, 0x9B, 0xDD, 0x03, 0x1E, 0xEB, 0xB4, 0x9D, 0x70, 0x5C, 0x7A, 0x1F, 0xB6, + 0x12, 0xEC, 0xCD, 0xAC, 0x6A, 0xCD, 0x2C, 0x25, 0x53, 0xEF, 0x34, 0xD5, 0xC5, + 0x97, 0x14, 0xD4, 0xB2, 0x86, 0x03, 0x5F, 0x89, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x82, 0x01, 0x00, 0x5D, 0x9E, 0xBF, 0x10, 0x48, 0x25, 0xDB, 0x00, 0xFD, + 0x43, 0x8E, 0xFC, 0xFB, 0x45, 0x88, 0xCE, 0xA9, 0xF6, 0xD9, 0x60, 0xC4, 0x22, + 0x48, 0x76, 0x4A, 0x70, 0x19, 0xBD, 0xCE, 0x87, 0xC8, 0x3C, 0x2B, 0xD0, 0x11, + 0xA3, 0x57, 0xED, 0x24, 0x33, 0x8D, 0x01, 0xDE, 0x46, 0xA1, 0x8D, 0x60, 0x96, + 0xC4, 0x0B, 0x2E, 0x52, 0x95, 0x6A, 0x71, 0x1F, 0xB1, 0xE4, 0x9A, 0xD1, 0xF8, + 0x72, 0xE1, 0xBA, 0x81, 0x3C, 0x83, 0x5F, 0x93, 0xA5, 0xD5, 0x9E, 0xD9, 0xD0, + 0x09, 0x46, 0x03, 0x6F, 0x37, 0xC2, 0xD9, 0xA5, 0xA2, 0x68, 0xF0, 0xD6, 0x7A, + 0xF6, 0x34, 0xEC, 0x1D, 0xE5, 0xE8, 0xC0, 0x3B, 0x71, 0x87, 0x9A, 0x0A, 0x52, + 0xD3, 0xD4, 0x58, 0x54, 0x9D, 0x52, 0x4B, 0x1A, 0x4E, 0xF6, 0xC7, 0x99, 0x18, + 0x44, 0x49, 0x4D, 0x88, 0x59, 0x1F, 0xCA, 0x4E, 0xDC, 0x57, 0xB7, 0x1D, 0x9D, + 0xDF, 0x59, 0x91, 0xD9, 0x2E, 0xE0, 0x54, 0xAA, 0x4E, 0x8F, 0x92, 0x82, 0x85, + 0x70, 0xF9, 0x93, 0x90, 0x3A, 0x30, 0xCD, 0xB3, 0x73, 0x81, 0x93, 0xE7, 0xF9, + 0x1F, 0xF6, 0xA9, 0xA9, 0xD4, 0xAE, 0x89, 0x0E, 0x38, 0x11, 0x61, 0xF7, 0xF7, + 0xDC, 0x9B, 0x99, 0x4B, 0xFE, 0xC0, 0x71, 0x78, 0x53, 0x18, 0x0F, 0x23, 0xA9, + 0x11, 0xA0, 0xAA, 0x57, 0xEE, 0x39, 0xAA, 0xEA, 0x2A, 0x7A, 0x8D, 0x12, 0x69, + 0x2C, 0x82, 0x4D, 0xA0, 0xE5, 0x1C, 0xB3, 0x69, 0x9D, 0xA1, 0x30, 0xA3, 0x40, + 0xFA, 0x86, 0x40, 0xD3, 0x8B, 0xF9, 0xAF, 0x98, 0x7D, 0x17, 0x07, 0xA3, 0x29, + 0xE2, 0x57, 0xEF, 0x47, 0xCF, 0x81, 0x22, 0x4D, 0x47, 0x63, 0xA4, 0x2F, 0x1A, + 0x8F, 0xC3, 0x26, 0x1F, 0xF6, 0xC5, 0x81, 0xFF, 0x14, 0xA9, 0x87, 0x56, 0x18, + 0x8A, 0x18, 0xFD, 0x37, 0xC3, 0x4B, 0x8E, 0xE0, 0x6B, 0x2C, 0x07, 0x4B, 0x05, + 0x02, 0x81, 0x81, 0x00, 0xED, 0x51, 0x06, 0x91, 0xB8, 0x94, 0x5E, 0x17, 0x9B, + 0x22, 0x25, 0xEF, 0x23, 0x76, 0x61, 0x26, 0xFA, 0xAC, 0xEE, 0xC1, 0x99, 0x8E, + 0x55, 0x38, 0x85, 0xD2, 0x15, 0x06, 0x6E, 0xBB, 0x45, 0xBB, 0xFE, 0x5F, 0xF7, + 0xD2, 0xA4, 0x41, 0x15, 0x24, 0x67, 0x8E, 0xA2, 0x6B, 0xBA, 0xAA, 0x28, 0x84, + 0x22, 0x63, 0xEE, 0xA8, 0xA0, 0xD0, 0xEA, 0x47, 0x8C, 0xAC, 0x4E, 0x98, 0x18, + 0x8A, 0xF2, 0x19, 0x76, 0x50, 0x9D, 0xFE, 0xD1, 0x59, 0xC3, 0xC1, 0x23, 0x3B, + 0x31, 0x73, 0xC7, 0x71, 0x3E, 0x94, 0xC8, 0x6D, 0x7F, 0xBA, 0x30, 0xF2, 0x4C, + 0x1A, 0x7E, 0x74, 0x52, 0x78, 0xA0, 0xAB, 0x69, 0x0C, 0x44, 0x59, 0xD0, 0xB0, + 0xFE, 0x2F, 0xE8, 0xC2, 0x18, 0xE7, 0x24, 0x8B, 0x73, 0xDF, 0x4F, 0x40, 0x92, + 0x0C, 0x8C, 0x6C, 0x92, 0x27, 0xBC, 0x3F, 0x5B, 0x79, 0x44, 0xC1, 0x32, 0xCC, + 0xA2, 0xB7, 0x02, 0x81, 0x81, 0x00, 0xE0, 0x3B, 0x1C, 0xC4, 0xC4, 0x69, 0x0D, + 0x6B, 0x57, 0x19, 0xB7, 0x59, 0x18, 0x92, 0xB2, 0x09, 0x39, 0x66, 0x97, 0xD1, + 0x18, 0xDE, 0x6B, 0x5F, 0xC5, 0x9B, 0x11, 0x47, 0x1E, 0xEA, 0xE3, 0xAC, 0x36, + 0x2B, 0x30, 0x99, 0x81, 0x00, 0x3D, 0x39, 0x41, 0x03, 0x90, 0x77, 0xDE, 0x4A, + 0xE1, 0x48, 0xDF, 0x98, 0x86, 0x03, 0x3B, 0xEA, 0xAF, 0xC8, 0xF6, 0xD7, 0x4F, + 0xE6, 0xAE, 0x70, 0xF2, 0x3D, 0xBB, 0xF2, 0x63, 0xB9, 0x2D, 0x3C, 0x08, 0xB3, + 0x10, 0x9E, 0x97, 0x6C, 0x8D, 0x28, 0x34, 0xAE, 0xDA, 0xD9, 0xA1, 0x8E, 0x3A, + 0x51, 0x7A, 0xA1, 0x14, 0x3F, 0xFB, 0xEA, 0x3B, 0xB4, 0x93, 0xAA, 0x14, 0x7A, + 0xB4, 0xD7, 0xCA, 0x7B, 0x61, 0xAF, 0xF5, 0x87, 0x1A, 0x64, 0xA9, 0x3E, 0x3C, + 0x7A, 0xDD, 0x11, 0x7F, 0x01, 0x2D, 0xA6, 0x91, 0xED, 0x3D, 0x28, 0x9C, 0x67, + 0xC2, 0x5C, 0xCF, 0xBF, 0x02, 0x81, 0x81, 0x00, 0xCE, 0x0C, 0x59, 0xCD, 0xD0, + 0x1B, 0x52, 0x0E, 0xE0, 0xED, 0x27, 0x4E, 0x98, 0xD5, 0xC1, 0xC8, 0x9C, 0x41, + 0xE6, 0x13, 0x46, 0x06, 0x24, 0xCC, 0x2C, 0xB4, 0x98, 0xF8, 0xBA, 0xCF, 0xF2, + 0xDE, 0x25, 0x20, 0xA2, 0x05, 0xCC, 0x03, 0x8E, 0x1D, 0xCB, 0xA4, 0x36, 0x35, + 0x9F, 0x1E, 0xFA, 0x8A, 0xAF, 0x69, 0x60, 0xE0, 0x1C, 0xB1, 0x07, 0x99, 0x13, + 0xF4, 0xCF, 0x50, 0x93, 0x8E, 0xA0, 0x61, 0xA7, 0x2E, 0x9B, 0xDF, 0x91, 0x59, + 0x84, 0xF3, 0x7E, 0x69, 0x78, 0xA8, 0x73, 0xF4, 0x49, 0x47, 0xD9, 0x35, 0xE9, + 0x7E, 0x79, 0xDD, 0x06, 0x62, 0xC2, 0x84, 0xB0, 0xCE, 0x77, 0x82, 0x1C, 0x75, + 0x40, 0x2B, 0x53, 0x5D, 0x39, 0x75, 0xD3, 0x7C, 0x23, 0x2F, 0x1D, 0xB5, 0xCE, + 0xE7, 0x86, 0xE2, 0x23, 0x6C, 0xAD, 0xC7, 0xDE, 0xA6, 0x8D, 0x75, 0xDD, 0x30, + 0x4F, 0x98, 0x07, 0x49, 0x51, 0xC5, 0x02, 0x81, 0x80, 0x46, 0x19, 0x34, 0xBD, + 0x2E, 0xC9, 0xC8, 0xB0, 0x2D, 0xE2, 0x94, 0x36, 0xFE, 0x3F, 0x9D, 0xF8, 0xD4, + 0x41, 0x06, 0x65, 0x0F, 0xE9, 0x38, 0x98, 0x10, 0x26, 0x92, 0x18, 0x31, 0xCA, + 0x2C, 0xB2, 0xC1, 0x9C, 0x6E, 0xED, 0x0E, 0x2F, 0x0C, 0xF4, 0xC1, 0x26, 0x64, + 0x1B, 0x95, 0x1A, 0xC3, 0xA3, 0x0C, 0x83, 0x9A, 0x21, 0x98, 0xB1, 0x9D, 0x92, + 0xAD, 0xD8, 0x51, 0xDA, 0x43, 0xDE, 0x7B, 0x5C, 0x61, 0x4D, 0x3D, 0x6F, 0xBE, + 0x7C, 0x6E, 0x1B, 0xCC, 0xAE, 0x47, 0x98, 0x5F, 0xE8, 0x99, 0xCF, 0xB0, 0x0B, + 0x29, 0x3E, 0x55, 0x6C, 0xF3, 0x71, 0x37, 0xEB, 0x68, 0xCD, 0xA9, 0x2C, 0xA2, + 0x9D, 0x21, 0x19, 0xDB, 0x3F, 0x3A, 0xC5, 0xA7, 0x9C, 0x62, 0x9D, 0x81, 0xDA, + 0xC6, 0x2D, 0xF6, 0xAA, 0x52, 0x42, 0x0D, 0xFA, 0x48, 0x53, 0x32, 0x7B, 0x80, + 0x0B, 0x1A, 0x1A, 0x35, 0xE0, 0xDD, 0xF1, 0x02, 0x81, 0x80, 0x76, 0x46, 0xB9, + 0x57, 0x91, 0x3F, 0x64, 0x5D, 0x42, 0x37, 0x70, 0x9D, 0x44, 0x38, 0x09, 0x09, + 0x42, 0x3E, 0x2E, 0x8A, 0x7A, 0xA4, 0x57, 0x4B, 0x81, 0x95, 0x65, 0x47, 0x3C, + 0xF3, 0x77, 0x54, 0xE3, 0x7D, 0xEC, 0x06, 0xC9, 0x26, 0xAB, 0xDD, 0x66, 0x73, + 0x54, 0x86, 0x31, 0x26, 0x75, 0x5B, 0x84, 0xAB, 0xD2, 0xA2, 0x6A, 0x9B, 0x6E, + 0xDD, 0x45, 0xAE, 0x81, 0x49, 0x12, 0x8D, 0x03, 0x1C, 0x1B, 0x6B, 0x5B, 0x37, + 0xFA, 0xE7, 0x05, 0x9F, 0xBD, 0x66, 0xDD, 0x6C, 0xD7, 0x16, 0x0D, 0xCC, 0x64, + 0x19, 0xC2, 0xCD, 0xC3, 0xA9, 0xED, 0x70, 0xFA, 0x75, 0xD8, 0x41, 0xF7, 0xC6, + 0x84, 0xE8, 0x40, 0xF0, 0xE5, 0x93, 0x88, 0xE2, 0x4E, 0x4F, 0xE4, 0x5F, 0xDF, + 0x53, 0xAB, 0xA7, 0x06, 0xDC, 0x64, 0x7E, 0x51, 0xE8, 0x7E, 0x1C, 0x33, 0x9F, + 0xBF, 0x5E, 0x58, 0xBC, 0x7D, 0xA3, 0x80, 0x84 +}; + + +/* Function checks key to see if its the "dummy" key */ +static inline int myTpmCheckKey(wc_CryptoInfo* info, TpmCryptoDevCtx* ctx) +{ + int ret = 0; + +#ifndef NO_RSA + if (info && info->pk.type == WC_PK_TYPE_RSA) { + byte e[sizeof(word32)], e2[sizeof(word32)]; + byte n[WOLFTPM2_WRAP_RSA_KEY_BITS / 8], n2[WOLFTPM2_WRAP_RSA_KEY_BITS / 8]; + word32 eSz = sizeof(e), e2Sz = sizeof(e); + word32 nSz = sizeof(n), n2Sz = sizeof(n); + RsaKey rsakey; + word32 idx = 0; + + /* export the raw public RSA portion */ + ret = wc_RsaFlattenPublicKey(info->pk.rsa.key, e, &eSz, n, &nSz); + if (ret == 0) { + /* load the modulus for the dummy key */ + ret = wc_InitRsaKey(&rsakey, NULL); + if (ret == 0) { + ret = wc_RsaPrivateKeyDecode(DUMMY_RSA_KEY, &idx, &rsakey, + (word32)sizeof(DUMMY_RSA_KEY)); + if (ret == 0) { + ret = wc_RsaFlattenPublicKey(&rsakey, e2, &e2Sz, n2, &n2Sz); + } + wc_FreeRsaKey(&rsakey); + } + } + + if (ret == 0 && XMEMCMP(n, n2, nSz) == 0) { +#ifdef DEBUG_WOLFTPM + printf("Detected dummy key, so using TPM RSA key handle\n"); +#endif + ret = 1; + } + } +#endif +#if defined(HAVE_ECC) + if (info && info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + byte qx[WOLFTPM2_WRAP_ECC_KEY_BITS / 8], qx2[WOLFTPM2_WRAP_ECC_KEY_BITS / 8]; + byte qy[WOLFTPM2_WRAP_ECC_KEY_BITS / 8], qy2[WOLFTPM2_WRAP_ECC_KEY_BITS / 8]; + word32 qxSz = sizeof(qx), qx2Sz = sizeof(qx2); + word32 qySz = sizeof(qy), qy2Sz = sizeof(qy2); + ecc_key eccKey; + word32 idx = 0; + + /* export the raw public ECC portion */ + ret = wc_ecc_export_public_raw(info->pk.eccsign.key, qx, &qxSz, qy, &qySz); + if (ret == 0) { + /* load the ECC public x/y for the dummy key */ + ret = wc_ecc_init(&eccKey); + if (ret == 0) { + ret = wc_EccPrivateKeyDecode(DUMMY_ECC_KEY, &idx, &eccKey, + (word32)sizeof(DUMMY_ECC_KEY)); + if (ret == 0) { + ret = wc_ecc_export_public_raw(&eccKey, qx2, &qx2Sz, qy2, &qy2Sz); + } + wc_ecc_free(&eccKey); + } + } + + if (ret == 0 && XMEMCMP(qx, qx2, qxSz) == 0 && + XMEMCMP(qy, qy2, qySz) == 0) { +#ifdef DEBUG_WOLFTPM + printf("Detected dummy key, so using TPM ECC key handle\n"); +#endif + ret = 1; + } + } +#endif + (void)info; + (void)ctx; + + /* non-zero return code means its a "dummy" key (not valid) and the + provided TPM handle will be used, not the wolf public key info */ + return ret; +} + + +static int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key) +{ + int rc = 0; +#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) + XFILE fp = NULL; + size_t fileSz = 0; + size_t bytes_read = 0; + byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; + int pubAreaSize; + + XMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB)); + + fp = XFOPEN(filename, "rb"); + if (fp != XBADFILE) { + XFSEEK(fp, 0, XSEEK_END); + fileSz = XFTELL(fp); + XREWIND(fp); + if (fileSz > sizeof(key->priv) + sizeof(key->pub)) { + printf("File size check failed\n"); + rc = BUFFER_E; goto exit; + } + printf("Reading %d bytes from %s\n", (int)fileSz, filename); + + bytes_read = XFREAD(&key->pub.size, 1, sizeof(key->pub.size), fp); + if (bytes_read != sizeof(key->pub.size)) { + printf("Read %zu, expected size marker of %zu bytes\n", + bytes_read, sizeof(key->pub.size)); + goto exit; + } + fileSz -= bytes_read; + + bytes_read = XFREAD(pubAreaBuffer, 1, sizeof(UINT16) + key->pub.size, fp); + if (bytes_read != sizeof(UINT16) + key->pub.size) { + printf("Read %zu, expected public blob %zu bytes\n", + bytes_read, sizeof(UINT16) + key->pub.size); + goto exit; + } + fileSz -= bytes_read; /* Reminder bytes for private key part */ + + /* Decode the byte stream into a publicArea structure ready for use */ + rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer, + (word32)sizeof(pubAreaBuffer), &pubAreaSize); + if (rc != TPM_RC_SUCCESS) return rc; +#ifdef DEBUG_WOLFTPM + //TPM2_PrintPublicArea(&key->pub); +#endif + + if (fileSz > 0) { + printf("Reading the private part of the key\n"); + bytes_read = XFREAD(&key->priv, 1, fileSz, fp); + if (bytes_read != fileSz) { + printf("Read %zu, expected private blob %zu bytes\n", + bytes_read, fileSz); + goto exit; + } + rc = 0; /* success */ + } + + /* sanity check the sizes */ + if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size)) || + key->priv.size > sizeof(key->priv.buffer)) { + printf("Struct size check failed (pub %d, priv %d)\n", + key->pub.size, key->priv.size); + rc = BUFFER_E; + } + } + else { + rc = BUFFER_E; + printf("File %s not found!\n", filename); + printf("Keys can be generated by running:\n" + " ./examples/keygen/keygen rsa_test_blob.raw -rsa -t\n" + " ./examples/keygen/keygen ecc_test_blob.raw -ecc -t\n"); + } + +exit: + if (fp) + XFCLOSE(fp); +#else + (void)filename; + (void)key; +#endif /* !NO_FILESYSTEM && !NO_WRITE_TEMP_FILES */ + return rc; +} + +static CURLcode sslctx_function(CURL* curl, void* sslctx, void* parm) +{ + + int rc = WOLFSSL_SUCCESS; + TPM_ALG_ID alg = TPM_ALG_RSA; + int tpmDevId; + WOLFSSL_CTX *ctx = (WOLFSSL_CTX*)sslctx; + + wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL); + wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_CHECKALL); + wolfSSL_CTX_EnableOCSPStapling(ctx); + + rc = readKeyBlob("rsa_test_blob.raw", &keyblob); + + /* Initi TPM */ + rc = wolfTPM2_Init(&dev, NULL, NULL); + if (rc != 0) { + printf("TPM init failed\n"); + goto exit; + } + + tpmCtx.rsaKey = &key; + tpmCtx.checkKeyCb = myTpmCheckKey; /* detects if using "dummy" key */ + tpmCtx.storageKey = &storageKey; + + rc = wolfTPM2_SetCryptoDevCb(&dev, wolfTPM2_CryptoDevCb, &tpmCtx, &tpmDevId); + if (rc != 0) { + printf("wolfTPM2_SetCryptoDevCb failed\n"); + goto exit; + } + + // load key + rc = wolfTPM2_CreateSRK(&dev, &storageKey, alg, + (byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth) - 1); + if (rc != 0) goto exit; + + rc = wolfTPM2_LoadKey(&dev, &keyblob, &storageKey.handle); + if (rc != TPM_RC_SUCCESS) { + printf("wolfTPM2_LoadKey failed\n"); + goto exit; + } + printf("Loaded key to 0x%x\n", (word32)keyblob.handle.hndl); + + //set auth + key.handle = keyblob.handle; + key.pub = keyblob.pub; + key.handle.auth.size = sizeof(gKeyAuth) - 1; + XMEMCPY(key.handle.auth.buffer, gKeyAuth, key.handle.auth.size); + + /* Setup DevID */ + wolfSSL_CTX_SetDevId(ctx, tpmDevId); + + printf("Loading RSA dummy key\n"); + + /* Private key is on TPM and crypto dev callbacks are used */ + /* TLS client (mutual auth) requires a dummy key loaded (workaround) */ + if (wolfSSL_CTX_use_PrivateKey_buffer(ctx, DUMMY_RSA_KEY, + sizeof(DUMMY_RSA_KEY), WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { + printf("Failed to set key!\r\n"); + goto exit; + } + + // load certificate + rc = wolfSSL_CTX_use_certificate_file(ctx, + "client-rsa-cert.pem", + WOLFSSL_FILETYPE_PEM); +exit: + printf("TLS Setup (%d)", rc); + + /* all set to go */ + if (rc == WOLFSSL_SUCCESS) + return CURLE_OK; + else + return CURLE_SSL_ENGINE_INITFAILED; +} + +int main(void) +{ + CURL* ch; + CURLcode rv; + + wolfSSL_Debugging_ON(); + + curl_global_init(CURL_GLOBAL_ALL); + ch = curl_easy_init(); + + //curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + //curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(ch, CURLOPT_CAINFO, "ca-cert.pem"); + curl_easy_setopt(ch, CURLOPT_URL, "https://example.com:11111"); + + /* Retrieve page using cacerts' certificate -> will succeed + * load the certificate by installing a function doing the necessary + * "modifications" to the SSL CONTEXT just before link init + * + */ + rv = curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); + //curl_easy_setopt(ch, CURLOPT_SSL_CTX_DATA, mypem); + rv = curl_easy_perform(ch); + if (!rv) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + if (storageKey.handle.hndl) { + wolfTPM2_UnloadHandle(&dev, &storageKey.handle); + } + if (key.handle.hndl) { + wolfTPM2_UnloadHandle(&dev, &key.handle); + } + + curl_easy_cleanup(ch); + curl_global_cleanup(); + return rv; +} \ No newline at end of file diff --git a/tpm/windows/mqtt_tpm/mqtt_tpm.vcxproj b/tpm/windows/mqtt_tpm/mqtt_tpm.vcxproj new file mode 100644 index 00000000..e0d6d055 --- /dev/null +++ b/tpm/windows/mqtt_tpm/mqtt_tpm.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 16.0 + Win32Proj + {bbaf23b5-7c6c-4d65-a4e0-f7ec91200c13} + mqtttpm + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(IncludePath) + $(LibraryPath) + + + false + + + true + $(IncludePath) + $(LibraryPath) + + + false + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;ENABLE_MQTT_TLS;WOLFTPM_USER_SETTINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + wolfmqtt.lib;wolftpm.lib;wolfssl.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/tpm/windows/tpm-examples.sln b/tpm/windows/tpm-examples.sln new file mode 100644 index 00000000..5f490596 --- /dev/null +++ b/tpm/windows/tpm-examples.sln @@ -0,0 +1,47 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31205.134 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl_tpm", "curl_mqtt\curl_mqtt.vcxproj", "{E1A43EF4-8F19-449A-880A-AA04EFE3B227}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mqtt_tpm", "mqtt_tpm\mqtt_tpm.vcxproj", "{BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Debug|x64.ActiveCfg = Debug|x64 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Debug|x64.Build.0 = Debug|x64 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Debug|x86.ActiveCfg = Debug|Win32 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Debug|x86.Build.0 = Debug|Win32 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Release|Any CPU.ActiveCfg = Release|Win32 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Release|x64.ActiveCfg = Release|x64 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Release|x64.Build.0 = Release|x64 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Release|x86.ActiveCfg = Release|Win32 + {E1A43EF4-8F19-449A-880A-AA04EFE3B227}.Release|x86.Build.0 = Release|Win32 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Debug|x64.ActiveCfg = Debug|x64 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Debug|x64.Build.0 = Debug|x64 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Debug|x86.ActiveCfg = Debug|Win32 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Debug|x86.Build.0 = Debug|Win32 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Release|Any CPU.ActiveCfg = Release|Win32 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Release|x64.ActiveCfg = Release|x64 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Release|x64.Build.0 = Release|x64 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Release|x86.ActiveCfg = Release|Win32 + {BBAF23B5-7C6C-4D65-A4E0-F7EC91200C13}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AB29BB26-A279-4020-BAF3-C25FDEB7ED24} + EndGlobalSection +EndGlobal From b660243542b9a82ac750041215ddaf66d170e426 Mon Sep 17 00:00:00 2001 From: Elms Date: Fri, 13 May 2022 15:17:34 -0700 Subject: [PATCH 3/5] tpm: curl nits --- tpm/windows/curl_mqtt/curl_tpm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tpm/windows/curl_mqtt/curl_tpm.cpp b/tpm/windows/curl_mqtt/curl_tpm.cpp index ebbae289..84d4d7ea 100644 --- a/tpm/windows/curl_mqtt/curl_tpm.cpp +++ b/tpm/windows/curl_mqtt/curl_tpm.cpp @@ -1,6 +1,7 @@ -/* OpenSSL specific */ +/* wolfSSL specific with TPM callbacks*/ #include + #ifndef WOLFTPM_USER_SETTINGS #include #endif @@ -391,7 +392,6 @@ int main(void) * */ rv = curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); - //curl_easy_setopt(ch, CURLOPT_SSL_CTX_DATA, mypem); rv = curl_easy_perform(ch); if (!rv) printf("*** transfer succeeded ***\n"); From b45dfbace5aa1ffe361326c0a9db1110c6599833 Mon Sep 17 00:00:00 2001 From: Elms Date: Fri, 13 May 2022 17:08:38 -0700 Subject: [PATCH 4/5] tpm: testing linux and fixes --- tpm/mqtt/Makefile | 6 +++++- tpm/mqtt/mqtt_tpm_simple.c | 23 +++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/tpm/mqtt/Makefile b/tpm/mqtt/Makefile index 049ac293..b4712ee1 100644 --- a/tpm/mqtt/Makefile +++ b/tpm/mqtt/Makefile @@ -1,3 +1,7 @@ +CC=gcc +WOLF_INSTALL_DIR=/usr/local +CFLAGS=-I$(WOLF_INSTALL_DIR)/include -Wall -DCERT_PATH=\"tmp_certs_and_keys/\" +LIBS=-L$(WOLF_INSTALL_DIR)/lib -lwolfssl -lwolftpm -lwolfmqtt mqtt_tpm_simple: mqtt_tpm_simple.c - gcc $^ -g -o $@ -I inst/include -L inst/lib -lwolfssl -lwolftpm -lwolfmqtt + gcc $^ -g -o $@ $(CFLAGS) $(LIBS) diff --git a/tpm/mqtt/mqtt_tpm_simple.c b/tpm/mqtt/mqtt_tpm_simple.c index 46300e97..823629ca 100644 --- a/tpm/mqtt/mqtt_tpm_simple.c +++ b/tpm/mqtt/mqtt_tpm_simple.c @@ -36,6 +36,7 @@ #include #include +#define SOCKET int #define CLOSE_SOCKET(sock) close(sock) #endif @@ -166,16 +167,18 @@ static int mqtt_net_connect(void *context, const char* host, word16 port, struct addrinfo *result = NULL; struct addrinfo hints; +#ifdef _WIN32 { - WORD wVersionRequested; - WSADATA wsaData; - int err; + WORD wVersionRequested; + WSADATA wsaData; + int err; - /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ - wVersionRequested = MAKEWORD(2, 2); + /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ + wVersionRequested = MAKEWORD(2, 2); - err = WSAStartup(wVersionRequested, &wsaData); + err = WSAStartup(wVersionRequested, &wsaData); } +#endif if (pSockFd == NULL) { return MQTT_CODE_ERROR_BAD_ARG; @@ -619,10 +622,10 @@ static int mqtt_tls_cb(MqttClient* client) int tpmDevId; -#ifdef WOLFSSL_RSA - rc = readKeyBlob("rsa_test_blob.raw", &keyblob); +#ifndef NO_RSA + rc = readKeyBlob(CERT_PATH "rsa_test_blob.raw", &keyblob); #else - rc = readKeyBlob("ecc_test_blob.raw", &keyblob); + rc = readKeyBlob(CERT_PATH "ecc_test_blob.raw", &keyblob); #endif /* Use highest available and allow downgrade. If wolfSSL is built with @@ -693,7 +696,7 @@ static int mqtt_tls_cb(MqttClient* client) /* load certificate */ rc = wolfSSL_CTX_use_certificate_file(client->tls.ctx, - "client-rsa-cert.pem", + CERT_PATH "client-rsa-cert.pem", WOLFSSL_FILETYPE_PEM); } From 69704c28e892f3eb99f96c3551777ed1cdc12a64 Mon Sep 17 00:00:00 2001 From: Elms Date: Wed, 18 May 2022 12:26:52 -0700 Subject: [PATCH 5/5] windows fixes --- tpm/mqtt/mqtt_tpm_simple.c | 3 +++ tpm/windows/README | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tpm/mqtt/mqtt_tpm_simple.c b/tpm/mqtt/mqtt_tpm_simple.c index 823629ca..9b6971b2 100644 --- a/tpm/mqtt/mqtt_tpm_simple.c +++ b/tpm/mqtt/mqtt_tpm_simple.c @@ -51,6 +51,9 @@ #include "wolftpm/tpm2.h" #include "wolftpm/tpm2_wrap.h" +#ifndef CERT_PATH +# define CERT_PATH "" +#endif /* Configuration */ #define MQTT_HOST "127.0.0.1" diff --git a/tpm/windows/README b/tpm/windows/README index f99a923f..18ae8939 100644 --- a/tpm/windows/README +++ b/tpm/windows/README @@ -2,9 +2,11 @@ 1. `mkdir certs` 2. Generate csr using wolfTPM `csr.exe` 3. Process csr to generate certificate `client-rsa-cert.pem` -4. Open solution `tpm-examples/tpm-examples.sln` +4. Open solution `tpm-examples.sln` 5. Set host `MQTT_HOST` in `mqtt_tpm_simple.c` 6. For `curl_tpm`, copy server CA cert to ca-cert.pem or change path setting `CURLOPT_CAINFO` 7. Build solution -After successfully building the example is ready to be run. \ No newline at end of file +After building the example is ready to be run. Note that projects are +setup to run in this directory, so certs and keyblobs should be copied +here if necessary. \ No newline at end of file