Commit 40d072cf authored by Leigh Stoller's avatar Leigh Stoller

A fair amount of cleanup, both of the ssl stuff and of tmcd in general.

Deal with ssl/nossl clients; at Chad's suggestion add a small handshake
tag to ssl enabled tmcc/tmcd which tells tmcd that it needs to enter
full SSL mode. This allows old tmcc to connect to an ssl enabled tmcd,
and still work okay.

I've also ironed out the verification stuff. At the client, we make sure
that the CommonName field of the peer cert maps to the same address that
we connected to (bossnode).

At the server, we check the OU field of the cert (we create the client
certs with the OU field set to the node type; a convention I made up!).
It must match the type of the node, as we get it from the nodes table.
Also check the CommonName to make sure it matches our hostname. This is
by no means bulletproof, but perfection is costly, and we don't have the
money!

Also cleaned up the REDIRECT testmode stuff. Instead of ifdef'ed under
TESTMODE, leave it compiled in all the time, but only allow it from the
local node (where tmcd is running). Mere users will not be able to
access it, but testbed people can use it since they have accounts on the
boss node.
parent 658ee16b
......@@ -20,9 +20,9 @@ TMLIBS = ${OBJDIR}/lib/libtb/libtb.a
#
# For SSL enabled tmcd/tmcc
#
#CFLAGS += -DWITHSSL -DETCDIR='"$(INSTALL_ETCDIR)"'
#CFLAGS += -DWITHSSL -DETCDIR='"$(INSTALL_ETCDIR)"'
#TMLIBS += -lssl -lcrypto
#SSLOBJ = ssl.o
#SSLOBJ = ssl.o
ifeq ($(EVENTSYS),1)
TMCDCFLAGS = `elvin-config --cflags vin4c` \
......
......@@ -2,8 +2,8 @@
* Insert Copyright Here.
*/
#define TBSERVER_PORT 7777
#define MYBUFSIZE 2048
#define TBSERVER_PORT 7777
#define MYBUFSIZE 2048
/*
* As the tmcd changes, incompatable changes with older version of
......@@ -18,6 +18,7 @@
* sure to change it there too!
*
* Note, this is assumed to be an integer. No need for 3.23.479 ...
* NB: See ron/libsetup.pm. That is version 4! I'll merge that in.
*/
#define DEFAULT_VERSION 2
#define CURRENT_VERSION 3
......@@ -12,10 +12,13 @@
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "decls.h"
......@@ -31,6 +34,11 @@
#define SERVER_CERTFILE "server.pem"
#define CLIENT_CERTFILE "client.pem"
/*
* This is used by tmcd to determine if the connection is ssl or not.
*/
int isssl;
/*
* On the client, we search a couple of dirs for the pem file.
*/
......@@ -46,6 +54,8 @@ static char *clientcertdirs[] = {
static SSL *ssl;
static SSL_CTX *ctx;
static int client = 0;
static char nosslbuf[MYBUFSIZE];
static int nosslbuflen, nosslbufidx;
static void tmcd_sslerror();
static void tmcd_sslprint(const char *fmt, ...);
......@@ -180,24 +190,49 @@ tmcd_client_sslinit(void)
int
tmcd_sslaccept(int sock, struct sockaddr *addr, socklen_t *addrlen)
{
int newsock;
int newsock, cc;
if ((newsock = accept(sock, addr, addrlen)) < 0)
return -1;
/*
* Read the first bit. It indicates whether we need to SSL
* handshake or not.
*/
if ((cc = read(newsock, nosslbuf, sizeof(nosslbuf) - 1)) <= 0) {
error("sslaccept: reading request");
if (cc == 0)
errno = EIO;
return -1;
}
if (strncmp(nosslbuf, SPEAKSSL, strlen(SPEAKSSL))) {
/*
* No ssl. Need to return this data on the next read.
* See below.
*/
isssl = 0;
nosslbuflen = cc;
nosslbufidx = 0;
return newsock;
}
isssl = 1;
nosslbuflen = 0;
if (! (ssl = SSL_new(ctx))) {
tmcd_sslerror();
errno = EIO;
return -1;
}
if (! SSL_set_fd(ssl, newsock)) {
tmcd_sslerror();
errno = EIO;
return -1;
}
if (SSL_accept(ssl) <= 0) {
tmcd_sslerror();
errno = EAUTH;
return -1;
}
tmcd_sslverify(newsock, 0);
return newsock;
}
......@@ -209,53 +244,136 @@ tmcd_sslaccept(int sock, struct sockaddr *addr, socklen_t *addrlen)
int
tmcd_sslconnect(int sock, const struct sockaddr *name, socklen_t namelen)
{
char *cp = SPEAKSSL;
int cc;
X509 *peer;
char cname[256];
struct hostent *he;
struct in_addr ipaddr;
if (connect(sock, name, namelen) < 0)
return -1;
/*
* Send our special tag which says we speak SSL.
*/
if ((cc = write(sock, cp, strlen(cp))) != strlen(cp)) {
if (cc >= 0) {
error("sslconnect: short write\n");
errno = EIO;
}
return -1;
}
if (! (ssl = SSL_new(ctx))) {
tmcd_sslerror();
errno = EIO;
return -1;
}
if (! SSL_set_fd(ssl, sock)) {
tmcd_sslerror();
errno = EIO;
return -1;
}
if (SSL_connect(ssl) <= 0) {
tmcd_sslerror();
return -1;
goto badauth;
}
/*
* Do the verification dance.
*/
if (SSL_get_verify_result(ssl) != X509_V_OK) {
tmcd_sslprint("Certificate did not verify!\n");
goto badauth;
}
if (! (peer = SSL_get_peer_certificate(ssl))) {
tmcd_sslprint("No certificate was presented by the peer!\n");
goto badauth;
}
/*
* Grab the common name from the cert.
*/
X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
NID_commonName, cname, sizeof(cname));
/*
* On the client, the common name must map to the same
* host we just connected to. This should be enough of
* a check?
*/
ipaddr = ((struct sockaddr_in *)name)->sin_addr;
if (!(he = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET))) {
error("Could not reverse map %s: %s\n",
inet_ntoa(ipaddr), hstrerror(h_errno));
goto badauth;
}
if (strcmp(he->h_name, cname)) {
error("Certificate commonname mismatch: %s!=%s\n",
he->h_name, cname);
goto badauth;
}
tmcd_sslverify(sock, 0);
return 0;
badauth:
errno = EAUTH;
return -1;
}
/*
* Verify the certificate of the peer.
* Verify the certificate of the client.
*/
int
tmcd_sslverify(int sock, char *host)
tmcd_sslverify_client(char *nodeid, char *class, char *type, int islocal)
{
X509 *peer;
char *cp, buf[256];
X509 *peer;
char cname[256], unitname[256];
if (SSL_get_verify_result(ssl) != X509_V_OK) {
tmcd_sslprint("Certificate did not verify!\n");
return 1;
error("sslverify: Certificate did not verify!\n");
return -1;
}
if (! (peer = SSL_get_peer_certificate(ssl))) {
tmcd_sslprint("No certificate was presented by the peer!\n");
return 1;
error("sslverify: No certificate presented!\n");
return -1;
}
if ((cp = X509_NAME_oneline(X509_get_subject_name(peer), 0, 0))) {
printf("Peer subject: %s\n", cp);
free(cp);
/*
* Grab stuff from the cert.
*/
X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
NID_organizationalUnitName,
unitname, sizeof(unitname));
X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
NID_commonName,
cname, sizeof(cname));
/*
* On the server, things are a bit more difficult since
* we share a common cert locally and a per group cert remotely.
*
* Make sure common name matches.
*/
if (strcmp(cname, BOSSNODE)) {
error("sslverify: commonname mismatch: %s!=%s\n",
cname, BOSSNODE);
return -1;
}
if ((cp = X509_NAME_oneline(X509_get_issuer_name(peer), 0, 0))) {
printf("Peer issuer: %s\n", cp);
free(cp);
/*
* If the node is remote, then the unitname must match the type.
* Simply a convention.
*/
if (!islocal && strcmp(unitname, type)) {
error("sslverify: unitname mismatch: %s!=%s\n",
unitname, type);
return -1;
}
return 0;
......@@ -272,8 +390,13 @@ tmcd_sslwrite(int sock, const void *buf, size_t nbytes)
int cc;
errno = 0;
if ((cc = SSL_write(ssl, buf, nbytes)) <= 0) {
if (cc < 0) {
if (isssl || client)
cc = SSL_write(ssl, buf, nbytes);
else
cc = write(sock, buf, nbytes);
if (cc <= 0) {
if (cc < 0 && isssl) {
tmcd_sslerror();
}
return cc;
......@@ -287,11 +410,27 @@ tmcd_sslwrite(int sock, const void *buf, size_t nbytes)
int
tmcd_sslread(int sock, void *buf, size_t nbytes)
{
int cc;
int cc = 0;
if (nosslbuflen) {
char *bp = (char *) buf, *cp = &nosslbuf[nosslbufidx];
while (cc < nbytes && nosslbuflen) {
*bp = *cp;
bp++; cp++; cc++;
nosslbuflen--; nosslbufidx++;
}
return cc;
}
errno = 0;
if ((cc = SSL_read(ssl, buf, nbytes)) <= 0) {
if (cc < 0) {
if (isssl || client)
cc = SSL_read(ssl, buf, nbytes);
else
cc = read(sock, buf, nbytes);
if (cc <= 0) {
if (cc < 0 && isssl) {
tmcd_sslerror();
}
return cc;
......@@ -310,6 +449,7 @@ tmcd_sslclose(int sock)
SSL_free(ssl);
ssl = NULL;
}
nosslbuflen = 0;
close(sock);
return 0;
}
......@@ -345,8 +485,7 @@ tmcd_sslprint(const char *fmt, ...)
if (client) {
fputs(buf, stderr);
fputs("\n", stderr);
}
else
error("%s\n", buf);
error("%s", buf);
}
......@@ -9,7 +9,14 @@ int tmcd_sslconnect(int sock, const struct sockaddr *, socklen_t);
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(int sock, char *host);
int tmcd_sslverify_client(char *, char *, char *, int);
int isssl;
/*
* The client sends this tag to indicate that it is SSL capable.
* Only local nodes can skip SSL. Remote nodes must use SSL!
*/
#define SPEAKSSL "ISPEAKSSL_TMCDV10"
/*
* When compiled to use SSL, redefine the routines appropriately
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment