/* This program is released under the Common Public License V1.0
 *
 * You should have received a copy of Common Public License V1.0 along with
 * with this program.
 */

/*
 * Entry point for crypto graphic instructions on s390. If a instruction
 * is not available, instruction will be simulated in software.
 *
 * Authors(s): Ralph Wuerthner <rwuerthn@de.ibm.com>
 *	       Jan Glauber <jan.glauber@de.ibm.com>
 *	       Felix Beck <felix.beck@de.ibm.com>
 *	       Christian Maaser <cmaaser@de.ibm.com>
 *	       Holger Dengler <hd@linux.vnet.ibm.com>
 *	       Ingo Tuchscherer <ingo.tuchscherer.linux.vnet.ibm.com>
 *
 * Copyright IBM Copr. 2007, 2009, 2011, 2013
 */

#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "s390_crypto.h"
#include "init.h"

s390_supported_function_t s390_kimd_functions[] = {
	{SHA_1, S390_CRYPTO_SHA_1, &sha1_switch},
	{SHA_224, S390_CRYPTO_SHA_256, &sha256_switch},
	{SHA_256, S390_CRYPTO_SHA_256, &sha256_switch},
	{SHA_384, S390_CRYPTO_SHA_512, &sha512_switch},
	{SHA_512, S390_CRYPTO_SHA_512, &sha512_switch},
	{GHASH, S390_CRYPTO_GHASH, &msa4_switch}
};

s390_supported_function_t s390_kmc_functions[] = {
	{DEA_ENCRYPT, S390_CRYPTO_DEA_ENCRYPT, &des_switch},
	{DEA_DECRYPT, S390_CRYPTO_DEA_DECRYPT, &des_switch},
	{TDEA_192_ENCRYPT, S390_CRYPTO_TDEA_192_ENCRYPT, &tdes_switch},
	{TDEA_192_DECRYPT, S390_CRYPTO_TDEA_192_DECRYPT, &tdes_switch},
	{AES_128_ENCRYPT, S390_CRYPTO_AES_128_ENCRYPT, &aes128_switch},
	{AES_128_DECRYPT, S390_CRYPTO_AES_128_DECRYPT, &aes128_switch},
	{AES_192_ENCRYPT, S390_CRYPTO_AES_192_ENCRYPT, &aes192_switch},
	{AES_192_DECRYPT, S390_CRYPTO_AES_192_DECRYPT, &aes192_switch},
	{AES_256_ENCRYPT, S390_CRYPTO_AES_256_ENCRYPT, &aes256_switch},
	{AES_256_DECRYPT, S390_CRYPTO_AES_256_DECRYPT, &aes256_switch},
	{AES_128_XTS_ENCRYPT, S390_CRYPTO_AES_128_XTS_ENCRYPT, &msa4_switch},
	{AES_128_XTS_DECRYPT, S390_CRYPTO_AES_128_XTS_DECRYPT, &msa4_switch},
	{AES_256_XTS_ENCRYPT, S390_CRYPTO_AES_256_XTS_ENCRYPT, &msa4_switch},
	{AES_256_XTS_DECRYPT, S390_CRYPTO_AES_256_XTS_DECRYPT, &msa4_switch},
	{PRNG, S390_CRYPTO_PRNG, &prng_switch}
};

s390_supported_function_t s390_msa4_functions[] = {
	{DEA_ENCRYPT, S390_CRYPTO_DEA_ENCRYPT, &msa4_switch},
	{DEA_DECRYPT, S390_CRYPTO_DEA_DECRYPT, &msa4_switch},
	{TDEA_192_ENCRYPT, S390_CRYPTO_TDEA_192_ENCRYPT, &msa4_switch},
	{TDEA_192_DECRYPT, S390_CRYPTO_TDEA_192_DECRYPT, &msa4_switch},
	{AES_128_ENCRYPT, S390_CRYPTO_AES_128_ENCRYPT, &msa4_switch},
	{AES_128_DECRYPT, S390_CRYPTO_AES_128_DECRYPT, &msa4_switch},
	{AES_192_ENCRYPT, S390_CRYPTO_AES_192_ENCRYPT, &msa4_switch},
	{AES_192_DECRYPT, S390_CRYPTO_AES_192_DECRYPT, &msa4_switch},
	{AES_256_ENCRYPT, S390_CRYPTO_AES_256_ENCRYPT, &msa4_switch},
	{AES_256_DECRYPT, S390_CRYPTO_AES_256_DECRYPT, &msa4_switch},
	{AES_128_XTS_ENCRYPT, S390_CRYPTO_AES_128_XTS_ENCRYPT, &msa4_switch},
	{AES_128_XTS_DECRYPT, S390_CRYPTO_AES_128_XTS_DECRYPT, &msa4_switch},
	{AES_256_XTS_ENCRYPT, S390_CRYPTO_AES_256_XTS_ENCRYPT, &msa4_switch},
	{AES_256_XTS_DECRYPT, S390_CRYPTO_AES_256_XTS_DECRYPT, &msa4_switch}
};

