Files

484 lines
16 KiB
C
Raw Permalink Normal View History

2018-01-19 11:43:05 -08:00
/* CRYPTO.C (C) Copyright Jan Jaeger, 2000-2012 */
2019-01-05 12:00:51 -08:00
/* (C) Copyright "Fish" (David B. Trout), 2018-2019 */
/* Hercules Crypto support */
/* */
/* Released under "The Q Public License Version 1" */
/* (http://www.hercules-390.org/herclic.html) as modifications to */
/* Hercules. */
2003-06-27 10:29:07 +00:00
#include "hstdinc.h"
#define _CRYPTO_C_
#define _HENGINE_DLL_
2018-01-27 10:32:03 -08:00
#include "hercules.h"
#include "opcode.h"
#include "hcrypto.h" // CSRNG constants and functions
2003-06-27 10:29:07 +00:00
//#define WRAPPINGKEYS_DEBUG // (#define for debugging)
/*-------------------------------------------------------------------*/
/* (delineates ARCH_DEP from non-arch_dep) */
/*-------------------------------------------------------------------*/
#if !defined( _GEN_ARCH )
#if defined( _ARCH_NUM_1 )
#define _GEN_ARCH _ARCH_NUM_1
#include "crypto.c"
#endif
#if defined( _ARCH_NUM_2 )
#undef _GEN_ARCH
#define _GEN_ARCH _ARCH_NUM_2
#include "crypto.c"
#endif
/*-------------------------------------------------------------------*/
/* (delineates ARCH_DEP from non-arch_dep) */
/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/
/* non-ARCH_DEP section: compiled only ONCE after last arch built */
/*-------------------------------------------------------------------*/
/* Note: the last architecture has been built so the normal non- */
/* underscore FEATURE values are now #defined according to the */
/* LAST built architecture just built (usually zarch = 900). This */
2018-01-31 10:58:49 -08:00
/* means from this point onward (to the end of file) you should */
/* ONLY be testing the underscore _FEATURE values to see if the */
/* given feature was defined for *ANY* of the build architectures. */
/*-------------------------------------------------------------------*/
/*********************************************************************/
/* IMPORTANT PROGRAMMING NOTE! */
/*********************************************************************/
/* */
/* It is CRITICALLY IMPORTANT to not use any architecture dependent */
/* macros anywhere in any of your non-arch_dep functions! This means */
/* you CANNOT use GREG, RADR, VADR, etc. anywhere in your function! */
/* */
/* Basically you MUST NOT use any architecture dependent macro that */
/* is #defined in the "feature.h" header. If you need to use */
/* any of them, then your function MUST be an "ARCH_DEP" function */
/* that is placed within the ARCH_DEP section at the beginning of */
/* this module where it can be compiled multiple times, once for */
/* each of the supported architectures so the macro gets #defined */
/* to its proper value for the architecture! YOU HAVE BEEN WARNED! */
/* */
/*********************************************************************/
2010-11-03 00:07:25 +00:00
#if defined( _FEATURE_076_MSA_EXTENSION_FACILITY_3 )
2003-06-28 16:51:18 +00:00
/*-------------------------------------------------------------------*/
/* Default CSRNG provider functions */
/*-------------------------------------------------------------------*/
2024-10-26 14:07:33 +02:00
static bool default_hopen_CSRNG( HRANDHAND* randhand )
{
sysblk.use_def_crypt = true; /* Default algorithm in use */
2024-10-26 14:07:33 +02:00
if (!*randhand)
{
int i, randval;
// "Crypto: **WARNING** Default insecure 'rand()' API being used"
WRMSG( HHC01495, "W" );
srand( (unsigned) time(0) );
for (i=0; i < 256; i++)
{
randval = (int) rand() * (int) (host_tod() & 0xFFFFFFFF);
srand( (unsigned) randval );
}
2024-10-26 14:07:33 +02:00
*randhand = (HRANDHAND) DUMMY_CYRPTO_HANDLE;
}
return true;
}
2024-10-26 14:07:33 +02:00
static bool default_hclose_CSRNG( HRANDHAND* randhand )
{
ASSERT( sysblk.use_def_crypt );
2024-10-26 14:07:33 +02:00
if (*randhand)
*randhand = 0;
return true;
}
2024-10-26 14:07:33 +02:00
static bool default_hget_random_bytes( BYTE* buf, size_t amt, HRANDHAND* randhand )
{
ASSERT( sysblk.use_def_crypt );
2024-10-26 14:07:33 +02:00
if (!*randhand)
VERIFY( default_hopen_CSRNG( randhand ) );
while (amt--)
*buf++ = (rand() & 0xFF);
return true;
}
/*-------------------------------------------------------------------*/
/* Open and initialize a CSRNG provider */
/*-------------------------------------------------------------------*/
2024-10-26 14:07:33 +02:00
bool hopen_CSRNG( HRANDHAND* randhand )
{
if (sysblk.use_def_crypt)
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
2024-10-26 14:07:33 +02:00
if (!*randhand)
{
#if !defined( NEED_CSRNG_INIT )
2024-10-26 14:07:33 +02:00
*randhand = DUMMY_CYRPTO_HANDLE;
#elif defined( USE_RAND_API )
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
2018-07-25 11:37:33 -07:00
#elif defined( USE_DEV_URANDOM )
int fd, ioctl_code, entropy, rc;
2018-07-25 11:37:33 -07:00
/* PROGRAMMING NOTE: we purposely use "dev/urandom" and NOT
"/dev/random" in order to prevent us from blocking while
2018-07-25 11:37:33 -07:00
we wait for entropy, and doing so is *NOT* any less secure
than always using "/dev/random"! (for our purposes)
Ref: "Myths about /dev/urandom"
https://www.2uo.de/myths-about-urandom/
*/
do fd = open( "/dev/urandom", O_RDONLY );
while (fd < 0 && errno == EINTR);
if (fd < 0)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "open()", strerror( errno ));
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
}
ioctl_code = RNDGETENTCNT; /* Try this one first */
if ((rc = ioctl( fd, ioctl_code, &entropy )) < 0)
{
if (ENOTTY != errno)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "ioctl()", strerror( errno ));
close( fd );
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
}
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "W", "ioctl( RNDGETENTCNT )", "Trying RNDGETENTCNT_ALT..." );
ioctl_code = RNDGETENTCNT_ALT; /* Try this one next */
if ((rc = ioctl( fd, ioctl_code, &entropy )) < 0)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "ioctl()", strerror( errno ));
close( fd );
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
}
}
/* Wait for minimum required entropy */
while (entropy < MIN_ENTROPY_BITS)
{
/* Use poll(), just like libsodium, since
we do not want to read from the device.
*/
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN;
2018-07-25 11:37:33 -07:00
/* Wait one millisecond and try again
until we get all the entropy we need.
*/
do rc = poll( &pfd, 1, 1 );
while (rc < 0 && (EINTR == errno || EAGAIN == errno));
if (rc < 0)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "poll()", strerror( errno ));
close( fd );
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
}
if ((rc = ioctl( fd, ioctl_code, &entropy )) < 0)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "ioctl()", strerror( errno ));
close( fd );
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
}
}
2024-10-26 14:07:33 +02:00
*randhand = fd;
#else // defined( _WIN32 )
BCRYPT_ALG_HANDLE hBCryptAlgHandle;
NTSTATUS ntStatus = BCryptOpenAlgorithmProvider
(
&hBCryptAlgHandle,
BCRYPT_RNG_ALGORITHM,
MS_PRIMITIVE_PROVIDER,
0 // (no flags)
);
if (!NT_SUCCESS( ntStatus ))
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "BCryptOpenAlgorithmProvider()",
strerror( w32_NtStatusToLastError( ntStatus )));
2024-10-26 14:07:33 +02:00
return default_hopen_CSRNG( randhand );
}
2024-10-26 14:07:33 +02:00
*randhand = hBCryptAlgHandle;
#endif
}
return true;
}
/*-------------------------------------------------------------------*/
/* Close and de-initialize a CSRNG provider */
/*-------------------------------------------------------------------*/
2024-10-26 14:07:33 +02:00
bool hclose_CSRNG( HRANDHAND* randhand )
{
if (sysblk.use_def_crypt)
2024-10-26 14:07:33 +02:00
return default_hclose_CSRNG( randhand );
2024-10-26 14:07:33 +02:00
if (*randhand)
{
2018-07-25 11:37:33 -07:00
#if defined( USE_DEV_URANDOM )
2024-10-26 14:07:33 +02:00
int rc, fd = *randhand;
do rc = close( fd );
while (rc < 0 && errno == EINTR);
if (rc < 0)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "W", "close()", strerror( errno ));
}
#elif defined( _WIN32 )
NTSTATUS ntStatus = BCryptCloseAlgorithmProvider
(
2024-10-26 14:07:33 +02:00
*randhand,
0 // (no flags)
);
if (!NT_SUCCESS( ntStatus ))
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "W", "BCryptCloseAlgorithmProvider()",
strerror( w32_NtStatusToLastError( ntStatus )));
}
#endif
2024-10-26 14:07:33 +02:00
*randhand = 0; // (always!)
}
return true;
}
/*-------------------------------------------------------------------*/
/* Obtain random bytes from CSRNG provider */
/*-------------------------------------------------------------------*/
2024-10-26 14:07:33 +02:00
bool hget_random_bytes( BYTE* buf, size_t amt, HRANDHAND* randhand )
{
if (sysblk.use_def_crypt)
2024-10-26 14:07:33 +02:00
return default_hget_random_bytes( buf, amt, randhand );
if (1
2024-10-26 14:07:33 +02:00
&& !*randhand
&& !hopen_CSRNG( randhand )
)
return false;
#if defined( USE_ARC4RANDOM )
{
arc4random_buf( buf, amt );
}
#elif defined( USE_SYS_GETRANDOM )
{
size_t chunk, offset = 0;
ssize_t rc;
while (amt > 0)
{
chunk = (amt <= MAX_CSRNG_BYTES) ? amt : MAX_CSRNG_BYTES;
do rc = syscall( SYS_getrandom, buf + offset, chunk, 0 );
while (rc < 0 && errno == EINTR);
if (rc < 0)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "syscall()", strerror( errno ));
return false;
}
offset += rc;
amt -= rc;
}
}
2018-07-25 11:37:33 -07:00
#elif defined( USE_DEV_URANDOM )
{
size_t chunk, offset = 0;
ssize_t rc;
/* Loop while bytes remain to be gotten... */
while (amt > 0)
{
chunk = (amt <= MAX_CSRNG_BYTES) ? amt : MAX_CSRNG_BYTES;
2024-10-26 14:07:33 +02:00
do rc = read( *randhand, buf + offset, chunk );
while (rc < 0 && (errno == EAGAIN || errno == EINTR));
if (rc < 0)
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "read()", strerror( errno ));
return false;
}
offset += rc;
amt -= rc;
}
}
#else // defined( _WIN32 )
{
2024-10-26 14:07:33 +02:00
NTSTATUS ntStatus = BCryptGenRandom( *randhand, buf, amt, 0 );
if (!NT_SUCCESS( ntStatus ))
{
// "Crypto: '%s' failed: %s"
WRMSG( HHC01494, "E", "BCryptGenRandom()",
strerror( w32_NtStatusToLastError( ntStatus )));
return false;
}
}
#endif
return true;
}
/*-------------------------------------------------------------------*/
/* Function: renew_wrapping_keys */
/*-------------------------------------------------------------------*/
/* Each time a clear reset is performed a new set of wrapping keys */
/* and their associated verification patterns are generated. The */
/* contents of the two wrapping-key registers are kept internal to */
/* the model so that no program, including the operating system, */
/* can directly observe their clear value. */
/*-------------------------------------------------------------------*/
void renew_wrapping_keys()
{
U64 cpuid;
BYTE lparname[8];
BYTE randbytes[32];
2018-05-31 12:01:02 -07:00
size_t i, idx = 0;
BYTE lparnum1;
CASSERT( sizeof( sysblk.wkvpaes_reg ) >= sizeof( cpuid ) + sizeof( lparname ) + 1, crypto_c );
CASSERT( sizeof( sysblk.wkvpdea_reg ) >= sizeof( cpuid ) + sizeof( lparname ) + 1, crypto_c );
2018-05-31 12:01:02 -07:00
/* Gather needed data */
2018-05-31 12:01:02 -07:00
cpuid = sysblk.cpuid;
lparnum1 = sysblk.lparnum & 0xff;
get_lparname( lparname );
2024-10-26 14:07:33 +02:00
VERIFY( hopen_CSRNG( &sysblk.wkrandhand ) );
2018-05-31 12:01:02 -07:00
{
2024-10-26 14:07:33 +02:00
VERIFY( hget_random_bytes( sysblk.wkaes_reg, sizeof( sysblk.wkaes_reg ), &sysblk.wkrandhand ) );
VERIFY( hget_random_bytes( sysblk.wkdea_reg, sizeof( sysblk.wkdea_reg ), &sysblk.wkrandhand ) );
VERIFY( hget_random_bytes( randbytes, sizeof( randbytes ), &sysblk.wkrandhand ) );
2018-05-31 12:01:02 -07:00
}
2024-10-26 14:07:33 +02:00
VERIFY( hclose_CSRNG( &sysblk.wkrandhand ) );
2018-05-31 12:01:02 -07:00
/*
** We set the verification pattern to:
**
** CPUID (8 bytes)
** LPAR Name (8 bytes)
** LPAR Number (1 byte) (low order)
** Random bytes (n bytes) (remainder)
*/
2018-05-31 12:01:02 -07:00
memset( sysblk.wkvpaes_reg, 0, sizeof( sysblk.wkvpaes_reg ));
memset( sysblk.wkvpdea_reg, 0, sizeof( sysblk.wkvpdea_reg ));
2018-05-31 12:01:02 -07:00
/* CPUID */
2018-05-31 12:01:02 -07:00
idx += sizeof( cpuid ); /* (since it's processed right to left) */
2018-05-31 12:01:02 -07:00
for (i=0; i < sizeof( cpuid ); i++)
{
sysblk.wkvpaes_reg[ idx - 1 - i ] = cpuid & 0xff;
sysblk.wkvpdea_reg[ idx - 1 - i ] = cpuid & 0xff;
cpuid >>= 8;
}
2018-05-31 12:01:02 -07:00
/* LPAR Name */
2018-05-31 12:01:02 -07:00
memcpy( &sysblk.wkvpaes_reg[ idx ], lparname, sizeof( lparname ));
memcpy( &sysblk.wkvpdea_reg[ idx ], lparname, sizeof( lparname ));
2018-05-31 12:01:02 -07:00
idx += sizeof( lparname ); /* (next field starts past this one) */
2018-05-31 12:01:02 -07:00
/* LPAR Number */
2018-05-31 12:01:02 -07:00
sysblk.wkvpaes_reg[ idx ] = lparnum1;
sysblk.wkvpdea_reg[ idx ] = lparnum1;
2018-05-31 12:01:02 -07:00
idx += 1;
2018-05-31 12:01:02 -07:00
/* Random bytes (if there's room) */
2018-05-31 12:01:02 -07:00
for (i=0; i < sizeof( sysblk.wkvpaes_reg ) - idx; i++)
sysblk.wkvpaes_reg[ idx + i ] = randbytes[i];
2018-05-31 12:01:02 -07:00
for (i=0; i < sizeof( sysblk.wkvpdea_reg ) - idx; i++)
sysblk.wkvpdea_reg[ idx + i ] = randbytes[i];
2018-05-31 12:01:02 -07:00
/* Display wrapping keys if debugging... */
#if defined( WRAPPINGKEYS_DEBUG ) // (see beginning of source module)
{
char buf[128] = {0};
#define DBG_WRMSG_CRYPT_REG( dbg_msg, wk_reg ) \
\
do \
{ \
STRLCPY( buf, dbg_msg ); \
\
for (i=0; i < sizeof( sysblk.wk_reg ); i++) snprintf( buf + strlen( buf ), \
sizeof( buf ) - strlen( buf ), "%02X", \
sysblk.wk_reg[i] ); \
\
WRMSG( HHC90190, "D", buf ); \
} \
while (0)
DBG_WRMSG_CRYPT_REG( "AES wrapping key: ", wkaes_reg );
DBG_WRMSG_CRYPT_REG( "AES wrapping key vp: ", wkvpaes_reg );
DBG_WRMSG_CRYPT_REG( "DEA wrapping key: ", wkdea_reg );
DBG_WRMSG_CRYPT_REG( "DEA wrapping key vp: ", wkvpdea_reg );
}
#endif // defined( WRAPPINGKEYS_DEBUG )
}
#endif /* defined( _FEATURE_076_MSA_EXTENSION_FACILITY_3 ) */
#endif /* !defined( _GEN_ARCH ) */