2009-07-28 18:46:53 +04:00
/*
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 0213 9 , 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: \n PKT = " ) ;
print_hash ( pkt_hash , sizeof ( pkt_hash ) ) ;
printf ( " \n EXP = " ) ;
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 ( 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: \n C = " ) ;
print_hash ( challenge , sizeof ( challenge ) ) ;
printf ( " \n H = " ) ;
print_hash ( hash , sizeof ( hash ) ) ;
printf ( " \n R = " ) ;
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 ) {
2009-08-20 22:24:12 +04:00
dbg_printf ( 3 , " Stopped reading @ %d bytes \n " ,
2009-07-28 18:46:53 +04:00
( int ) max_len - remain ) ;
break ;
}
p + = nread ;
remain - = nread ;
}
close ( fd ) ;
2009-08-20 22:24:12 +04:00
dbg_printf ( 3 , " Actual key length = %d bytes \n " , ( int ) max_len - remain ) ;
2009-07-28 18:46:53 +04:00
return ( int ) ( max_len - remain ) ;
}