s390_supported_function_t s390_ppno_functions[] = {
	{SHA512_DRNG_GEN, S390_CRYPTO_SHA512_DRNG_GEN, &sha512_drng_switch},
	{SHA512_DRNG_SEED, S390_CRYPTO_SHA512_DRNG_SEED, &sha512_drng_switch},
};

int read_cpuinfo(void)
{
	int msa = 0;
	FILE *handle = fopen("/proc/cpuinfo", "r");
	if (handle) {
		char buffer[80];
		int i = 0;
		while(fgets(buffer, sizeof(buffer), handle)) {
			i++;
			if(strstr(buffer,"features") && strstr(buffer,"msa")) {
				msa = 1;
				break;
			}
		}
		fclose(handle);
	}
	return msa;
}

int read_facility_bits(void)
{
	int msa = 0;
	unsigned long long facility_bits[2] = {0};
	struct sigaction oldact;
	sigset_t oldset;
	int rc = -1;

	rc = begin_sigill_section(&oldact, &oldset);
	if (!rc) {
		rc = __stfle(facility_bits, 2);
		end_sigill_section(&oldact, &oldset);
	}
	/* __stfle always returns the no. of double words needed to store the
	 * facility bits. This quantity is machine dependent. However, we just
	 * need the first two double words. */
	if(rc >= 2){
		if(facility_bits[0] & (1ULL << (63 - 17)))
			msa = 1;
		if(facility_bits[1] & (1ULL << (127 - 76)))
			msa = 3;
		if(facility_bits[1] & (1ULL << (127 - 77)))
			msa = 4;
		if(facility_bits[0] & (1ULL << (63 - 57)))
			msa = 5;
	}

	return msa;
}

void set_switches(int msa)
{
	unsigned char mask[16];
	unsigned int n;
	unsigned int on = 0;
	struct sigaction oldact;
	sigset_t oldset;
	/* The function arrays contain integers. Thus to compute the amount of
	 * their elements the result of sizeof(*functions) has to be divided by
	 * sizeof(int).
	 * The msa4_switch will be set in the kimd function. Because this is
	 * the only switch for all MSA4 functions we just set it through the
	 * kimd query and do not need to over the whole array. Therfore there
	 * is also no distict setting of the switch needed in form
	 * msa4_switch = 1. */
	memset(mask, 0, sizeof(mask));
	if (msa) {
		if (begin_sigill_section(&oldact, &oldset) == 0) {
			s390_kmc(S390_CRYPTO_QUERY, mask, (void *) 0, (void *) 0, 0);
			end_sigill_section(&oldact, &oldset);
		}
	}
	for (n = 0; n < (sizeof(s390_kmc_functions) /
			 sizeof(s390_supported_function_t)); n++) {
		if (S390_CRYPTO_TEST_MASK(mask, s390_kmc_functions[n].hw_fc))
			on = 1;
		else
			on = 0;
		*s390_kmc_functions[n].enabled = on;
	}

	if (msa) {
		if (begin_sigill_section(&oldact, &oldset) == 0) {
			s390_kimd(S390_CRYPTO_QUERY, mask, (void *) 0, 0);
			end_sigill_section(&oldact, &oldset);
		}
	}

	for (n = 0; n < (sizeof(s390_kimd_functions) /
			 sizeof(s390_supported_function_t)); n++) {
		if (S390_CRYPTO_TEST_MASK(mask, s390_kimd_functions[n].hw_fc))
			on = 1;
		else
			on = 0;
		*s390_kimd_functions[n].enabled = on;
	}

	if (5 <= msa) {
		msa5_switch = 1;
		if (begin_sigill_section(&oldact, &oldset) == 0) {
			s390_ppno(S390_CRYPTO_QUERY, mask, NULL, 0, NULL, 0);
			end_sigill_section(&oldact, &oldset);
		}
	}

	for (n = 0; n < (sizeof(s390_ppno_functions) /
			 sizeof(s390_supported_function_t)); n++) {
		if (S390_CRYPTO_TEST_MASK(mask, s390_ppno_functions[n].hw_fc))
			on = 1;
		else
			on = 0;
		*s390_ppno_functions[n].enabled = on;
	}
}

