f7ccaa261a
Signed-off-by: Lon Hohberger <lon@users.sourceforge.net>
419 lines
8.0 KiB
C
419 lines
8.0 KiB
C
/*
|
|
Copyright Red Hat, Inc. 2006
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING. If not, write to the
|
|
Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
|
|
MA 02139, USA.
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sechash.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
/* Local includes */
|
|
#include "xvm.h"
|
|
#include "simple_auth.h"
|
|
#include "debug.h"
|
|
|
|
|
|
void
|
|
print_hash(unsigned char *hash, size_t hashlen)
|
|
{
|
|
int x;
|
|
|
|
for (x = 0; x < hashlen; x++)
|
|
printf("%02x", (hash[x]&0xff));
|
|
}
|
|
|
|
|
|
static void
|
|
sha_sign(fence_req_t *req, void *key, size_t key_len)
|
|
{
|
|
unsigned char hash[SHA512_LENGTH];
|
|
HASHContext *h;
|
|
HASH_HashType ht;
|
|
unsigned int rlen;
|
|
int devrand;
|
|
|
|
switch(req->hashtype) {
|
|
case HASH_SHA1:
|
|
ht = HASH_AlgSHA1;
|
|
break;
|
|
case HASH_SHA256:
|
|
ht = HASH_AlgSHA256;
|
|
break;
|
|
case HASH_SHA512:
|
|
ht = HASH_AlgSHA512;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
dbg_printf(4, "Opening /dev/urandom\n");
|
|
devrand = open("/dev/urandom", O_RDONLY);
|
|
if (devrand >= 0) {
|
|
if (read(devrand, req->random, sizeof(req->random)) < 0) {
|
|
perror("read /dev/urandom");
|
|
}
|
|
close(devrand);
|
|
}
|
|
|
|
memset(hash, 0, sizeof(hash));
|
|
h = HASH_Create(ht);
|
|
if (!h)
|
|
return;
|
|
|
|
HASH_Begin(h);
|
|
HASH_Update(h, key, key_len);
|
|
HASH_Update(h, (void *)req, sizeof(*req));
|
|
HASH_End(h, hash, &rlen, sizeof(hash));
|
|
HASH_Destroy(h);
|
|
|
|
memcpy(req->hash, hash, sizeof(req->hash));
|
|
}
|
|
|
|
|
|
static int
|
|
sha_verify(fence_req_t *req, void *key, size_t key_len)
|
|
{
|
|
unsigned char hash[SHA512_LENGTH];
|
|
unsigned char pkt_hash[SHA512_LENGTH];
|
|
HASHContext *h = NULL;
|
|
HASH_HashType ht;
|
|
unsigned int rlen;
|
|
int ret;
|
|
|
|
switch(req->hashtype) {
|
|
case HASH_SHA1:
|
|
ht = HASH_AlgSHA1;
|
|
break;
|
|
case HASH_SHA256:
|
|
ht = HASH_AlgSHA256;
|
|
break;
|
|
case HASH_SHA512:
|
|
ht = HASH_AlgSHA512;
|
|
break;
|
|
default:
|
|
dbg_printf(3, "%s: no-op (HASH_NONE)\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
memset(hash, 0, sizeof(hash));
|
|
h = HASH_Create(ht);
|
|
if (!h)
|
|
return 0;
|
|
|
|
memcpy(pkt_hash, req->hash, sizeof(pkt_hash));
|
|
memset(req->hash, 0, sizeof(req->hash));
|
|
|
|
HASH_Begin(h);
|
|
HASH_Update(h, key, key_len);
|
|
HASH_Update(h, (void *)req, sizeof(*req));
|
|
HASH_End(h, hash, &rlen, sizeof(hash));
|
|
HASH_Destroy(h);
|
|
|
|
memcpy(req->hash, pkt_hash, sizeof(req->hash));
|
|
|
|
ret = !memcmp(hash, pkt_hash, sizeof(hash));
|
|
if (!ret) {
|
|
printf("Hash mismatch:\nPKT = ");
|
|
print_hash(pkt_hash, sizeof(pkt_hash));
|
|
printf("\nEXP = ");
|
|
print_hash(hash, sizeof(hash));
|
|
printf("\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int
|
|
sign_request(fence_req_t *req, void *key, size_t key_len)
|
|
{
|
|
memset(req->hash, 0, sizeof(req->hash));
|
|
switch(req->hashtype) {
|
|
case HASH_NONE:
|
|
dbg_printf(3, "%s: no-op (HASH_NONE)\n", __FUNCTION__);
|
|
return 0;
|
|
case HASH_SHA1:
|
|
case HASH_SHA256:
|
|
case HASH_SHA512:
|
|
sha_sign(req, key, key_len);
|
|
return 0;
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
verify_request(fence_req_t *req, fence_hash_t min,
|
|
void *key, size_t key_len)
|
|
{
|
|
if (req->hashtype < min) {
|
|
printf("Hash type not strong enough (%d < %d)\n",
|
|
req->hashtype, min);
|
|
return 0;
|
|
}
|
|
switch(req->hashtype) {
|
|
case HASH_NONE:
|
|
return 1;
|
|
case HASH_SHA1:
|
|
case HASH_SHA256:
|
|
case HASH_SHA512:
|
|
return sha_verify(req, key, key_len);
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
sha_challenge(int fd, fence_auth_type_t auth, void *key,
|
|
size_t key_len, int timeout)
|
|
{
|
|
fd_set rfds;
|
|
struct timeval tv;
|
|
unsigned char hash[MAX_HASH_LENGTH];
|
|
unsigned char challenge[MAX_HASH_LENGTH];
|
|
unsigned char response[MAX_HASH_LENGTH];
|
|
int devrand;
|
|
int ret;
|
|
HASHContext *h;
|
|
HASH_HashType ht;
|
|
unsigned int rlen;
|
|
|
|
devrand = open("/dev/urandom", O_RDONLY);
|
|
if (devrand < 0) {
|
|
perror("open /dev/urandom");
|
|
return 0;
|
|
}
|
|
if (read(devrand, challenge, sizeof(challenge)) < 0) {
|
|
perror("read /dev/urandom");
|
|
return 0;
|
|
}
|
|
close(devrand);
|
|
|
|
if (write(fd, challenge, sizeof(challenge)) < 0) {
|
|
perror("write");
|
|
return 0;
|
|
}
|
|
|
|
switch(auth) {
|
|
case HASH_SHA1:
|
|
ht = HASH_AlgSHA1;
|
|
break;
|
|
case HASH_SHA256:
|
|
ht = HASH_AlgSHA256;
|
|
break;
|
|
case HASH_SHA512:
|
|
ht = HASH_AlgSHA512;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
memset(hash, 0, sizeof(hash));
|
|
h = HASH_Create(ht);
|
|
if (!h)
|
|
return 0;
|
|
|
|
HASH_Begin(h);
|
|
HASH_Update(h, key, key_len);
|
|
HASH_Update(h, challenge, sizeof(challenge));
|
|
HASH_End(h, hash, &rlen, sizeof(hash));
|
|
HASH_Destroy(h);
|
|
|
|
memset(response, 0, sizeof(response));
|
|
|
|
FD_ZERO(&rfds);
|
|
FD_SET(fd, &rfds);
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
|
|
perror("select");
|
|
return 0;
|
|
}
|
|
|
|
if (read(fd, response, sizeof(response)) < sizeof(response)) {
|
|
perror("read");
|
|
return 0;
|
|
}
|
|
|
|
ret = !memcmp(response, hash, sizeof(response));
|
|
if (!ret) {
|
|
printf("Hash mismatch:\nC = ");
|
|
print_hash(challenge, sizeof(challenge));
|
|
printf("\nH = ");
|
|
print_hash(hash, sizeof(hash));
|
|
printf("\nR = ");
|
|
print_hash(response, sizeof(response));
|
|
printf("\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int
|
|
sha_response(int fd, fence_auth_type_t auth, void *key,
|
|
size_t key_len, int timeout)
|
|
{
|
|
fd_set rfds;
|
|
struct timeval tv;
|
|
unsigned char challenge[MAX_HASH_LENGTH];
|
|
unsigned char hash[MAX_HASH_LENGTH];
|
|
HASHContext *h;
|
|
HASH_HashType ht;
|
|
unsigned int rlen;
|
|
|
|
FD_ZERO(&rfds);
|
|
FD_SET(fd, &rfds);
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
|
|
perror("select");
|
|
return 0;
|
|
}
|
|
|
|
if (read(fd, challenge, sizeof(challenge)) < 0) {
|
|
perror("read");
|
|
return 0;
|
|
}
|
|
|
|
switch(auth) {
|
|
case AUTH_SHA1:
|
|
ht = HASH_AlgSHA1;
|
|
break;
|
|
case AUTH_SHA256:
|
|
ht = HASH_AlgSHA256;
|
|
break;
|
|
case AUTH_SHA512:
|
|
ht = HASH_AlgSHA512;
|
|
break;
|
|
default:
|
|
dbg_printf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
memset(hash, 0, sizeof(hash));
|
|
h = HASH_Create(ht); /* */
|
|
if (!h)
|
|
return 0;
|
|
|
|
HASH_Begin(h);
|
|
HASH_Update(h, key, key_len);
|
|
HASH_Update(h, challenge, sizeof(challenge));
|
|
HASH_End(h, hash, &rlen, sizeof(hash));
|
|
HASH_Destroy(h);
|
|
|
|
if (write(fd, hash, sizeof(hash)) < sizeof(hash)) {
|
|
perror("read");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
tcp_challenge(int fd, fence_auth_type_t auth, void *key, size_t key_len,
|
|
int timeout)
|
|
{
|
|
switch(auth) {
|
|
case AUTH_NONE:
|
|
dbg_printf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__);
|
|
return 1;
|
|
case AUTH_SHA1:
|
|
case AUTH_SHA256:
|
|
case AUTH_SHA512:
|
|
return sha_challenge(fd, auth, key, key_len, timeout);
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
tcp_response(int fd, fence_auth_type_t auth, void *key, size_t key_len,
|
|
int timeout)
|
|
{
|
|
switch(auth) {
|
|
case AUTH_NONE:
|
|
dbg_printf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__);
|
|
return 1;
|
|
case AUTH_SHA1:
|
|
case AUTH_SHA256:
|
|
case AUTH_SHA512:
|
|
return sha_response(fd, auth, key, key_len, timeout);
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
read_key_file(char *file, char *key, size_t max_len)
|
|
{
|
|
int fd;
|
|
int nread, remain = max_len;
|
|
char *p;
|
|
|
|
dbg_printf(3, "Reading in key file %s into %p (%d max size)\n",
|
|
file, key, (int)max_len);
|
|
fd = open(file, O_RDONLY);
|
|
if (fd < 0) {
|
|
dbg_printf(2, "Error opening key file: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
memset(key, 0, max_len);
|
|
p = key;
|
|
remain = max_len;
|
|
|
|
while (remain) {
|
|
nread = read(fd, p, remain);
|
|
if (nread < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
dbg_printf(2, "Error from read: %s\n", strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
if (nread == 0) {
|
|
dbg_printf(3, "Stopped reading @ %d bytes\n",
|
|
(int)max_len-remain);
|
|
break;
|
|
}
|
|
|
|
p += nread;
|
|
remain -= nread;
|
|
}
|
|
|
|
close(fd);
|
|
dbg_printf(3, "Actual key length = %d bytes\n", (int)max_len-remain);
|
|
|
|
return (int)(max_len - remain);
|
|
}
|