Commit c4497f62 authored by Cody Cutler's avatar Cody Cutler

Add ability to use TPM to tmcc/tmcd, necessary build system changes

(including an update to make schemacheck happy), and client-side script
modifications.

Tested by me on a few different machines. Ok by Mike.
parent 20bca221
......@@ -43,6 +43,7 @@
#undef ELVIN_COMPAT
#undef ISOLATEADMINS
#undef DYNAMICROOTPASSWORDS
#undef TPM
#undef HAVE_SRANDOMDEV
......
......@@ -1538,6 +1538,7 @@ PELABSUPPORT=0
ELVIN_COMPAT=0
ISOLATEADMINS=1
DYNAMICROOTPASSWORDS=1
TPM=0
REMOTEWIKIDOCS=1
PROTOGENI_SUPPORT=0
PROTOGENI_CLEARINGHOUSE=0
......@@ -1770,6 +1771,13 @@ if test $DYNAMICROOTPASSWORDS -eq 1; then
EOF
fi
if test $TPM -eq 1; then
cat >> confdefs.h <<EOF
#define TPM 1
EOF
fi
LOG_TESTBED=`echo "LOG_$TBLOGFACIL" | tr a-z A-Z`
cat >> confdefs.h <<EOF
......@@ -3052,6 +3060,7 @@ s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
s%@INSTALL_DATA@%$INSTALL_DATA%g
s%@RSYNC@%$RSYNC%g
s%@DISTCLEAN_FILES@%$DISTCLEAN_FILES%g
s%@TPM@%$TPM%g
CEOF
EOF
......
......@@ -206,6 +206,7 @@ AC_SUBST(PELABSUPPORT)
AC_SUBST(ELVIN_COMPAT)
AC_SUBST(ISOLATEADMINS)
AC_SUBST(DYNAMICROOTPASSWORDS)
AC_SUBST(TPM)
AC_SUBST(REMOTEWIKIDOCS)
AC_SUBST(PROTOGENI_SUPPORT)
AC_SUBST(PROTOGENI_CLEARINGHOUSE)
......@@ -291,6 +292,7 @@ PELABSUPPORT=0
ELVIN_COMPAT=0
ISOLATEADMINS=1
DYNAMICROOTPASSWORDS=1
TPM=0
REMOTEWIKIDOCS=1
PROTOGENI_SUPPORT=0
PROTOGENI_CLEARINGHOUSE=0
......@@ -411,6 +413,10 @@ fi
if test $DYNAMICROOTPASSWORDS -eq 1; then
AC_DEFINE_UNQUOTED(DYNAMICROOTPASSWORDS, 1)
fi
if test $TPM -eq 1; then
AC_DEFINE_UNQUOTED(TPM, 1)
fi
LOG_TESTBED=`echo "LOG_$TBLOGFACIL" | tr a-z A-Z`
AC_DEFINE_UNQUOTED(LOG_TESTBED, $LOG_TESTBED)
......
......@@ -2058,6 +2058,8 @@ CREATE TABLE `node_hostkeys` (
`sshrsa_v1` mediumtext,
`sshrsa_v2` mediumtext,
`sshdsa_v2` mediumtext,
`tpmblob` mediumtext,
`tpmx509` mediumtext,
`sfshostid` varchar(128) default NULL,
PRIMARY KEY (`node_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
......
#
# Updates to add support for TPM info
#
use strict;
use libdb;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
#
# Update the schema...
#
# Add a new osfeature
DBQueryFatal("ALTER TABLE node_hostkeys ADD COLUMN" .
" tpmblob mediumtext");
DBQueryFatal("ALTER TABLE node_hostkeys ADD COLUMN" .
" tpmx509 mediumtext");
return 0;
}
1;
......@@ -35,6 +35,8 @@ CFLAGS += -DETCDIR='"$(INSTALL_ETCDIR)"'
SSLFLAGS = -DWITHSSL
TMLIBS += -lssl -lcrypto
SSLOBJ = ssl.o
TPMOBJ = tpm.o
NOTPM = notpm
ifeq ($(SYSTEM),Linux)
ifneq ($(LDSTATIC),)
......@@ -104,9 +106,9 @@ ifeq ($(EVENTSYS),1)
ELVINFLAGS = -lm -L/usr/local/lib -lpubsub
endif
tmcd: tmcd.c ${TMCDLIBS} decls.h version.o $(SSLOBJ) $(BOOTINFO)
tmcd: tmcd.c ${TMCDLIBS} decls.h version.o $(SSLOBJ) $(BOOTINFO) $(NOTPM)
$(CC) $(CFLAGS) $(SSLFLAGS) $(TMCDCFLAGS) -o tmcd $< \
version.o $(SSLOBJ) $(BOOTINFO) \
version.o $(SSLOBJ) $(TPMOBJ) $(BOOTINFO) \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient \
$(ELVINFLAGS) $(TMCDLDFLAGS) $(TMCDLIBS) $(TMLIBS)
......@@ -115,27 +117,29 @@ mod_tmcd.so: libtmcd.o
-L /usr/local/lib -lxml2 $(SSLOBJ) \
$(ELVINFLAGS) $(TMCDLDFLAGS) $(TMCDLIBS) $(TMLIBS) $<
newtmcd: newtmcd.c libtmcd.o ${TMCDLIBS} decls.h version.o $(SSLOBJ) $(BOOTINFO)
newtmcd: newtmcd.c libtmcd.o ${TMCDLIBS} decls.h version.o $(SSLOBJ) \
$(NOTPMOBJ) $(BOOTINFO)
$(CC) $(CFLAGS) $(SSLFLAGS) $(TMCDCFLAGS) -o tmcd $< \
libtmcd.o version.o $(SSLOBJ) $(BOOTINFO) \
libtmcd.o version.o $(SSLOBJ) $(TPMOBJ) $(BOOTINFO) \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient -lxml2 \
$(ELVINFLAGS) $(TMCDLDFLAGS) $(TMCDLIBS) $(TMLIBS)
libtmcd.o: libtmcd.c ${TMCDLIBS} decls.h version.o $(SSLOBJ) $(BOOTINFO)
$(CC) $(CFLAGS) -I/usr/local/include/libxml2 $(SSLFLAGS) $(TMCDCFLAGS) -c -o libtmcd.o $<
$(CC) $(CFLAGS) -I/usr/local/include/libxml2 $(SSLFLAGS) \
$(TMCDCFLAGS) -c -o libtmcd.o $<
libtmcd.so: libtmcd.o ${TMCDLIBS} decls.h $(BOOTINFO)
$(LD) -shared $^ -L/usr/local/lib/mysql -lxml2 -lmysqlclient \
$(TMCDLIBS) $(ELVINFLAGS) ../lib/libtb/libtb.a \
-o $@
tmcc: tmcc.c decls.h $(SSLOBJ)
$(CC) $(CFLAGS) $(SSLFLAGS) $(LDSTATIC) -g -o tmcc $< $(SSLOBJ) \
$(LFLAGS) $(TMLIBS)
tmcc: tmcc.c decls.h $(SSLOBJ) $(TPMOBJ)
$(CC) $(CFLAGS) $(SSLFLAGS) $(LDSTATIC) -g -o tmcc \
$< $(SSLOBJ) $(TPMOBJ) $(LFLAGS) $(TMLIBS)
tmcc-shared: tmcc.c decls.h $(SSLOBJ)
tmcc-shared: tmcc.c decls.h $(SSLOBJ) $(TPMOBJ)
$(CC) $(CFLAGS) $(SSLFLAGS) -g -o tmcc $< $(SSLOBJ) \
$(LFLAGS) $(TMLIBS)
$(TPMOBJ) $(LFLAGS) $(TMLIBS)
tmcc-nossl-debug: tmcc.c decls.h
$(CC) $(CFLAGS) $(LDSTATIC) -g -o $@ $< $(LFLAGS) $(TMSLIBS)
......@@ -148,6 +152,14 @@ dostype-debug: dostype.o
ssl.o: ssl.c ssl.h decls.h
tpm.o: tpm.c tpm.h
$(CC) -c $(CFLAGS) $(TESTBED_SRCDIR)/tmcd/tpm.c \
-I$(TESTBED_SRCDIR)/tmcd/
notpm: tpm.c tpm.h
$(CC) -c $(CFLAGS) -DTPMOVERRIDE $(TESTBED_SRCDIR)/tmcd/tpm.c \
-I$(TESTBED_SRCDIR)/tmcd/
version.c: tmcd.c
echo >$@ "char build_info[] = \"Built `date +%d-%b-%Y` by `id -nu`@`hostname | sed 's/\..*//'`:`pwd`\";"
......
......@@ -23,7 +23,8 @@ SCRIPTS = $(addprefix $(SRCDIR)/, \
rc.syncserver rc.linkagent rc.mkelab rc.localize \
rc.keys rc.trafgen rc.tarfiles rc.rpms rc.progagent \
rc.startcmd rc.simulator rc.topomap rc.firewall \
rc.tiptunnels rc.trace rc.motelog rc.fakejail)
rc.tiptunnels rc.trace rc.motelog rc.fakejail \
rc.tpmsetup)
include $(OBJDIR)/Makeconf
......
......@@ -97,14 +97,15 @@ elsif (WINDOWS()) {
"rc.tarfiles", "rc.rpms");
}
else {
@bootscripts = ("rc.firewall",
@bootscripts = ("rc.firewall", "rc.tpmsetup",
"rc.misc", "rc.localize", "rc.keys", "rc.mounts",
"rc.topomap", "rc.accounts",
"rc.route", "rc.tunnels", "rc.ifconfig", "rc.delays",
"rc.hostnames", "rc.trace",
"rc.syncserver", "rc.trafgen",
"rc.tarfiles", "rc.rpms", "rc.progagent", "rc.linkagent",
"rc.tiptunnels", "rc.motelog", "rc.simulator");
"rc.tiptunnels", "rc.motelog", "rc.simulator"
);
}
# Execute the action.
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
sub usage()
{
print "Usage: " .
scriptname() . " [-j vnodeid] boot|shutdown|reconfig|reset\n";
exit(1);
}
my $optlist = "j:";
my $action = "boot";
my $vnodeid;
# Turn off line buffering on output
$| = 1;
# Drag in path stuff so we can find emulab stuff.
BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }
# Only root.
if ($EUID != 0) {
die("*** $0:\n".
" Must be root to run this script!\n");
}
# Script specific goo.
#
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
use libsetup;
use libtmcc;
use librc;
#my $RCDIR = "$BINDIR/rc";
#
# Not all clients support this.
#
#exit(0)
# if (MFS());
# Protos.
sub doboot();
sub doshutdown();
sub doreconfig();
sub docleanup();
# Parse command line.
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{'j'})) {
$vnodeid = $options{'j'};
libsetup_setvnodeid($vnodeid);
}
# Allow default above.
if (@ARGV) {
$action = $ARGV[0];
}
# Execute the action.
SWITCH: for ($action) {
/^boot$/i && do {
doboot();
last SWITCH;
};
/^shutdown$/i && do {
doshutdown();
last SWITCH;
};
/^reconfig$/i && do {
doreconfig();
last SWITCH;
};
/^cleanup$/i && do {
docleanup();
last SWITCH;
};
fatal("Invalid action: $action");
}
exit(0);
#
# Boot Action.
#
sub doboot()
{
# Here we get the keyblob which is ready to be loaded into the TPM
# via tpm-openssl-engine. This key is saved in $BINDIR/tpm.key.
# I am not sure if this is the best place to save this stuff. I also
# get the tpm x509 cert (which is supposed to be signed by the CA)
# from tmcd. It is also stored as $BINDIR/tpm.cert
my @tpmblob;
my @tpmpub;
#if (tmcc(TMCCCMD_TPMBLOB, "hex", \@tpmblob) < 0) {
if (tmcc(TMCCCMD_TPMBLOB, undef, \@tpmblob) < 0) {
#fatal("Could not get tpmblob from server");
print STDOUT "Could not get tpmblob from server";
return;
}
$str = $tpmblob[0];
if(!$str) {
#fatal("no tpmblob in database")
print STDOUT "no tpmblob in database";
return;
}
# Sanity check and trim BLOB= or BLOBHEX=
if($str =~ /^BLOBHEX=/){
$str = substr($str, 8);
}elsif($str =~ /^BLOB=/){
$str = substr($str, 5);
}else{
#fatal("corrupt key blob: @tpmblob");
print STDOUT "corrupt key blob: @tpmblob";
return;
}
# Strip off newline
# XXX: should check the newline probably
$len = length($str);
$str = substr($str, 0, $len-1);
open(FD, ">$BINDIR/tpm.key");
print FD pack("H*", $str);
close(FD);
if (tmcc(TMCCCMD_TPMPUB, undef, \@tpmpub) < 0) {
#fatal("Could not get tpmpub from server");
print STDOUT "Could not get tpmpub from server";
return;
}
$str = $tpmpub[0];
if(!$str) {
#fatal("no tpm x509 cert in database")
print STDOUT "no tpm x509 cert in database";
return;
}
# Trim TPMPUB=
if($str =~ /^TPMPUB=/){
$str = substr($str, 7);
}else{
#fatal("bogus tpmpub: @tpmpub");
print STDOUT "bogus tpmpub: @tpmpub";
return;
}
open(FD, ">$BINDIR/tpm.cert");
print FD $str;
$size = @tpmpub;
for($i = 1;$i < $size;$i++){
print FD $tpmpub[$i];
}
close(FD);
}
#
# Shutdown Action.
#
sub doshutdown()
{
}
#
# Node Reconfig Action (without rebooting).
#
sub doreconfig()
{
doshutdown();
return doboot();
}
#
# Node cleanup action (node is reset to completely clean state).
#
sub docleanup()
{
}
......@@ -34,6 +34,7 @@ use Exporter;
TMCCCMD_PLABEVENTKEYS TMCCCMD_PORTREGISTER
TMCCCMD_MOTELOG TMCCCMD_BOOTWHAT TMCCCMD_ROOTPSWD
TMCCCMD_LTMAP TMCCCMD_LTPMAP TMCCCMD_TOPOMAP TMCCCMD_LOADINFO
TMCCCMD_TPMBLOB TMCCCMD_TPMPUB
);
# Must come after package declaration!
......@@ -84,6 +85,7 @@ my $beproxy = 0;
"clrcache" => 0,
"noproxy" => 0,
"nossl" => 0,
"usetpm" => 0,
);
# The cache directory is named by the vnodeid. This avoids some confusion.
......@@ -183,6 +185,8 @@ my %commandset =
"topomap" => {TAG => "topomap"},
"ltmap" => {TAG => "ltmap"},
"ltpmap" => {TAG => "ltpmap"},
"tpmblob" => {TAG => "tpmblob"},
"tpmpubkey" => {TAG => "tpmpubkey"},
"loadinfo" => {TAG => "loadinfo"},
);
......@@ -247,6 +251,8 @@ sub TMCCCMD_ROOTPSWD() { $commandset{"rootpswd"}->{TAG}; }
sub TMCCCMD_TOPOMAP(){ $commandset{"topomap"}->{TAG}; }
sub TMCCCMD_LTMAP() { $commandset{"ltmap"}->{TAG}; }
sub TMCCCMD_LTPMAP() { $commandset{"ltpmap"}->{TAG}; }
sub TMCCCMD_TPMBLOB() { $commandset{"tpmblob"}->{TAG}; }
sub TMCCCMD_TPMPUB() { $commandset{"tpmpubkey"}->{TAG}; }
sub TMCCCMD_LOADINFO() { $commandset{"loadinfo"}->{TAG}; }
#
......@@ -284,6 +290,9 @@ sub optionstring($%)
if ($opthash{"nossl"}) {
$options .= " -i";
}
if ($opthash{"usetpm"}) {
$options .= " -T";
}
if ($opthash{"beproxy"}) {
$options .= " -x " . $opthash{"beproxy"};
$beproxy = 1;
......
......@@ -31,9 +31,10 @@ sub usage()
print STDERR " -i Do not use SSL protocol\n";
print STDERR " -c Clear tmcc cache first (must be root)\n";
print STDERR " -D Force command to use a direct, UDP request\n";
print STDERR " -T Use TPM\n";
exit(1);
}
my $optlist = "ds:p:v:n:k:ul:t:x:X:o:bcDif:";
my $optlist = "ds:p:v:n:k:ul:t:x:X:o:bcDif:T";
my $debug = 0;
my $CMD;
my $ARGS;
......@@ -92,6 +93,9 @@ sub ParseOptions()
if (defined($options{"i"})) {
libtmcc::configtmcc("nossl", 1);
}
if (defined($options{"T"})) {
libtmcc::configtmcc("usetpm", 1);
}
if (defined($options{"c"})) {
if ($UID) {
print STDERR "Must be root to use the -c option!\n";
......
......@@ -27,10 +27,12 @@
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <openssl/engine.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "decls.h"
#include "ssl.h"
#include "tpm.h"
#ifndef STANDALONE
#include "log.h"
#include "config.h"
......@@ -45,6 +47,8 @@
#define EMULAB_CERTFILE "emulab.pem"
#define SERVER_CERTFILE "server.pem"
#define CLIENT_CERTFILE "client.pem"
#define TPM_CERTFILE "tpm.cert"
#define TPM_KEYFILE "tpm.key"
#ifdef linux
#define EAUTH EPERM
......@@ -60,6 +64,11 @@ int isssl;
*/
int nousessl;
/*
* Client side; use TPM for SSL
*/
int usetpm;
/*
* On the client, we search a couple of dirs for the pem file.
*/
......@@ -100,7 +109,7 @@ tmcd_server_sslinit(void)
}
sprintf(buf, "%s/%s", ETCDIR, SERVER_CERTFILE);
/*
* Load our server key and certificate and then check it.
*/
......@@ -163,14 +172,16 @@ tmcd_client_sslinit(void)
*/
cp = clientcertdirs;
while (*cp) {
sprintf(buf, "%s/%s", *cp, CLIENT_CERTFILE);
sprintf(buf, "%s/%s", *cp,
(usetpm ? TPM_CERTFILE : CLIENT_CERTFILE));
if (access(buf, R_OK) == 0)
break;
cp++;
}
if (! *cp) {
error("Could not find a client certificate!\n");
error("Could not find a %s certificate!\n",
(usetpm ? "TPM" : "client"));
return 1;
}
......@@ -181,10 +192,31 @@ tmcd_client_sslinit(void)
tmcd_sslerror();
return 1;
}
if (! SSL_CTX_use_PrivateKey_file(ctx, buf, SSL_FILETYPE_PEM)) {
tmcd_sslerror();
return 1;
if (usetpm) {
sprintf(buf, "%s/%s", *cp, TPM_KEYFILE);
if (tmcd_tpm_loadengine()) {
tmcd_sslerror();
return 1;
}
/*
* Our key isn't in the same PEM as our cert
* because our keyfile is a binary blob
*/
if (tmcd_tpm_getkey(buf)) {
tmcd_sslerror();
return 1;
}
if (SSL_CTX_use_PrivateKey(ctx, tpmk) != 1) {
tmcd_sslerror();
return 1;
}
} else {
if (! SSL_CTX_use_PrivateKey_file(ctx, buf, SSL_FILETYPE_PEM)) {
tmcd_sslerror();
return 1;
}
}
if (SSL_CTX_check_private_key(ctx) != 1) {
......@@ -381,7 +413,7 @@ tmcd_sslconnect(int sock, const struct sockaddr *name, socklen_t namelen)
* a check?
*/
ipaddr = ((struct sockaddr_in *)name)->sin_addr;
if (!(he = gethostbyname(cname))) {
error("Could not map %s: %s\n", cname, hstrerror(h_errno));
goto badauth;
......@@ -535,7 +567,7 @@ tmcd_sslread(int sock, void *buf, size_t nbytes)
}
errno = 0;
if (isssl)
if (isssl) /* Renegotiations? */
cc = SSL_read(ssl, buf, nbytes);
else
cc = read(sock, buf, nbytes);
......@@ -566,6 +598,14 @@ tmcd_sslclose(int sock)
tmcd_sslprint("SSL_shutdown: ");
tmcd_sslerror();
}
/*
* This is here for completeness only; the server cannot use
* TPM right now or set 'usetpm' (we decided it was pointless
* at the moment) and the tmcc never calls this function.
*/
if (usetpm)
tmcd_tpm_free();
SSL_free(ssl);
ssl = NULL;
ERR_clear_error();
......@@ -575,6 +615,40 @@ tmcd_sslclose(int sock)
return 0;
}
/*
* Return the peer's cert. Caller must free the returned X509 via X509_free().
*/
X509*
tmcd_sslgetpeercert(void)
{
return (SSL_get_peer_certificate(ssl));
}
/*
* Take a row from the database (like TPM public key) and turn it into an X509.
* Caller must free the returned X509 via X509_free().
*/
X509*
tmcd_sslrowtocert(char *in, char *nid)
{
BIO *b;
X509 *local;
if (in == NULL)
return NULL;
b = BIO_new_mem_buf(in, -1);
local = PEM_read_bio_X509(b, NULL, NULL, NULL);
BIO_free(b);
if (!local) {
error("Error reading PEM from bio for node %s\n", nid);
return NULL;
}
return local;
}
/*
* Log an SSL error
*/
......
......@@ -3,6 +3,7 @@
* Copyright (c) 2000-2002, 2004, 2006 University of Utah and the Flux Group.
* All rights reserved.
*/
#include<openssl/x509.h>
/*
* SSL prototypes and definitions.
......@@ -16,8 +17,11 @@ int tmcd_sslwrite(int sock, const void *buf, size_t nbytes);
int tmcd_sslread(int sock, void *buf, size_t nbytes);
int tmcd_sslclose(int sock);
int tmcd_sslverify_client(char *, char *, char *, int);
X509* tmcd_sslgetpeercert(void);
X509* tmcd_sslrowtocert(char*, char*);
int isssl;
int nousessl;
int usetpm;
/*
* The client sends this tag to indicate that it is SSL capable.
......
......@@ -114,6 +114,7 @@ char *usagestr =
" -o logfile Specify log file name for -x option\n"
" -f datafile Extra stuff to send to tmcd (tcp mode only)\n"
" -i Do not use SSL protocol\n"
" -T Use the TPM for SSL negotiation\n"
"\n";
void
......@@ -171,7 +172,7 @@ main(int argc, char **argv)
WSADATA wsaData;
#endif
while ((ch = getopt(argc, argv, "v:s:p:un:t:k:x:X:l:do:if:")) != -1)
while ((ch = getopt(argc, argv, "v:s:p:un:t:k:x:X:l:do:if:T")) != -1)
switch(ch) {
case 'd':
debug++;
......@@ -224,6 +225,9 @@ main(int argc, char **argv)
nousessl = 1;
#endif
break;
case 'T':
usetpm = 1;
break;
default:
usage();
}
......@@ -256,6 +260,17 @@ main(int argc, char **argv)
"You may not use the -k or -s with the -l option\n");
usage();
}
if (usetpm && nousessl) {
fprintf(stderr, "You cannot use -T and -i together\n");
usage();
}
#ifndef WITHSSL
if (usetpm) {
fprintf(stderr,
"You used -T but compiled without WITHSSL. Bailing!\n");
exit(1);
}
#endif
#ifndef _WIN32
if( (! unixpath) && (0==access("/etc/emulab/emulab-privkey", R_OK)) ) {
......
......@@ -114,6 +114,7 @@ static int checkprivkey(struct in_addr, char *);
static void tcpserver(int sock, int portnum);
static void udpserver(int sock, int portnum);
static int handle_request(int, struct sockaddr_in *, char *, int);
static int checkcerts(char*);
static int makesockets(int portnum, int *udpsockp, int *tcpsockp);
int client_writeback(int sock, void *buf, int len, int tcp);
void client_writeback_done(int sock, struct sockaddr_in *client);
......@@ -279,6 +280,7 @@ COMMAND_PROTOTYPE(doportregister);
COMMAND_PROTOTYPE(dobootwhat);
COMMAND_PROTOTYPE(dotpmblob);
COMMAND_PROTOTYPE(dotpmpubkey);
COMMAND_PROTOTYPE(dotpmdummy);
/*
* The fullconfig slot determines what routines get called when pushing
......@@ -300,6 +302,7 @@ COMMAND_PROTOTYPE(dotpmpubkey);
#define F_ALLOCATED 0x08 /* node must be allocated to make call */
#define F_REMNOSSL 0x10 /* remote nodes can request without SSL */
#define F_REMREQSSL 0x20 /* remote nodes must connect with SSL */
#define F_REQTPM 0x40 /* require TPM on client */
struct command {
char *cmdname;
......@@ -377,6 +380,7 @@ struct command {
{ "bootwhat", FULLCONFIG_NONE, 0, dobootwhat },
{ "tpmblob", FULLCONFIG_ALL, 0, dotpmblob },
{ "tpmpubkey", FULLCONFIG_ALL, 0, dotpmpubkey },
{ "tpmdummy", FULLCONFIG_ALL, F_REQTPM, dotpmdummy },
};
static int numcommands = sizeof(command_array)/sizeof(struct command);
......@@ -1215,6 +1219,28 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp)
goto skipit;
}
/*
* Enforce TPM use with an iron fist!
*/
if ((command_array[i].flags & F_REQTPM)) {
if (!isssl) {
/* Should at least be TLS encrypted */
error("%s: %s: Invalid non-SSL/TPM request\n",
reqp->nodeid, command_array[i].cmdname);
goto skipit;
}
/*
* Make sure they are using the TPM certificate that we have in
* the database for this TLS sesion.
*/
if (checkcerts(reqp->nodeid)) {
error("%s: %s: TPM certificate mismatch\n",
reqp->nodeid, command_array[i].cmdname);
goto skipit;
}
}
/*
* Execute it.
*/
......@@ -1249,6 +1275,60 @@ handle_request(int sock, struct sockaddr_in *client, char *rdata, int istcp)
return 0;
}
static int checkcerts(char *nid)
{
MYSQL_RES *res;
MYSQL_ROW row;
int nrows, ret;
X509 *local, *remote;
res = mydb_query("select tpmx509 "
"from node_hostkeys "
"where node_id='%s' ",
1, nid);
/* Treat errors as failure */
if (!res) {