void s390_crypto_switches_init(void)
{
	int msa;

	msa = read_facility_bits();
	if (!msa)
		msa = read_cpuinfo();

	set_switches(msa);
}

/*
 * The first field represents the mechanism ID.
 * The second field represents the function family type (category),
 * The third filed represents the function code.
 * This function code will be used later to check if HW support
 * is available and modifies the SW/HW-support-flag.
 * SHW - static hardware support (CPACF)
 * DHW - dynamic hardware support (crypto adapter)
 * SW  - software support
 * Bit field flags: [0|0|0|0|0|SHW|DHW|SW]
 * The last filed represent the property flags
 */
libica_func_list_element_int icaList[] = {
 {SHA1,   KIMD, SHA_1  		, ICA_FLAG_SW, 0},
 {SHA224, KIMD, SHA_256		, ICA_FLAG_SW, 0},
 {SHA256, KIMD, SHA_256		, ICA_FLAG_SW, 0},
 {SHA384, KIMD, SHA_512		, ICA_FLAG_SW, 0},
 {SHA512, KIMD, SHA_512		, ICA_FLAG_SW, 0},
 {G_HASH, KIMD, GHASH		,           0, 0},

 {DES_ECB,      KMC,  DEA_ENCRYPT, ICA_FLAG_SW, 0},
 {DES_CBC,      KMC,  DEA_ENCRYPT, ICA_FLAG_SW, 0},
 {DES_OFB,      MSA4, DEA_ENCRYPT, 0, 0},
 {DES_CFB,      MSA4, DEA_ENCRYPT, 0, 0},
 {DES_CTR,      MSA4, DEA_ENCRYPT, 0, 0},
 {DES_CMAC,     MSA4, DEA_ENCRYPT, 0, 0},					// CPACF only (MSA4)

 {DES3_ECB,     KMC,  TDEA_192_ENCRYPT, ICA_FLAG_SW, 0},
 {DES3_CBC,     KMC,  TDEA_192_ENCRYPT, ICA_FLAG_SW, 0},
 {DES3_OFB,     MSA4, TDEA_192_ENCRYPT,           0, 0},
 {DES3_CFB,     MSA4, TDEA_192_ENCRYPT, 	  	  0, 0},
 {DES3_CTR,     MSA4, TDEA_192_ENCRYPT,           0, 0},
 {DES3_CMAC,    MSA4, TDEA_192_ENCRYPT,           0, 0},

 {AES_ECB,      KMC,  AES_128_ENCRYPT, ICA_FLAG_SW, 0},
 {AES_CBC,      KMC,  AES_128_ENCRYPT, ICA_FLAG_SW, 0},
 {AES_OFB,      MSA4, AES_128_ENCRYPT,           0, 0},
 {AES_CFB,      MSA4, AES_128_ENCRYPT,           0, 0},
 {AES_CTR,      MSA4, AES_128_ENCRYPT,           0, 0},
 {AES_CMAC,     MSA4, AES_128_ENCRYPT,           0, 0},
 {AES_CCM,      MSA4, AES_128_ENCRYPT, 	         0, 0},
 {AES_GCM,      MSA4, AES_128_ENCRYPT,           0, 0},
 {AES_XTS,      MSA4, AES_128_XTS_ENCRYPT,       0, 0},
 {P_RNG,    		ADAPTER, 0, ICA_FLAG_SHW | ICA_FLAG_SW, 0},	// SHW (CPACF) + SW
 {RSA_ME, 		ADAPTER, 0, ICA_FLAG_DHW | ICA_FLAG_SW, 0x0F},	// DHW (CEX) + SW / 512,1024,2048, 4096 bit key length
 {RSA_CRT, 		ADAPTER, 0, ICA_FLAG_DHW | ICA_FLAG_SW, 0x0F},	// DHW (CEX) + SW / 512,1024,2048, 4096 bit key length
 {RSA_KEY_GEN_ME,  	ADAPTER, 0, ICA_FLAG_SW, 		0},	// SW (openssl)
 {RSA_KEY_GEN_CRT, 	ADAPTER, 0, ICA_FLAG_SW, 		0},	// SW (openssl)

 {SHA512_DRNG, PPNO, SHA512_DRNG_GEN, ICA_FLAG_SHW | ICA_FLAG_SW, 0},

/* available for the MSA4 instruction */
/* available for the RSA instruction */

};

/*
 * initializes the libica function list
 * Query s390_xxx_functions for each algorithm to check
 * CPACF support and update the corresponding SHW-flags.
 */
int s390_initialize_functionlist() {

  unsigned int list_len = sizeof(icaList)/sizeof(libica_func_list_element_int);

  unsigned int x;
  for (x=0; x<list_len; x++) {
	switch ((int)icaList[x].type) {
	case KIMD:
		icaList[x].flags = icaList[x].flags |
		((*s390_kimd_functions[icaList[x].id].enabled)? 4: 0);
	break;
	case KMC:
		icaList[x].flags = icaList[x].flags |
		((*s390_kmc_functions[icaList[x].id].enabled)? 4: 0);
		if (icaList[x].id == AES_128_ENCRYPT) { // check for the maximum size
		  if (*s390_kmc_functions[icaList[AES_256_ENCRYPT].id].enabled)
			icaList[x].property = icaList[x].property | 4; // 256 bit
		  if (*s390_kmc_functions[icaList[AES_192_ENCRYPT].id].enabled)
			icaList[x].property = icaList[x].property | 2; // 192 bit
		  if (*s390_kmc_functions[icaList[AES_128_ENCRYPT].id].enabled)
			icaList[x].property = icaList[x].property | 1; // 128 bit
		}
	break;
	case MSA4:
		icaList[x].flags = icaList[x].flags |
		((*s390_msa4_functions[icaList[x].id].enabled)? 4: 0);
		  if (icaList[x].id == AES_128_ENCRYPT) { // check for the maximum size
			if (*s390_msa4_functions[icaList[AES_256_ENCRYPT].id].enabled)
				icaList[x].property = icaList[x].property | 4; // 256 bit
			if (*s390_msa4_functions[icaList[AES_192_ENCRYPT].id].enabled)
				icaList[x].property = icaList[x].property | 2; // 192 bit
			if (*s390_msa4_functions[icaList[AES_128_ENCRYPT].id].enabled)
				icaList[x].property = icaList[x].property | 1; // 128 bit
		  }
		  else if (icaList[x].id == AES_128_XTS_ENCRYPT) { // check for the maximum size
			if      (*s390_msa4_functions[icaList[AES_256_XTS_ENCRYPT].id].enabled)
				icaList[x].property = icaList[x].property | 2; // 256 bit
			if (*s390_msa4_functions[icaList[AES_128_XTS_ENCRYPT].id].enabled)
				icaList[x].property = icaList[x].property | 1; // 128 bit
		}
	break;
	case PPNO:
		icaList[x].flags = icaList[x].flags |
		((*s390_ppno_functions[icaList[x].id].enabled)? 4: 0);
	break;
	default:
	break;
	}
  }
  return 0;
}

/**
 * Function that returns a list of crypto mechanisms supported by libica.
 * @param pmech_list
 *    Pointer to an array of libica_func_list_element
 *    If NULL, the API will return the number of elements to allocate
 *    in the @pmech_list_len parameter.
 *    If not NULL, libica will assume @pmech_list is an array that has
 *    @pmech_list_len elements.
 *    On success, @pmech_list will be filled out with the supported libica
 *    crypto mechanisms.
 * @param pmech_list_len
 *    number of list entries
 *    On input, pointer to the number of elements allocated in the
 *    @pmech_list array.
 *    On output, @pmech_list_len will contain the number of items copied to
 *    the @pmech_list array, or the number of items libica would have returned
 *    in case the @pmech_list parameter is set to NULL.
 *
 * @return
 *    0 on success
 *    EINVAL if at least one invalid parameter is given
 *
 *   A typical usage scenario would be that an exploiter makes a first call to
 *   ica_get_functionlist() with @pmech_list set to NULL in order to determine
 *   the number of elements to allocate. This is followed by a second call to
 *   ica_get_functionlist() with a valid pointer @pmech_list to an array of
 *   libica_func_list_element structures with @pmech_list_len elements.
 */
int s390_get_functionlist(libica_func_list_element *pmech_list,
				      unsigned int *pmech_list_len) {
  int x;

  if (!pmech_list_len) {
	return EINVAL;
  }

  if (!pmech_list) {
	*pmech_list_len = sizeof(icaList)/sizeof(libica_func_list_element_int);
	return 0;
  }
  else if (*pmech_list_len <
	  (sizeof(icaList)/sizeof(libica_func_list_element_int)) ) {
	return EINVAL;
  }

  for (x=0; x<*pmech_list_len; x++) {
      pmech_list[x].mech_mode_id = icaList[x].mech_mode_id;
      pmech_list[x].flags        = icaList[x].flags;
      pmech_list[x].property     = icaList[x].property;
  }

  return 0;
}

