2012-10-14 12:35:46 +00:00
/*
* sc - hsm - tool . c : SmartCard - HSM Management Tool
*
* Copyright ( C ) 2001 Juha Yrjölä < juha . yrjola @ iki . fi >
* Copyright ( C ) 2012 www . CardContact . de , Andreas Schwier , Minden , Germany
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "config.h"
# include <stdio.h>
# include <stdlib.h>
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# include <string.h>
# include <errno.h>
# include <ctype.h>
# include <sys/stat.h>
/* Requires openssl for dkek import */
2016-01-06 14:40:59 +00:00
# include <openssl/opensslv.h>
2012-10-14 12:35:46 +00:00
# include <openssl/opensslconf.h>
# include <openssl/bio.h>
# include <openssl/evp.h>
2013-02-06 15:47:08 +00:00
# include <openssl/bn.h>
# include <openssl/rand.h>
2013-05-25 02:22:28 +00:00
# include <openssl/err.h>
2012-10-14 12:35:46 +00:00
2016-01-06 14:40:59 +00:00
# include "libopensc/sc-ossl-compat.h"
2012-10-14 12:35:46 +00:00
# include "libopensc/opensc.h"
# include "libopensc/cardctl.h"
# include "libopensc/asn1.h"
# include "libopensc/card-sc-hsm.h"
# include "util.h"
static const char * app_name = " sc-hsm-tool " ;
static const char magic [ ] = " Salted__ " ;
static struct sc_aid sc_hsm_aid = { { 0xE8 , 0x2B , 0x06 , 0x01 , 0x04 , 0x01 , 0x81 , 0xC3 , 0x1F , 0x02 , 0x01 } , 11 } ;
static int opt_wait = 0 ;
2014-01-08 15:07:13 +00:00
static char * opt_reader = NULL ;
static char * opt_label = NULL ;
2012-10-14 12:35:46 +00:00
static int verbose = 0 ;
// Some reasonable maximums
# define MAX_CERT 4096
# define MAX_PRKD 256
2013-04-29 15:24:21 +00:00
# define MAX_KEY 1024
2012-10-14 12:35:46 +00:00
# define MAX_WRAPPED_KEY (MAX_CERT + MAX_PRKD + MAX_KEY)
2015-01-28 06:04:02 +00:00
# define SEED_LENGTH 16
2012-10-14 12:35:46 +00:00
enum {
OPT_SO_PIN = 0x100 ,
OPT_PIN ,
OPT_RETRY ,
2013-02-06 15:47:08 +00:00
OPT_PASSWORD ,
OPT_PASSWORD_SHARES_THRESHOLD ,
OPT_PASSWORD_SHARES_TOTAL
2012-10-14 12:35:46 +00:00
} ;
static const struct option options [ ] = {
2013-02-06 15:47:08 +00:00
{ " initialize " , 0 , NULL , ' X ' } ,
{ " create-dkek-share " , 1 , NULL , ' C ' } ,
{ " import-dkek-share " , 1 , NULL , ' I ' } ,
2016-09-20 09:24:40 +00:00
# ifdef PRINT_DKEK_SHARE
2016-07-10 12:08:48 +00:00
{ " print-dkek-share " , 1 , NULL , ' P ' } ,
2016-09-20 09:24:40 +00:00
# endif
2013-02-06 15:47:08 +00:00
{ " wrap-key " , 1 , NULL , ' W ' } ,
{ " unwrap-key " , 1 , NULL , ' U ' } ,
{ " dkek-shares " , 1 , NULL , ' s ' } ,
{ " so-pin " , 1 , NULL , OPT_SO_PIN } ,
{ " pin " , 1 , NULL , OPT_PIN } ,
{ " pin-retry " , 1 , NULL , OPT_RETRY } ,
{ " password " , 1 , NULL , OPT_PASSWORD } ,
{ " pwd-shares-threshold " , 1 , NULL , OPT_PASSWORD_SHARES_THRESHOLD } ,
{ " pwd-shares-total " , 1 , NULL , OPT_PASSWORD_SHARES_TOTAL } ,
{ " key-reference " , 1 , NULL , ' i ' } ,
2014-01-08 15:07:13 +00:00
{ " label " , 1 , NULL , ' l ' } ,
2013-02-06 15:47:08 +00:00
{ " force " , 0 , NULL , ' f ' } ,
{ " reader " , 1 , NULL , ' r ' } ,
{ " wait " , 0 , NULL , ' w ' } ,
{ " verbose " , 0 , NULL , ' v ' } ,
2012-10-14 12:35:46 +00:00
{ NULL , 0 , NULL , 0 }
} ;
static const char * option_help [ ] = {
" Initialize token " ,
" Create DKEK key share and save to <filename> " ,
" Import DKEK key share <filename> " ,
2016-09-20 09:24:40 +00:00
# ifdef PRINT_DKEK_SHARE
2016-07-10 12:08:48 +00:00
" Print HEX of DKEK key share <filename> " ,
2016-09-20 09:24:40 +00:00
# endif
2012-10-14 12:35:46 +00:00
" Wrap key and save to <filename> " ,
" Unwrap key read from <filename> " ,
" Number of DKEK shares [No DKEK] " ,
" Define security officer PIN (SO-PIN) " ,
" Define user PIN " ,
" Define user PIN retry counter " ,
" Define password for DKEK share " ,
2013-02-06 15:47:08 +00:00
" Define threshold for number of password shares required for reconstruction " ,
" Define number of password shares " ,
2012-10-14 12:35:46 +00:00
" Key reference for key wrap/unwrap " ,
2014-01-08 15:07:13 +00:00
" Token label for --initialize " ,
2012-10-14 12:35:46 +00:00
" Force replacement of key and certificate " ,
" Uses reader number <arg> [0] " ,
" Wait for a card to be inserted " ,
" Verbose operation. Use several times to enable debug output. " ,
} ;
2013-02-06 15:47:08 +00:00
typedef struct {
2016-01-06 14:40:59 +00:00
BIGNUM * x ;
BIGNUM * y ;
2013-02-06 15:47:08 +00:00
} secret_share_t ;
2012-10-14 12:35:46 +00:00
static sc_context_t * ctx = NULL ;
static sc_card_t * card = NULL ;
2013-02-06 15:47:08 +00:00
/**
* Generate a prime number
*
* The internal CPRNG is seeded using the provided seed value .
*
* @ param prime Pointer for storage of prime number
* @ param s Secret to share
2016-01-28 12:52:46 +00:00
* @ param bits Bit size of prime
2013-02-06 15:47:08 +00:00
* @ param rngSeed Seed value for CPRNG
2016-01-28 12:52:46 +00:00
* @ param rngSeedLength Length of Seed value for CPRNG
2013-02-06 15:47:08 +00:00
*
*/
2016-01-28 12:52:46 +00:00
static int generatePrime ( BIGNUM * prime , const BIGNUM * s , const int bits , unsigned char * rngSeed , const unsigned int rngSeedLength )
2013-06-04 07:32:51 +00:00
{
2016-01-28 12:52:46 +00:00
int max_rounds = 1000 ;
2013-02-06 15:47:08 +00:00
// Seed the RNG
2015-01-28 06:04:02 +00:00
RAND_seed ( rngSeed , rngSeedLength ) ;
2013-02-06 15:47:08 +00:00
// Clear the prime value
BN_clear ( prime ) ;
2016-01-28 12:52:46 +00:00
do {
// Generate random prime
2016-01-06 14:40:59 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x00908000L /* last parm is BN_GENCB which is null in our case */
BN_generate_prime_ex ( prime , bits , 1 , NULL , NULL , NULL ) ;
# else
2016-01-28 12:52:46 +00:00
BN_generate_prime ( prime , bits , 1 , NULL , NULL , NULL , NULL ) ;
2016-01-06 14:40:59 +00:00
# endif
2016-01-28 12:52:46 +00:00
} while ( ( BN_ucmp ( prime , s ) = = - 1 ) & & ( max_rounds - - > 0 ) ) ; // If prime < s or not reached 1000 tries
if ( max_rounds > 0 )
return 0 ;
else
return - 1 ; // We could not find a prime number
2013-02-06 15:47:08 +00:00
}
/**
* Helper method to calculate the y - value
* for a given x - value and a polynomial
*
* @ param x X - value
* @ param polynomial The underlying polynomial
* @ param t Threshold ( determines the degree of the polynomial )
* @ param prime Prime for finite field arithmetic
* @ param y Pointer for storage of calculated y - value
*/
2016-01-06 14:40:59 +00:00
static void calculatePolynomialValue ( const BIGNUM * x , BIGNUM * * polynomial , const unsigned char t , const BIGNUM * prime , BIGNUM * y )
2013-06-04 07:32:51 +00:00
{
2013-02-06 15:47:08 +00:00
BIGNUM * * pp ;
2016-01-06 14:40:59 +00:00
BIGNUM * temp ;
BIGNUM * exponent ;
2013-02-06 15:47:08 +00:00
unsigned long exp ;
BN_CTX * ctx ;
// Create context for temporary variables of OpenSSL engine
ctx = BN_CTX_new ( ) ;
2016-01-06 14:40:59 +00:00
temp = BN_new ( ) ;
exponent = BN_new ( ) ;
2013-02-06 15:47:08 +00:00
// Set y to ZERO
BN_zero ( y ) ;
/* Initialize the result using the secret value at position 0 of the polynomial */
pp = polynomial ;
BN_copy ( y , * pp ) ;
pp + + ;
for ( exp = 1 ; exp < t ; exp + + ) {
2016-01-06 14:40:59 +00:00
BN_copy ( temp , x ) ;
2013-02-06 15:47:08 +00:00
2016-01-06 14:40:59 +00:00
BN_set_word ( exponent , exp ) ;
2013-02-06 15:47:08 +00:00
// temp = x^exponent mod prime
2016-01-06 14:40:59 +00:00
BN_mod_exp ( temp , x , exponent , prime , ctx ) ;
2013-02-06 15:47:08 +00:00
// exponent = temp * a = a * x^exponent mod prime
2016-01-06 14:40:59 +00:00
BN_mod_mul ( exponent , temp , * pp , prime , ctx ) ;
2013-02-06 15:47:08 +00:00
// add the temp value from exponent to y
2016-01-06 14:40:59 +00:00
BN_copy ( temp , y ) ;
BN_mod_add ( y , temp , exponent , prime , ctx ) ;
2013-02-06 15:47:08 +00:00
pp + + ;
}
2016-01-06 14:40:59 +00:00
BN_clear_free ( temp ) ;
BN_clear_free ( exponent ) ;
2013-02-06 15:47:08 +00:00
BN_CTX_free ( ctx ) ;
}
/**
* Create shares depending on the provided parameters
*
* @ param s Secret value to share
* @ param t Threshold needed to reconstruct the secret
* @ param n Total number of shares
* @ param prime Prime for finite field arithmetic
* @ param shares Pointer for storage of calculated shares ( must be big enough to hold n shares )
*/
2016-01-06 14:40:59 +00:00
static int createShares ( const BIGNUM * s , const unsigned char t , const unsigned char n , const BIGNUM * prime , secret_share_t * shares )
2013-06-04 07:32:51 +00:00
{
2013-02-06 15:47:08 +00:00
// Array representing the polynomial a(x) = s + a_1 * x + ... + a_n-1 * x^n-1 mod p
BIGNUM * * polynomial = malloc ( n * sizeof ( BIGNUM * ) ) ;
BIGNUM * * pp ;
unsigned long i ;
secret_share_t * sp ;
2017-04-20 19:08:49 +00:00
if ( ! polynomial )
return - 1 ;
2013-02-06 15:47:08 +00:00
// Set the secret value as the constant part of the polynomial
pp = polynomial ;
* pp = BN_new ( ) ;
BN_copy ( * pp , s ) ;
pp + + ;
// Initialize and generate some random values for coefficients a_x in the remaining polynomial
for ( i = 1 ; i < t ; i + + ) {
* pp = BN_new ( ) ;
2016-01-06 14:40:59 +00:00
BN_rand_range ( * pp , prime ) ;
2013-02-06 15:47:08 +00:00
pp + + ;
}
sp = shares ;
// Now calculate n secret shares
for ( i = 1 ; i < = n ; i + + ) {
2016-01-06 14:40:59 +00:00
sp - > x = BN_new ( ) ;
sp - > y = BN_new ( ) ;
BN_set_word ( ( sp - > x ) , i ) ;
calculatePolynomialValue ( sp - > x , polynomial , t , prime , ( sp - > y ) ) ;
2013-02-06 15:47:08 +00:00
sp + + ;
}
// Deallocate the resource of the polynomial
pp = polynomial ;
for ( i = 0 ; i < t ; i + + ) {
BN_clear_free ( * pp ) ;
pp + + ;
}
free ( polynomial ) ;
return 0 ;
}
/**
* Reconstruct secret using the provided shares
*
* @ param shares Shares used to reconstruct secret ( should contain t entries )
* @ param t Threshold used to reconstruct the secret
* @ param prime Prime for finite field arithmetic
* @ param s Pointer for storage of calculated secred
*/
2016-01-06 14:40:59 +00:00
static int reconstructSecret ( secret_share_t * shares , unsigned char t , const BIGNUM * prime , BIGNUM * s )
2013-06-04 07:32:51 +00:00
{
2013-02-06 15:47:08 +00:00
unsigned char i ;
unsigned char j ;
// Array representing the polynomial a(x) = s + a_1 * x + ... + a_n-1 * x^n-1 mod p
BIGNUM * * bValue = malloc ( t * sizeof ( BIGNUM * ) ) ;
BIGNUM * * pbValue ;
2016-01-06 14:40:59 +00:00
BIGNUM * numerator ;
BIGNUM * denominator ;
BIGNUM * temp ;
2013-02-06 15:47:08 +00:00
secret_share_t * sp_i ;
secret_share_t * sp_j ;
BN_CTX * ctx ;
2017-04-20 19:08:49 +00:00
if ( ! bValue )
return - 1 ;
2013-02-06 15:47:08 +00:00
// Initialize
pbValue = bValue ;
for ( i = 0 ; i < t ; i + + ) {
* pbValue = BN_new ( ) ;
pbValue + + ;
}
2016-01-06 14:40:59 +00:00
numerator = BN_new ( ) ;
denominator = BN_new ( ) ;
temp = BN_new ( ) ;
2013-02-06 15:47:08 +00:00
// Create context for temporary variables of engine
ctx = BN_CTX_new ( ) ;
pbValue = bValue ;
sp_i = shares ;
for ( i = 0 ; i < t ; i + + ) {
2016-01-06 14:40:59 +00:00
BN_one ( numerator ) ;
BN_one ( denominator ) ;
2013-02-06 15:47:08 +00:00
sp_j = shares ;
for ( j = 0 ; j < t ; j + + ) {
if ( i = = j ) {
sp_j + + ;
continue ;
}
2016-01-06 14:40:59 +00:00
BN_mul ( numerator , numerator , ( sp_j - > x ) , ctx ) ;
BN_sub ( temp , ( sp_j - > x ) , ( sp_i - > x ) ) ;
BN_mul ( denominator , denominator , temp , ctx ) ;
2013-02-06 15:47:08 +00:00
sp_j + + ;
}
/*
* Use the modular inverse value of the denominator for the
* multiplication
*/
2016-01-06 14:40:59 +00:00
if ( BN_mod_inverse ( denominator , denominator , prime , ctx ) = = NULL ) {
2015-04-29 21:22:30 +00:00
free ( bValue ) ;
2013-02-06 15:47:08 +00:00
return - 1 ;
}
2016-01-06 14:40:59 +00:00
BN_mod_mul ( * pbValue , numerator , denominator , prime , ctx ) ;
2013-02-06 15:47:08 +00:00
pbValue + + ;
sp_i + + ;
}
/*
* Calculate the secret by multiplying all y - values with their
* corresponding intermediate values
*/
pbValue = bValue ;
sp_i = shares ;
BN_zero ( s ) ;
for ( i = 0 ; i < t ; i + + ) {
2016-01-06 14:40:59 +00:00
BN_mul ( temp , ( sp_i - > y ) , * pbValue , ctx ) ;
BN_add ( s , s , temp ) ;
2013-02-06 15:47:08 +00:00
pbValue + + ;
sp_i + + ;
}
// Perform modulo operation and copy result
2016-01-06 14:40:59 +00:00
BN_nnmod ( temp , s , prime , ctx ) ;
BN_copy ( s , temp ) ;
2013-02-06 15:47:08 +00:00
2016-01-06 14:40:59 +00:00
BN_clear_free ( numerator ) ;
BN_clear_free ( denominator ) ;
BN_clear_free ( temp ) ;
2013-02-06 15:47:08 +00:00
BN_CTX_free ( ctx ) ;
// Deallocate the resource of the polynomial
pbValue = bValue ;
for ( i = 0 ; i < t ; i + + ) {
BN_clear_free ( * pbValue ) ;
pbValue + + ;
}
free ( bValue ) ;
return 0 ;
}
/**
* Helper method to free allocated resources
*
* @ param shares Shares to be freed
* @ param n Total number of shares to freed
*/
2013-06-04 07:32:51 +00:00
static int cleanUpShares ( secret_share_t * shares , unsigned char n )
{
2013-02-06 15:47:08 +00:00
int i ;
secret_share_t * sp ;
sp = shares ;
for ( i = 0 ; i < n ; i + + ) {
2016-01-06 14:40:59 +00:00
BN_clear_free ( ( sp - > x ) ) ;
BN_clear_free ( ( sp - > y ) ) ;
2013-02-06 15:47:08 +00:00
sp + + ;
}
free ( shares ) ;
return 0 ;
}
2013-06-04 07:32:51 +00:00
void clearScreen ( )
{
2015-03-22 16:38:51 +00:00
if ( system ( " clear " ) ) {
if ( system ( " cls " ) ) {
fprintf ( stderr , " Clearing the screen failed \n " ) ;
}
}
2013-02-06 15:47:08 +00:00
}
2013-06-04 07:32:51 +00:00
void waitForEnterKeyPressed ( )
{
2015-01-24 18:47:01 +00:00
int c ;
2013-02-06 15:47:08 +00:00
fflush ( stdout ) ;
while ( ( c = getchar ( ) ) ! = ' \n ' & & c ! = EOF ) {
}
}
2013-06-04 07:32:51 +00:00
static void print_dkek_info ( sc_cardctl_sc_hsm_dkek_t * dkekinfo )
{
2012-10-14 12:35:46 +00:00
printf ( " DKEK shares : %d \n " , dkekinfo - > dkek_shares ) ;
if ( dkekinfo - > outstanding_shares > 0 ) {
printf ( " DKEK import pending, %d share(s) still missing \n " , dkekinfo - > outstanding_shares ) ;
} else {
printf ( " DKEK key check value : " ) ;
util_hex_dump ( stdout , dkekinfo - > key_check_value , 8 , NULL ) ;
printf ( " \n " ) ;
}
}
static void print_info ( sc_card_t * card , sc_file_t * file )
{
int r , tries_left ;
struct sc_pin_cmd_data data ;
sc_cardctl_sc_hsm_dkek_t dkekinfo ;
2015-09-03 19:18:40 +00:00
u8 major , minor , opt ;
2012-10-14 12:35:46 +00:00
major = file - > prop_attr [ file - > prop_attr_len - 2 ] ;
minor = file - > prop_attr [ file - > prop_attr_len - 1 ] ;
printf ( " Version : %d.%d \n " , ( int ) major , ( int ) minor ) ;
2015-09-03 19:18:40 +00:00
if ( file - > prop_attr_len > 2 ) { /* Version >= 2.0 */
opt = file - > prop_attr [ file - > prop_attr_len - 4 ] ;
if ( opt ! = 0 ) {
printf ( " Config options : \n " ) ;
if ( opt & INIT_RRC_ENABLED ) {
printf ( " User PIN reset with SO-PIN enabled \n " ) ;
}
if ( opt & INIT_TRANSPORT_PIN ) {
printf ( " Transport-PIN mode enabled \n " ) ;
}
}
2012-10-14 12:35:46 +00:00
2015-09-03 19:18:40 +00:00
/* Try to update SO-PIN info from card */
memset ( & data , 0 , sizeof ( data ) ) ;
data . cmd = SC_PIN_CMD_GET_INFO ;
data . pin_type = SC_AC_CHV ;
data . pin_reference = ID_SO_PIN ;
2012-10-14 12:35:46 +00:00
2015-09-03 19:18:40 +00:00
r = sc_pin_cmd ( card , & data , & tries_left ) ;
if ( r = = SC_ERROR_DATA_OBJECT_NOT_FOUND ) {
printf ( " SmartCard-HSM has never been initialized. Please use --initialize to set SO-PIN and user PIN. \n " ) ;
2012-10-14 12:35:46 +00:00
} else {
2015-09-03 19:18:40 +00:00
if ( tries_left = = 0 ) {
printf ( " SO-PIN locked \n " ) ;
} else {
printf ( " SO-PIN tries left : %d \n " , tries_left ) ;
}
/* Try to update PIN info from card */
memset ( & data , 0 , sizeof ( data ) ) ;
data . cmd = SC_PIN_CMD_GET_INFO ;
data . pin_type = SC_AC_CHV ;
data . pin_reference = ID_USER_PIN ;
r = sc_pin_cmd ( card , & data , & tries_left ) ;
if ( r = = SC_ERROR_CARD_CMD_FAILED ) {
printf ( " Public key authentication active. \n " ) ;
} else if ( r = = SC_ERROR_REF_DATA_NOT_USABLE ) {
printf ( " Transport-PIN active. Please change to user selected PIN first. \n " ) ;
} else {
if ( tries_left = = 0 ) {
printf ( " User PIN locked \n " ) ;
} else {
printf ( " User PIN tries left : %d \n " , tries_left ) ;
}
}
}
} else { /* Version < 2.0 */
/* Try to update PIN info from card */
memset ( & data , 0 , sizeof ( data ) ) ;
data . cmd = SC_PIN_CMD_GET_INFO ;
data . pin_type = SC_AC_CHV ;
data . pin_reference = ID_USER_PIN ;
r = sc_pin_cmd ( card , & data , & tries_left ) ;
if ( r = = SC_ERROR_REF_DATA_NOT_USABLE ) {
printf ( " SmartCard-HSM has never been initialized. Please use --initialize to set SO-PIN and user PIN. \n " ) ;
} else {
if ( tries_left = = 0 ) {
printf ( " User PIN locked \n " ) ;
} else {
printf ( " User PIN tries left : %d \n " , tries_left ) ;
}
2012-10-14 12:35:46 +00:00
}
}
memset ( & dkekinfo , 0 , sizeof ( dkekinfo ) ) ;
r = sc_card_ctl ( card , SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE , ( void * ) & dkekinfo ) ;
if ( r = = SC_ERROR_INS_NOT_SUPPORTED ) { // Not supported or not initialized for key shares
return ;
}
if ( r < 0 ) {
fprintf ( stderr , " sc_card_ctl(*, SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, *) failed with %s \n " , sc_strerror ( r ) ) ;
}
print_dkek_info ( & dkekinfo ) ;
}
2014-08-25 19:46:52 +00:00
static int initialize ( sc_card_t * card , const char * so_pin , const char * user_pin , int retry_counter , int dkek_shares , const char * label )
2012-10-14 12:35:46 +00:00
{
sc_cardctl_sc_hsm_init_param_t param ;
size_t len ;
char * _so_pin = NULL , * _user_pin = NULL ;
int r ;
if ( so_pin = = NULL ) {
2012-11-16 14:48:37 +00:00
printf ( " Enter SO-PIN (16 hexadecimal characters) : " ) ;
2012-10-14 12:35:46 +00:00
util_getpass ( & _so_pin , NULL , stdin ) ;
printf ( " \n " ) ;
} else {
_so_pin = ( char * ) so_pin ;
}
2012-11-16 14:48:37 +00:00
len = sizeof ( param . init_code ) ;
r = sc_hex_to_bin ( _so_pin , param . init_code , & len ) ;
if ( r < 0 ) {
fprintf ( stderr , " Error decoding initialization code (%s) \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-11-16 14:48:37 +00:00
}
if ( len ! = 8 ) {
fprintf ( stderr , " SO-PIN must be a hexadecimal string of 16 characters \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-11-16 14:48:37 +00:00
}
2012-10-14 12:35:46 +00:00
if ( user_pin = = NULL ) {
2012-11-16 14:48:37 +00:00
printf ( " Enter initial User-PIN (6 - 16 characters) : " ) ;
2012-10-14 12:35:46 +00:00
util_getpass ( & _user_pin , NULL , stdin ) ;
printf ( " \n " ) ;
} else {
_user_pin = ( char * ) user_pin ;
}
2012-11-16 14:48:37 +00:00
param . user_pin_len = strlen ( _user_pin ) ;
if ( param . user_pin_len < 6 ) {
fprintf ( stderr , " PIN must be at least 6 characters long \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
2012-11-16 14:48:37 +00:00
if ( param . user_pin_len > 16 ) {
fprintf ( stderr , " PIN must not be longer than 16 characters \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-11-16 14:48:37 +00:00
}
if ( ( param . user_pin_len = = 6 ) & & ( retry_counter > 3 ) ) {
fprintf ( stderr , " Retry counter must not exceed 3 for a 6 digit PIN. Use a longer PIN for a higher retry counter. \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-11-16 14:48:37 +00:00
}
if ( ( param . user_pin_len = = 7 ) & & ( retry_counter > 5 ) ) {
fprintf ( stderr , " Retry counter must not exceed 5 for a 7 digit PIN. Use a longer PIN for a higher retry counter. \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-11-16 14:48:37 +00:00
}
if ( retry_counter > 10 ) {
fprintf ( stderr , " Retry counter must not exceed 10 \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
param . user_pin = ( u8 * ) _user_pin ;
param . user_pin_retry_counter = ( u8 ) retry_counter ;
param . options [ 0 ] = 0x00 ;
param . options [ 1 ] = 0x01 ;
param . dkek_shares = ( char ) dkek_shares ;
2014-01-08 15:07:13 +00:00
param . label = ( char * ) label ;
2012-10-14 12:35:46 +00:00
r = sc_card_ctl ( card , SC_CARDCTL_SC_HSM_INITIALIZE , ( void * ) & param ) ;
if ( r < 0 ) {
fprintf ( stderr , " sc_card_ctl(*, SC_CARDCTL_SC_HSM_INITIALIZE, *) failed with %s \n " , sc_strerror ( r ) ) ;
}
2014-08-25 19:46:52 +00:00
return 0 ;
2012-10-14 12:35:46 +00:00
}
2013-06-04 07:32:51 +00:00
static int recreate_password_from_shares ( char * * pwd , int * pwdlen , int num_of_password_shares )
{
2013-02-06 15:47:08 +00:00
int r , i ;
2016-01-06 14:40:59 +00:00
BIGNUM * prime ;
BIGNUM * secret ;
2013-02-06 15:47:08 +00:00
BIGNUM * p ;
char inbuf [ 64 ] ;
2013-05-27 14:44:32 +00:00
unsigned char bin [ 64 ] ;
2013-04-29 15:24:21 +00:00
size_t binlen = 0 ;
2013-05-27 14:44:32 +00:00
unsigned char * ip ;
2013-02-06 15:47:08 +00:00
secret_share_t * shares = NULL ;
secret_share_t * sp ;
2015-03-22 16:38:51 +00:00
if ( num_of_password_shares < 2 ) {
fprintf ( stderr , " --pwd-shares-total must 2 or larger \n " ) ;
return - 1 ;
}
2017-04-20 19:08:49 +00:00
// Allocate data buffer for the shares
shares = malloc ( num_of_password_shares * sizeof ( secret_share_t ) ) ;
if ( ! shares )
return - 1 ;
2013-02-06 15:47:08 +00:00
/*
* Initialize prime and secret
*/
2016-01-06 14:40:59 +00:00
prime = BN_new ( ) ;
secret = BN_new ( ) ;
2013-02-06 15:47:08 +00:00
printf ( " \n Deciphering the DKEK for import into the SmartCard-HSM requires %i key custodians " , num_of_password_shares ) ;
printf ( " \n to present their share. Only the first key custodian needs to enter the public prime. " ) ;
printf ( " \n Please remember to present the share id as well as the share value. " ) ;
printf ( " \n \n Please enter prime: " ) ;
memset ( inbuf , 0 , sizeof ( inbuf ) ) ;
2015-03-22 16:38:51 +00:00
if ( fgets ( inbuf , sizeof ( inbuf ) , stdin ) = = NULL ) {
fprintf ( stderr , " Input aborted \n " ) ;
2015-11-01 09:44:24 +00:00
free ( shares ) ;
2015-03-22 16:38:51 +00:00
return - 1 ;
}
2013-02-06 15:47:08 +00:00
binlen = 64 ;
sc_hex_to_bin ( inbuf , bin , & binlen ) ;
2016-01-06 14:40:59 +00:00
BN_bin2bn ( bin , binlen , prime ) ;
2013-02-06 15:47:08 +00:00
sp = shares ;
for ( i = 0 ; i < num_of_password_shares ; i + + ) {
clearScreen ( ) ;
printf ( " Press <enter> to enter share %i of %i \n \n " , i + 1 , num_of_password_shares ) ;
waitForEnterKeyPressed ( ) ;
clearScreen ( ) ;
2016-01-06 14:40:59 +00:00
sp - > x = BN_new ( ) ;
sp - > y = BN_new ( ) ;
2013-02-06 15:47:08 +00:00
printf ( " Share %i of %i \n \n " , i + 1 , num_of_password_shares ) ;
printf ( " Please enter share ID: " ) ;
memset ( inbuf , 0 , sizeof ( inbuf ) ) ;
2015-03-22 16:38:51 +00:00
if ( fgets ( inbuf , sizeof ( inbuf ) , stdin ) = = NULL ) {
fprintf ( stderr , " Input aborted \n " ) ;
2017-04-03 11:43:30 +00:00
free ( shares ) ;
2015-03-22 16:38:51 +00:00
return - 1 ;
}
2016-01-06 14:40:59 +00:00
p = ( sp - > x ) ;
2013-02-06 15:47:08 +00:00
BN_hex2bn ( & p , inbuf ) ;
printf ( " Please enter share value: " ) ;
memset ( inbuf , 0 , sizeof ( inbuf ) ) ;
2015-03-22 16:38:51 +00:00
if ( fgets ( inbuf , sizeof ( inbuf ) , stdin ) = = NULL ) {
fprintf ( stderr , " Input aborted \n " ) ;
2017-04-03 11:43:30 +00:00
free ( shares ) ;
2015-03-22 16:38:51 +00:00
return - 1 ;
}
2013-02-06 15:47:08 +00:00
binlen = 64 ;
sc_hex_to_bin ( inbuf , bin , & binlen ) ;
2016-01-06 14:40:59 +00:00
BN_bin2bn ( bin , binlen , ( sp - > y ) ) ;
2013-02-06 15:47:08 +00:00
sp + + ;
}
clearScreen ( ) ;
2016-01-06 14:40:59 +00:00
r = reconstructSecret ( shares , num_of_password_shares , prime , secret ) ;
2013-02-06 15:47:08 +00:00
if ( r < 0 ) {
printf ( " \n Error during reconstruction of secret. Wrong shares? \n " ) ;
2015-04-29 21:22:30 +00:00
cleanUpShares ( shares , num_of_password_shares ) ;
2013-02-06 15:47:08 +00:00
return r ;
}
/*
* Encode the secret value
*/
2013-05-27 14:44:32 +00:00
ip = ( unsigned char * ) inbuf ;
2016-01-06 14:40:59 +00:00
* pwdlen = BN_bn2bin ( secret , ip ) ;
2013-02-06 15:47:08 +00:00
* pwd = calloc ( 1 , * pwdlen ) ;
2017-04-20 19:08:49 +00:00
if ( * pwd ) {
memcpy ( * pwd , ip , * pwdlen ) ;
}
2013-02-06 15:47:08 +00:00
cleanUpShares ( shares , num_of_password_shares ) ;
2016-01-06 14:40:59 +00:00
BN_clear_free ( prime ) ;
BN_clear_free ( secret ) ;
2013-02-06 15:47:08 +00:00
2017-04-20 19:08:49 +00:00
return * pwd ? 0 : - 1 ;
2013-02-06 15:47:08 +00:00
}
2014-12-07 16:19:57 +00:00
static int import_dkek_share ( sc_card_t * card , const char * inf , int iter , const char * password , int num_of_password_shares )
2012-10-14 12:35:46 +00:00
{
sc_cardctl_sc_hsm_dkek_t dkekinfo ;
2016-01-06 14:40:59 +00:00
EVP_CIPHER_CTX * ctx = NULL ;
2012-10-14 12:35:46 +00:00
FILE * in = NULL ;
u8 filebuff [ 64 ] , key [ EVP_MAX_KEY_LENGTH ] , iv [ EVP_MAX_IV_LENGTH ] , outbuff [ 64 ] ;
char * pwd = NULL ;
2013-02-06 15:47:08 +00:00
int r , outlen , pwdlen ;
2012-10-14 12:35:46 +00:00
2014-08-25 19:46:52 +00:00
if ( inf = = NULL ) {
fprintf ( stderr , " No file name specified for DKEK share \n " ) ;
return - 1 ;
}
2012-10-14 12:35:46 +00:00
in = fopen ( inf , " rb " ) ;
if ( in = = NULL ) {
perror ( inf ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( fread ( filebuff , 1 , sizeof ( filebuff ) , in ) ! = sizeof ( filebuff ) ) {
perror ( inf ) ;
2015-04-29 21:22:30 +00:00
fclose ( in ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
fclose ( in ) ;
if ( memcmp ( filebuff , magic , sizeof ( magic ) - 1 ) ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " File %s is not a DKEK share \n " , inf ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( password = = NULL ) {
2013-02-06 15:47:08 +00:00
if ( num_of_password_shares = = - 1 ) {
printf ( " Enter password to decrypt DKEK share : " ) ;
util_getpass ( & pwd , NULL , stdin ) ;
pwdlen = strlen ( pwd ) ;
printf ( " \n " ) ;
} else {
r = recreate_password_from_shares ( & pwd , & pwdlen , num_of_password_shares ) ;
if ( r < 0 ) {
2014-08-25 19:46:52 +00:00
return - 1 ;
2013-02-06 15:47:08 +00:00
}
}
2012-10-14 12:35:46 +00:00
} else {
2014-12-07 16:19:57 +00:00
pwd = ( char * ) password ;
2013-02-06 15:47:08 +00:00
pwdlen = strlen ( password ) ;
2012-10-14 12:35:46 +00:00
}
printf ( " Deciphering DKEK share, please wait... \n " ) ;
2013-02-06 15:47:08 +00:00
EVP_BytesToKey ( EVP_aes_256_cbc ( ) , EVP_md5 ( ) , filebuff + 8 , ( u8 * ) pwd , pwdlen , iter , key , iv ) ;
2012-10-14 12:35:46 +00:00
OPENSSL_cleanse ( pwd , strlen ( pwd ) ) ;
if ( password = = NULL ) {
free ( pwd ) ;
}
2016-01-06 14:40:59 +00:00
ctx = EVP_CIPHER_CTX_new ( ) ;
EVP_DecryptInit_ex ( ctx , EVP_aes_256_cbc ( ) , NULL , key , iv ) ;
if ( ! EVP_DecryptUpdate ( ctx , outbuff , & outlen , filebuff + 16 , sizeof ( filebuff ) - 16 ) ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Error decrypting DKEK share. Password correct ? \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
2016-01-06 14:40:59 +00:00
if ( ! EVP_DecryptFinal_ex ( ctx , outbuff + outlen , & r ) ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Error decrypting DKEK share. Password correct ? \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
memset ( & dkekinfo , 0 , sizeof ( dkekinfo ) ) ;
memcpy ( dkekinfo . dkek_share , outbuff , sizeof ( dkekinfo . dkek_share ) ) ;
dkekinfo . importShare = 1 ;
OPENSSL_cleanse ( outbuff , sizeof ( outbuff ) ) ;
r = sc_card_ctl ( card , SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE , ( void * ) & dkekinfo ) ;
OPENSSL_cleanse ( & dkekinfo . dkek_share , sizeof ( dkekinfo . dkek_share ) ) ;
2016-01-06 14:40:59 +00:00
EVP_CIPHER_CTX_free ( ctx ) ;
2012-10-14 12:35:46 +00:00
if ( r = = SC_ERROR_INS_NOT_SUPPORTED ) { // Not supported or not initialized for key shares
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Not supported by card or card not initialized for key share usage \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( r < 0 ) {
fprintf ( stderr , " sc_card_ctl(*, SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, *) failed with %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
printf ( " DKEK share imported \n " ) ;
print_dkek_info ( & dkekinfo ) ;
2014-08-25 19:46:52 +00:00
return 0 ;
2012-10-14 12:35:46 +00:00
}
2016-07-10 12:08:48 +00:00
static int print_dkek_share ( sc_card_t * card , const char * inf , int iter , const char * password , int num_of_password_shares )
{
// hex output can be used in the SCSH shell with the
// decrypt_keyblob.js file
sc_cardctl_sc_hsm_dkek_t dkekinfo ;
2016-01-06 14:40:59 +00:00
EVP_CIPHER_CTX * ctx = NULL ;
2016-07-10 12:08:48 +00:00
FILE * in = NULL ;
u8 filebuff [ 64 ] , key [ EVP_MAX_KEY_LENGTH ] , iv [ EVP_MAX_IV_LENGTH ] , outbuff [ 64 ] ;
char * pwd = NULL ;
int r , outlen , pwdlen ;
u8 i ;
if ( inf = = NULL ) {
fprintf ( stderr , " No file name specified for DKEK share \n " ) ;
return - 1 ;
}
in = fopen ( inf , " rb " ) ;
if ( in = = NULL ) {
perror ( inf ) ;
return - 1 ;
}
if ( fread ( filebuff , 1 , sizeof ( filebuff ) , in ) ! = sizeof ( filebuff ) ) {
perror ( inf ) ;
fclose ( in ) ;
return - 1 ;
}
2012-10-14 12:35:46 +00:00
2016-07-10 12:08:48 +00:00
fclose ( in ) ;
if ( memcmp ( filebuff , magic , sizeof ( magic ) - 1 ) ) {
fprintf ( stderr , " File %s is not a DKEK share \n " , inf ) ;
return - 1 ;
}
if ( password = = NULL ) {
if ( num_of_password_shares = = - 1 ) {
printf ( " Enter password to decrypt DKEK share : " ) ;
util_getpass ( & pwd , NULL , stdin ) ;
pwdlen = strlen ( pwd ) ;
printf ( " \n " ) ;
} else {
r = recreate_password_from_shares ( & pwd , & pwdlen , num_of_password_shares ) ;
if ( r < 0 ) {
return - 1 ;
}
}
} else {
pwd = ( char * ) password ;
pwdlen = strlen ( password ) ;
}
printf ( " Deciphering DKEK share, please wait... \n " ) ;
EVP_BytesToKey ( EVP_aes_256_cbc ( ) , EVP_md5 ( ) , filebuff + 8 , ( u8 * ) pwd , pwdlen , iter , key , iv ) ;
OPENSSL_cleanse ( pwd , strlen ( pwd ) ) ;
if ( password = = NULL ) {
free ( pwd ) ;
}
2016-01-06 14:40:59 +00:00
ctx = EVP_CIPHER_CTX_new ( ) ;
EVP_DecryptInit_ex ( ctx , EVP_aes_256_cbc ( ) , NULL , key , iv ) ;
if ( ! EVP_DecryptUpdate ( ctx , outbuff , & outlen , filebuff + 16 , sizeof ( filebuff ) - 16 ) ) {
2016-07-10 12:08:48 +00:00
fprintf ( stderr , " Error decrypting DKEK share. Password correct ? \n " ) ;
return - 1 ;
}
2016-01-06 14:40:59 +00:00
if ( ! EVP_DecryptFinal_ex ( ctx , outbuff + outlen , & r ) ) {
2016-07-10 12:08:48 +00:00
fprintf ( stderr , " Error decrypting DKEK share. Password correct ? \n " ) ;
return - 1 ;
}
memset ( & dkekinfo , 0 , sizeof ( dkekinfo ) ) ;
memcpy ( dkekinfo . dkek_share , outbuff , sizeof ( dkekinfo . dkek_share ) ) ;
dkekinfo . importShare = 1 ;
OPENSSL_cleanse ( outbuff , sizeof ( outbuff ) ) ;
printf ( " DKEK Share HEX: \n \n " ) ;
for ( i = 0 ; i < sizeof ( dkekinfo . dkek_share ) ; i + + )
{
printf ( " %02X " , dkekinfo . dkek_share [ i ] ) ;
}
printf ( " \n \n " ) ;
OPENSSL_cleanse ( & dkekinfo . dkek_share , sizeof ( dkekinfo . dkek_share ) ) ;
2016-01-06 14:40:59 +00:00
EVP_CIPHER_CTX_free ( ctx ) ;
2016-07-10 12:08:48 +00:00
if ( r = = SC_ERROR_INS_NOT_SUPPORTED ) { // Not supported or not initialized for key shares
fprintf ( stderr , " Not supported by card or card not initialized for key share usage \n " ) ;
return - 1 ;
}
if ( r < 0 ) {
fprintf ( stderr , " sc_card_ctl(*, SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, *) failed with %s \n " , sc_strerror ( r ) ) ;
return - 1 ;
}
//printf("DKEK share imported\n");
//print_dkek_info(&dkekinfo);
return 0 ;
}
2012-10-14 12:35:46 +00:00
2013-02-06 15:47:08 +00:00
static void ask_for_password ( char * * pwd , int * pwdlen )
{
char * refpwd = NULL ;
printf ( " \n The DKEK share will be enciphered using a key derived from a user supplied password. \n " ) ;
printf ( " The security of the DKEK share relies on a well chosen and sufficiently long password. \n " ) ;
printf ( " The recommended length is more than 10 characters, which are mixed letters, numbers and \n " ) ;
printf ( " symbols. \n \n " ) ;
printf ( " Please keep the generated DKEK share file in a safe location. We also recommend to keep a \n " ) ;
printf ( " paper printout, in case the electronic version becomes unavailable. A printable version \n " ) ;
printf ( " of the file can be generated using \" openssl base64 -in <filename> \" . \n " ) ;
while ( 1 ) {
printf ( " Enter password to encrypt DKEK share : " ) ;
util_getpass ( pwd , NULL , stdin ) ;
printf ( " \n " ) ;
if ( strlen ( * pwd ) < 6 ) {
printf ( " Password way to short. Please retry. \n " ) ;
continue ;
}
printf ( " Please retype password to confirm : " ) ;
util_getpass ( & refpwd , NULL , stdin ) ;
printf ( " \n " ) ;
if ( strcmp ( * pwd , refpwd ) ) {
printf ( " Passwords do not match. Please retry. \n " ) ;
continue ;
}
* pwdlen = strlen ( * pwd ) ;
break ;
}
OPENSSL_cleanse ( refpwd , strlen ( refpwd ) ) ;
free ( refpwd ) ;
}
2015-03-22 16:38:51 +00:00
static int generate_pwd_shares ( sc_card_t * card , char * * pwd , int * pwdlen , int password_shares_threshold , int password_shares_total )
2013-02-06 15:47:08 +00:00
{
2015-03-22 16:38:51 +00:00
int r , i ;
2016-01-06 14:40:59 +00:00
BIGNUM * prime ;
BIGNUM * secret ;
2013-05-27 14:44:32 +00:00
unsigned char buf [ 64 ] ;
2013-02-06 15:47:08 +00:00
char hex [ 64 ] ;
int l ;
secret_share_t * shares = NULL ;
secret_share_t * sp ;
u8 rngseed [ 16 ] ;
2015-03-22 16:38:51 +00:00
if ( ( password_shares_threshold = = - 1 ) | | ( password_shares_total = = - 1 ) ) {
fprintf ( stderr , " Must specify both, --pwd-shares-total and --pwd-shares-threshold \n " ) ;
return - 1 ;
}
if ( password_shares_total < 3 ) {
fprintf ( stderr , " --pwd-shares-total must be 3 or larger \n " ) ;
return - 1 ;
}
if ( password_shares_threshold < 2 ) {
fprintf ( stderr , " --pwd-shares-threshold must 2 or larger \n " ) ;
return - 1 ;
}
if ( password_shares_threshold > password_shares_total ) {
fprintf ( stderr , " --pwd-shares-threshold must be smaller or equal to --pwd-shares-total \n " ) ;
return - 1 ;
}
2013-02-06 15:47:08 +00:00
printf ( " \n The DKEK will be enciphered using a randomly generated 64 bit password. \n " ) ;
printf ( " This password is split using a (%i-of-%i) threshold scheme. \n \n " , password_shares_threshold , password_shares_total ) ;
printf ( " Please keep the generated and encrypted DKEK file in a safe location. We also recommend \n " ) ;
printf ( " to keep a paper printout, in case the electronic version becomes unavailable. A printable version \n " ) ;
printf ( " of the file can be generated using \" openssl base64 -in <filename> \" . \n " ) ;
printf ( " \n \n Press <enter> to continue " ) ;
waitForEnterKeyPressed ( ) ;
* pwd = calloc ( 1 , 8 ) ;
* pwdlen = 8 ;
2014-01-08 15:07:13 +00:00
r = sc_get_challenge ( card , ( unsigned char * ) * pwd , 8 ) ;
2013-02-06 15:47:08 +00:00
if ( r < 0 ) {
2013-05-27 14:44:32 +00:00
printf ( " Error generating random key failed with %s " , sc_strerror ( r ) ) ;
OPENSSL_cleanse ( * pwd , * pwdlen ) ;
free ( * pwd ) ;
2013-02-06 15:47:08 +00:00
return r ;
}
2016-01-28 12:52:46 +00:00
* * pwd & = 0x7F ; // Make sure the bit size of the secret is not bigger than 63 bits
2013-02-06 15:47:08 +00:00
/*
* Initialize prime and secret
*/
2016-01-06 14:40:59 +00:00
prime = BN_new ( ) ;
secret = BN_new ( ) ;
2013-02-06 15:47:08 +00:00
/*
* Encode the secret value
*/
2016-01-06 14:40:59 +00:00
BN_bin2bn ( ( unsigned char * ) * pwd , * pwdlen , secret ) ;
2013-02-06 15:47:08 +00:00
/*
* Generate seed and calculate a prime depending on the size of the secret
*/
2015-01-28 06:04:02 +00:00
r = sc_get_challenge ( card , rngseed , SEED_LENGTH ) ;
2013-02-06 15:47:08 +00:00
if ( r < 0 ) {
2013-05-27 14:44:32 +00:00
printf ( " Error generating random seed failed with %s " , sc_strerror ( r ) ) ;
OPENSSL_cleanse ( * pwd , * pwdlen ) ;
free ( * pwd ) ;
2013-02-06 15:47:08 +00:00
return r ;
}
2016-01-06 14:40:59 +00:00
r = generatePrime ( prime , secret , 64 , rngseed , SEED_LENGTH ) ;
2016-01-28 12:52:46 +00:00
if ( r < 0 ) {
printf ( " Error generating valid prime number. Please try again. " ) ;
OPENSSL_cleanse ( * pwd , * pwdlen ) ;
free ( * pwd ) ;
return r ;
}
2013-02-06 15:47:08 +00:00
// Allocate data buffer for the generated shares
shares = malloc ( password_shares_total * sizeof ( secret_share_t ) ) ;
2016-01-06 14:40:59 +00:00
createShares ( secret , password_shares_threshold , password_shares_total , prime , shares ) ;
2013-02-06 15:47:08 +00:00
sp = shares ;
for ( i = 0 ; i < password_shares_total ; i + + ) {
clearScreen ( ) ;
printf ( " Press <enter> to display key share %i of %i \n \n " , i + 1 , password_shares_total ) ;
waitForEnterKeyPressed ( ) ;
clearScreen ( ) ;
printf ( " Share %i of %i \n \n " , i + 1 , password_shares_total ) ;
2016-01-06 14:40:59 +00:00
l = BN_bn2bin ( prime , buf ) ;
2013-02-06 15:47:08 +00:00
sc_bin_to_hex ( buf , l , hex , 64 , ' : ' ) ;
printf ( " \n Prime : %s \n " , hex ) ;
2016-01-06 14:40:59 +00:00
printf ( " Share ID : %s \n " , BN_bn2dec ( ( sp - > x ) ) ) ;
l = BN_bn2bin ( ( sp - > y ) , buf ) ;
2013-02-06 15:47:08 +00:00
sc_bin_to_hex ( buf , l , hex , 64 , ' : ' ) ;
printf ( " Share value : %s \n " , hex ) ;
printf ( " \n \n Please note ALL values above and press <enter> when finished " ) ;
waitForEnterKeyPressed ( ) ;
sp + + ;
}
clearScreen ( ) ;
cleanUpShares ( shares , password_shares_total ) ;
2016-01-06 14:40:59 +00:00
BN_clear_free ( prime ) ;
BN_clear_free ( secret ) ;
2013-02-06 15:47:08 +00:00
return 0 ;
}
2015-03-22 16:38:51 +00:00
static int create_dkek_share ( sc_card_t * card , const char * outf , int iter , const char * password , int password_shares_threshold , int password_shares_total )
2012-10-14 12:35:46 +00:00
{
2016-01-06 14:40:59 +00:00
EVP_CIPHER_CTX * ctx = NULL ;
2012-10-14 12:35:46 +00:00
FILE * out = NULL ;
2013-06-04 07:32:51 +00:00
u8 filebuff [ 64 ] , key [ EVP_MAX_KEY_LENGTH ] , iv [ EVP_MAX_IV_LENGTH ] ;
2012-10-14 12:35:46 +00:00
u8 dkek_share [ 32 ] ;
char * pwd = NULL ;
2013-02-06 15:47:08 +00:00
int r = 0 , outlen , pwdlen = 0 ;
2012-10-14 12:35:46 +00:00
2014-08-25 19:46:52 +00:00
if ( outf = = NULL ) {
fprintf ( stderr , " No file name specified for DKEK share \n " ) ;
return - 1 ;
}
2012-10-14 12:35:46 +00:00
if ( password = = NULL ) {
2015-03-22 16:38:51 +00:00
if ( ( password_shares_threshold = = - 1 ) & & ( password_shares_total = = - 1 ) ) {
2013-02-06 15:47:08 +00:00
ask_for_password ( & pwd , & pwdlen ) ;
} else { // create password using threshold scheme
r = generate_pwd_shares ( card , & pwd , & pwdlen , password_shares_threshold , password_shares_total ) ;
2012-10-14 12:35:46 +00:00
}
2013-02-06 15:47:08 +00:00
2012-10-14 12:35:46 +00:00
} else {
2014-12-07 16:19:57 +00:00
pwd = ( char * ) password ;
2013-02-06 15:47:08 +00:00
pwdlen = strlen ( password ) ;
}
if ( r < 0 ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Creating DKEK share failed \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
memcpy ( filebuff , magic , sizeof ( magic ) - 1 ) ;
r = sc_get_challenge ( card , filebuff + 8 , 8 ) ;
if ( r < 0 ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Error generating random number failed with %s \n " , sc_strerror ( r ) ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
printf ( " Enciphering DKEK share, please wait... \n " ) ;
2013-02-06 15:47:08 +00:00
EVP_BytesToKey ( EVP_aes_256_cbc ( ) , EVP_md5 ( ) , filebuff + 8 , ( u8 * ) pwd , pwdlen , iter , key , iv ) ;
2012-10-14 12:35:46 +00:00
if ( password = = NULL ) {
2013-02-06 15:47:08 +00:00
OPENSSL_cleanse ( pwd , pwdlen ) ;
2012-10-14 12:35:46 +00:00
free ( pwd ) ;
}
r = sc_get_challenge ( card , dkek_share , sizeof ( dkek_share ) ) ;
if ( r < 0 ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Error generating random number failed with %s \n " , sc_strerror ( r ) ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
2016-01-06 14:40:59 +00:00
ctx = EVP_CIPHER_CTX_new ( ) ;
EVP_EncryptInit_ex ( ctx , EVP_aes_256_cbc ( ) , NULL , key , iv ) ;
if ( ! EVP_EncryptUpdate ( ctx , filebuff + 16 , & outlen , dkek_share , sizeof ( dkek_share ) ) ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Error encrypting DKEK share \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
2016-01-06 14:40:59 +00:00
if ( ! EVP_EncryptFinal_ex ( ctx , filebuff + 16 + outlen , & r ) ) {
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Error encrypting DKEK share \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
out = fopen ( outf , " wb " ) ;
if ( out = = NULL ) {
perror ( outf ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( fwrite ( filebuff , 1 , sizeof ( filebuff ) , out ) ! = sizeof ( filebuff ) ) {
perror ( outf ) ;
2015-04-29 21:22:30 +00:00
fclose ( out ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
fclose ( out ) ;
OPENSSL_cleanse ( filebuff , sizeof ( filebuff ) ) ;
2016-01-06 14:40:59 +00:00
EVP_CIPHER_CTX_free ( ctx ) ;
2012-10-14 12:35:46 +00:00
printf ( " DKEK share created and saved to %s \n " , outf ) ;
2014-08-25 19:46:52 +00:00
return 0 ;
2012-10-14 12:35:46 +00:00
}
static size_t determineLength ( const u8 * tlv , size_t buflen )
{
const u8 * ptr = tlv ;
unsigned int cla , tag ;
size_t len ;
if ( sc_asn1_read_tag ( & ptr , buflen , & cla , & tag , & len ) ! = SC_SUCCESS ) {
return 0 ;
}
return len + ( ptr - tlv ) ;
}
2013-04-29 15:24:21 +00:00
/**
* Encapsulate data object as TLV object
*
* @ param tag the one byte tag
* @ param indata the value field
* @ param inlen the length of the value field
* @ param outdata pointer to the allocated memory buffer
* @ param outlen the size of the TLV object
*/
2013-06-04 07:32:51 +00:00
static int wrap_with_tag ( u8 tag , u8 * indata , size_t inlen , u8 * * outdata , size_t * outlen )
2013-04-29 15:24:21 +00:00
{
int nlc = 0 ;
u8 * ptr ;
if ( inlen > 127 ) {
do {
nlc + + ;
2014-01-08 15:07:13 +00:00
} while ( inlen > = ( unsigned ) ( 1 < < ( nlc < < 3 ) ) ) ;
2013-04-29 15:24:21 +00:00
}
* outlen = 2 + nlc + inlen ;
ptr = malloc ( * outlen ) ;
if ( ptr = = NULL ) {
return SC_ERROR_OUT_OF_MEMORY ;
}
* outdata = ptr ;
* ptr + + = tag ;
if ( nlc ) {
* ptr + + = 0x80 | nlc ;
while ( nlc - - ) {
* ptr + + = ( inlen > > ( nlc < < 3 ) ) & 0xFF ;
}
} else {
* ptr + + = inlen & 0x7F ;
}
memcpy ( ptr , indata , inlen ) ;
2013-06-04 07:32:51 +00:00
return SC_SUCCESS ;
2013-04-29 15:24:21 +00:00
}
2014-08-25 19:46:52 +00:00
static int wrap_key ( sc_card_t * card , int keyid , const char * outf , const char * pin )
2012-10-14 12:35:46 +00:00
{
sc_cardctl_sc_hsm_wrapped_key_t wrapped_key ;
struct sc_pin_cmd_data data ;
sc_path_t path ;
FILE * out = NULL ;
u8 fid [ 2 ] ;
u8 ef_prkd [ MAX_PRKD ] ;
u8 ef_cert [ MAX_CERT ] ;
2013-04-29 15:24:21 +00:00
u8 wrapped_key_buff [ MAX_KEY ] ;
2012-10-14 12:35:46 +00:00
u8 keyblob [ MAX_WRAPPED_KEY ] ;
u8 * key ;
u8 * ptr ;
char * lpin = NULL ;
size_t key_len ;
int r , ef_prkd_len , ef_cert_len ;
2014-08-25 19:46:52 +00:00
if ( ( keyid < 1 ) | | ( keyid > 255 ) ) {
fprintf ( stderr , " Invalid key reference (must be 0 < keyid <= 255) \n " ) ;
return - 1 ;
}
if ( outf = = NULL ) {
fprintf ( stderr , " No file name specified for wrapped key \n " ) ;
return - 1 ;
}
2012-10-14 12:35:46 +00:00
if ( pin = = NULL ) {
printf ( " Enter User PIN : " ) ;
util_getpass ( & lpin , NULL , stdin ) ;
printf ( " \n " ) ;
} else {
2014-01-08 15:07:13 +00:00
lpin = ( char * ) pin ;
2012-10-14 12:35:46 +00:00
}
memset ( & data , 0 , sizeof ( data ) ) ;
data . cmd = SC_PIN_CMD_VERIFY ;
data . pin_type = SC_AC_CHV ;
data . pin_reference = ID_USER_PIN ;
2014-01-08 15:07:13 +00:00
data . pin1 . data = ( unsigned char * ) lpin ;
2012-10-14 12:35:46 +00:00
data . pin1 . len = strlen ( lpin ) ;
r = sc_pin_cmd ( card , & data , NULL ) ;
if ( r < 0 ) {
fprintf ( stderr , " PIN verification failed with %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( pin = = NULL ) {
free ( lpin ) ;
}
wrapped_key . key_id = keyid ;
2013-04-29 15:24:21 +00:00
wrapped_key . wrapped_key = wrapped_key_buff ;
wrapped_key . wrapped_key_length = sizeof ( wrapped_key_buff ) ;
2012-10-14 12:35:46 +00:00
r = sc_card_ctl ( card , SC_CARDCTL_SC_HSM_WRAP_KEY , ( void * ) & wrapped_key ) ;
if ( r = = SC_ERROR_INS_NOT_SUPPORTED ) { // Not supported or not initialized for key shares
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Card not initialized for key wrap \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( r < 0 ) {
fprintf ( stderr , " sc_card_ctl(*, SC_CARDCTL_SC_HSM_WRAP_KEY, *) failed with %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
fid [ 0 ] = PRKD_PREFIX ;
2014-08-25 19:46:52 +00:00
fid [ 1 ] = ( unsigned char ) keyid ;
2012-10-14 12:35:46 +00:00
ef_prkd_len = 0 ;
/* Try to select a related EF containing the PKCS#15 description of the key */
sc_path_set ( & path , SC_PATH_TYPE_FILE_ID , fid , sizeof ( fid ) , 0 , 0 ) ;
r = sc_select_file ( card , & path , NULL ) ;
if ( r = = SC_SUCCESS ) {
ef_prkd_len = sc_read_binary ( card , 0 , ef_prkd , sizeof ( ef_prkd ) , 0 ) ;
if ( ef_prkd_len < 0 ) {
fprintf ( stderr , " Error reading PRKD file %s. Skipping. \n " , sc_strerror ( ef_prkd_len ) ) ;
ef_prkd_len = 0 ;
} else {
ef_prkd_len = determineLength ( ef_prkd , ef_prkd_len ) ;
}
}
fid [ 0 ] = EE_CERTIFICATE_PREFIX ;
2014-08-25 19:46:52 +00:00
fid [ 1 ] = ( unsigned char ) keyid ;
2012-10-14 12:35:46 +00:00
ef_cert_len = 0 ;
/* Try to select a related EF containing the certificate for the key */
sc_path_set ( & path , SC_PATH_TYPE_FILE_ID , fid , sizeof ( fid ) , 0 , 0 ) ;
r = sc_select_file ( card , & path , NULL ) ;
if ( r = = SC_SUCCESS ) {
ef_cert_len = sc_read_binary ( card , 0 , ef_cert , sizeof ( ef_cert ) , 0 ) ;
if ( ef_cert_len < 0 ) {
fprintf ( stderr , " Error reading certificate %s. Skipping \n " , sc_strerror ( ef_cert_len ) ) ;
ef_cert_len = 0 ;
} else {
ef_cert_len = determineLength ( ef_cert , ef_cert_len ) ;
}
}
ptr = keyblob ;
// Encode key in octet string object
2013-04-29 15:24:21 +00:00
key_len = 0 ;
wrap_with_tag ( 0x04 , wrapped_key . wrapped_key , wrapped_key . wrapped_key_length ,
& key , & key_len ) ;
2012-10-14 12:35:46 +00:00
memcpy ( ptr , key , key_len ) ;
ptr + = key_len ;
2015-01-24 18:22:39 +00:00
2012-10-14 12:35:46 +00:00
free ( key ) ;
2015-01-24 18:22:39 +00:00
key = NULL ;
key_len = 0 ;
2012-10-14 12:35:46 +00:00
// Add private key description
if ( ef_prkd_len > 0 ) {
memcpy ( ptr , ef_prkd , ef_prkd_len ) ;
ptr + = ef_prkd_len ;
}
// Add certificate
if ( ef_cert_len > 0 ) {
memcpy ( ptr , ef_cert , ef_cert_len ) ;
ptr + = ef_cert_len ;
}
2013-04-29 15:24:21 +00:00
// Encode key, key decription and certificate object in sequence
wrap_with_tag ( 0x30 , keyblob , ptr - keyblob , & key , & key_len ) ;
2012-10-14 12:35:46 +00:00
out = fopen ( outf , " wb " ) ;
if ( out = = NULL ) {
perror ( outf ) ;
free ( key ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( fwrite ( key , 1 , key_len , out ) ! = key_len ) {
perror ( outf ) ;
free ( key ) ;
2015-04-29 21:22:30 +00:00
fclose ( out ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
free ( key ) ;
fclose ( out ) ;
2014-08-25 19:46:52 +00:00
return 0 ;
2012-10-14 12:35:46 +00:00
}
static int update_ef ( sc_card_t * card , u8 prefix , u8 id , int erase , const u8 * buf , size_t buflen )
{
sc_file_t * file = NULL ;
sc_path_t path ;
u8 fid [ 2 ] ;
int r ;
fid [ 0 ] = prefix ;
fid [ 1 ] = id ;
sc_path_set ( & path , SC_PATH_TYPE_FILE_ID , fid , 2 , 0 , - 1 ) ;
r = sc_select_file ( card , & path , NULL ) ;
if ( ( r = = SC_SUCCESS ) & & erase ) {
r = sc_delete_file ( card , & path ) ;
r = SC_ERROR_FILE_NOT_FOUND ;
}
if ( r = = SC_ERROR_FILE_NOT_FOUND ) {
file = sc_file_new ( ) ;
file - > id = ( path . value [ 0 ] < < 8 ) | path . value [ 1 ] ;
file - > type = SC_FILE_TYPE_WORKING_EF ;
file - > ef_structure = SC_FILE_EF_TRANSPARENT ;
file - > size = ( size_t ) 0 ;
file - > status = SC_FILE_STATUS_ACTIVATED ;
r = sc_create_file ( card , file ) ;
sc_file_free ( file ) ;
if ( r < 0 ) {
return r ;
}
}
r = sc_update_binary ( card , 0 , buf , buflen , 0 ) ;
return r ;
}
2014-08-25 19:46:52 +00:00
static int unwrap_key ( sc_card_t * card , int keyid , const char * inf , const char * pin , int force )
2012-10-14 12:35:46 +00:00
{
sc_cardctl_sc_hsm_wrapped_key_t wrapped_key ;
struct sc_pin_cmd_data data ;
u8 keyblob [ MAX_WRAPPED_KEY ] ;
const u8 * ptr , * prkd , * cert ;
FILE * in = NULL ;
sc_path_t path ;
u8 fid [ 2 ] ;
char * lpin = NULL ;
unsigned int cla , tag ;
int r , keybloblen ;
size_t len , olen , prkd_len , cert_len ;
2014-08-25 19:46:52 +00:00
if ( ( keyid < 1 ) | | ( keyid > 255 ) ) {
fprintf ( stderr , " Invalid key reference (must be 0 < keyid <= 255) \n " ) ;
return - 1 ;
}
if ( inf = = NULL ) {
fprintf ( stderr , " No file name specified for wrapped key \n " ) ;
return - 1 ;
}
2012-10-14 12:35:46 +00:00
in = fopen ( inf , " rb " ) ;
if ( in = = NULL ) {
perror ( inf ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( ( keybloblen = fread ( keyblob , 1 , sizeof ( keyblob ) , in ) ) < 0 ) {
perror ( inf ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
fclose ( in ) ;
ptr = keyblob ;
if ( ( sc_asn1_read_tag ( & ptr , keybloblen , & cla , & tag , & len ) ! = SC_SUCCESS ) | |
( ( cla & SC_ASN1_TAG_CONSTRUCTED ) ! = SC_ASN1_TAG_CONSTRUCTED ) | |
( ( tag ! = SC_ASN1_TAG_SEQUENCE ) ) ) {
fprintf ( stderr , " Invalid wrapped key format (Outer sequence). \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( ( sc_asn1_read_tag ( & ptr , len , & cla , & tag , & olen ) ! = SC_SUCCESS ) | |
( cla & SC_ASN1_TAG_CONSTRUCTED ) | |
( ( tag ! = SC_ASN1_TAG_OCTET_STRING ) ) ) {
fprintf ( stderr , " Invalid wrapped key format (Key binary). \n " ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
wrapped_key . wrapped_key = ( u8 * ) ptr ;
wrapped_key . wrapped_key_length = olen ;
ptr + = olen ;
prkd = ptr ;
prkd_len = determineLength ( ptr , keybloblen - ( ptr - keyblob ) ) ;
ptr + = prkd_len ;
cert = ptr ;
cert_len = determineLength ( ptr , keybloblen - ( ptr - keyblob ) ) ;
printf ( " Wrapped key contains: \n " ) ;
printf ( " Key blob \n " ) ;
if ( prkd_len > 0 ) {
printf ( " Private Key Description (PRKD) \n " ) ;
}
if ( cert_len > 0 ) {
printf ( " Certificate \n " ) ;
}
if ( ( prkd_len > 0 ) & & ! force ) {
fid [ 0 ] = PRKD_PREFIX ;
2014-08-25 19:46:52 +00:00
fid [ 1 ] = ( unsigned char ) keyid ;
2012-10-14 12:35:46 +00:00
/* Try to select a related EF containing the PKCS#15 description of the key */
sc_path_set ( & path , SC_PATH_TYPE_FILE_ID , fid , sizeof ( fid ) , 0 , 0 ) ;
r = sc_select_file ( card , & path , NULL ) ;
if ( r = = SC_SUCCESS ) {
fprintf ( stderr , " Found existing private key description in EF with fid %02x%02x. Please remove key first, select unused key reference or use --force. \n " , fid [ 0 ] , fid [ 1 ] ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
}
if ( ( cert_len > 0 ) & & ! force ) {
fid [ 0 ] = EE_CERTIFICATE_PREFIX ;
2014-08-25 19:46:52 +00:00
fid [ 1 ] = ( unsigned char ) keyid ;
2012-10-14 12:35:46 +00:00
/* Try to select a related EF containing the certificate */
sc_path_set ( & path , SC_PATH_TYPE_FILE_ID , fid , sizeof ( fid ) , 0 , 0 ) ;
r = sc_select_file ( card , & path , NULL ) ;
if ( r = = SC_SUCCESS ) {
fprintf ( stderr , " Found existing certificate in EF with fid %02x%02x. Please remove certificate first, select unused key reference or use --force. \n " , fid [ 0 ] , fid [ 1 ] ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
}
if ( pin = = NULL ) {
printf ( " Enter User PIN : " ) ;
util_getpass ( & lpin , NULL , stdin ) ;
printf ( " \n " ) ;
} else {
2014-01-08 15:07:13 +00:00
lpin = ( char * ) pin ;
2012-10-14 12:35:46 +00:00
}
memset ( & data , 0 , sizeof ( data ) ) ;
data . cmd = SC_PIN_CMD_VERIFY ;
data . pin_type = SC_AC_CHV ;
data . pin_reference = ID_USER_PIN ;
2014-01-08 15:07:13 +00:00
data . pin1 . data = ( u8 * ) lpin ;
2012-10-14 12:35:46 +00:00
data . pin1 . len = strlen ( lpin ) ;
r = sc_pin_cmd ( card , & data , NULL ) ;
if ( r < 0 ) {
fprintf ( stderr , " PIN verification failed with %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( pin = = NULL ) {
free ( lpin ) ;
}
if ( force ) {
fid [ 0 ] = KEY_PREFIX ;
fid [ 1 ] = keyid ;
sc_path_set ( & path , SC_PATH_TYPE_FILE_ID , fid , 2 , 0 , - 1 ) ;
sc_delete_file ( card , & path ) ;
}
wrapped_key . key_id = keyid ;
r = sc_card_ctl ( card , SC_CARDCTL_SC_HSM_UNWRAP_KEY , ( void * ) & wrapped_key ) ;
if ( r = = SC_ERROR_INS_NOT_SUPPORTED ) { // Not supported or not initialized for key shares
2014-08-25 19:46:52 +00:00
fprintf ( stderr , " Card not initialized for key wrap \n " ) ;
return - 1 ;
}
if ( r = = SC_ERROR_INCORRECT_PARAMETERS ) { // Not supported or not initialized for key shares
fprintf ( stderr , " Wrapped key does not match DKEK \n " ) ;
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( r < 0 ) {
fprintf ( stderr , " sc_card_ctl(*, SC_CARDCTL_SC_HSM_UNWRAP_KEY, *) failed with %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
if ( prkd_len > 0 ) {
r = update_ef ( card , PRKD_PREFIX , keyid , force , prkd , prkd_len ) ;
if ( r < 0 ) {
fprintf ( stderr , " Updating private key description failed with %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
}
if ( cert_len > 0 ) {
r = update_ef ( card , EE_CERTIFICATE_PREFIX , keyid , force , cert , cert_len ) ;
if ( r < 0 ) {
fprintf ( stderr , " Updating certificate failed with %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
return - 1 ;
2012-10-14 12:35:46 +00:00
}
}
printf ( " Key successfully imported \n " ) ;
2014-08-25 19:46:52 +00:00
return 0 ;
2012-10-14 12:35:46 +00:00
}
int main ( int argc , char * const argv [ ] )
{
int err = 0 , r , c , long_optind = 0 ;
int action_count = 0 ;
int do_initialize = 0 ;
int do_import_dkek_share = 0 ;
2016-07-10 12:08:48 +00:00
int do_print_dkek_share = 0 ;
2012-10-14 12:35:46 +00:00
int do_create_dkek_share = 0 ;
int do_wrap_key = 0 ;
int do_unwrap_key = 0 ;
sc_path_t path ;
sc_file_t * file = NULL ;
const char * opt_so_pin = NULL ;
const char * opt_pin = NULL ;
const char * opt_filename = NULL ;
2014-12-07 16:19:57 +00:00
const char * opt_password = NULL ;
2012-10-14 12:35:46 +00:00
int opt_retry_counter = 3 ;
int opt_dkek_shares = - 1 ;
int opt_key_reference = - 1 ;
2013-02-06 15:47:08 +00:00
int opt_password_shares_threshold = - 1 ;
int opt_password_shares_total = - 1 ;
2012-10-14 12:35:46 +00:00
int opt_force = 0 ;
int opt_iter = 10000000 ;
sc_context_param_t ctx_param ;
setbuf ( stderr , NULL ) ;
setbuf ( stdout , NULL ) ;
while ( 1 ) {
2016-07-10 12:08:48 +00:00
c = getopt_long ( argc , argv , " XC:I:P:W:U:s:i:fr:wv " , options , & long_optind ) ;
2012-10-14 12:35:46 +00:00
if ( c = = - 1 )
break ;
if ( c = = ' ? ' )
util_print_usage_and_die ( app_name , options , option_help , NULL ) ;
switch ( c ) {
case ' X ' :
do_initialize = 1 ;
action_count + + ;
break ;
case ' C ' :
do_create_dkek_share = 1 ;
opt_filename = optarg ;
action_count + + ;
break ;
case ' I ' :
do_import_dkek_share = 1 ;
opt_filename = optarg ;
action_count + + ;
break ;
2016-07-10 12:08:48 +00:00
case ' P ' :
do_print_dkek_share = 1 ;
opt_filename = optarg ;
action_count + + ;
break ;
2012-10-14 12:35:46 +00:00
case ' W ' :
do_wrap_key = 1 ;
opt_filename = optarg ;
action_count + + ;
break ;
case ' U ' :
do_unwrap_key = 1 ;
opt_filename = optarg ;
action_count + + ;
break ;
case OPT_PASSWORD :
2014-11-04 20:44:02 +00:00
util_get_pin ( optarg , & opt_password ) ;
2012-10-14 12:35:46 +00:00
break ;
case OPT_SO_PIN :
2014-11-04 20:44:02 +00:00
util_get_pin ( optarg , & opt_so_pin ) ;
2012-10-14 12:35:46 +00:00
break ;
case OPT_PIN :
2014-11-04 20:44:02 +00:00
util_get_pin ( optarg , & opt_pin ) ;
2012-10-14 12:35:46 +00:00
break ;
case OPT_RETRY :
opt_retry_counter = atol ( optarg ) ;
break ;
2013-02-06 15:47:08 +00:00
case OPT_PASSWORD_SHARES_THRESHOLD :
opt_password_shares_threshold = atol ( optarg ) ;
break ;
case OPT_PASSWORD_SHARES_TOTAL :
opt_password_shares_total = atol ( optarg ) ;
break ;
2012-10-14 12:35:46 +00:00
case ' s ' :
opt_dkek_shares = atol ( optarg ) ;
break ;
case ' f ' :
opt_force = 1 ;
break ;
case ' i ' :
opt_key_reference = atol ( optarg ) ;
break ;
case ' r ' :
opt_reader = optarg ;
break ;
2014-01-08 15:07:13 +00:00
case ' l ' :
opt_label = optarg ;
break ;
2012-10-14 12:35:46 +00:00
case ' v ' :
verbose + + ;
break ;
case ' w ' :
opt_wait = 1 ;
break ;
}
}
2016-10-04 01:10:21 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x10100000L && !(defined LIBRESSL_VERSION_NUMBER)
2016-01-06 14:40:59 +00:00
OPENSSL_init_crypto ( OPENSSL_INIT_LOAD_CRYPTO_STRINGS
| OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS ,
NULL ) ;
# else
2012-10-14 12:35:46 +00:00
CRYPTO_malloc_init ( ) ;
ERR_load_crypto_strings ( ) ;
OpenSSL_add_all_algorithms ( ) ;
2016-01-06 14:40:59 +00:00
# endif
2012-10-14 12:35:46 +00:00
memset ( & ctx_param , 0 , sizeof ( sc_context_param_t ) ) ;
ctx_param . app_name = app_name ;
r = sc_context_create ( & ctx , & ctx_param ) ;
if ( r ! = SC_SUCCESS ) {
fprintf ( stderr , " Failed to establish context: %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
exit ( 1 ) ;
2012-10-14 12:35:46 +00:00
}
/* Only change if not in opensc.conf */
if ( verbose > 1 & & ctx - > debug = = 0 ) {
ctx - > debug = verbose ;
sc_ctx_log_to_file ( ctx , " stderr " ) ;
}
2016-09-19 15:49:34 +00:00
r = util_connect_card_ex ( ctx , & card , opt_reader , opt_wait , 0 , verbose ) ;
2014-08-25 19:46:52 +00:00
if ( r ! = SC_SUCCESS ) {
if ( r < 0 ) {
2014-06-06 19:10:28 +00:00
fprintf ( stderr , " Failed to connect to card: %s \n " , sc_strerror ( err ) ) ;
}
2012-10-14 12:35:46 +00:00
goto end ;
2013-01-08 07:44:56 +00:00
}
2012-10-14 12:35:46 +00:00
sc_path_set ( & path , SC_PATH_TYPE_DF_NAME , sc_hsm_aid . value , sc_hsm_aid . len , 0 , 0 ) ;
r = sc_select_file ( card , & path , & file ) ;
2013-01-08 07:44:56 +00:00
if ( r ! = SC_SUCCESS ) {
fprintf ( stderr , " Failed to select application: %s \n " , sc_strerror ( r ) ) ;
2014-08-25 19:46:52 +00:00
goto fail ;
2013-01-08 07:44:56 +00:00
}
2014-08-25 19:46:52 +00:00
if ( do_initialize & & initialize ( card , opt_so_pin , opt_pin , opt_retry_counter , opt_dkek_shares , opt_label ) )
goto fail ;
2012-10-14 12:35:46 +00:00
2015-03-22 16:38:51 +00:00
if ( do_create_dkek_share & & create_dkek_share ( card , opt_filename , opt_iter , opt_password , opt_password_shares_threshold , opt_password_shares_total ) )
goto fail ;
2012-10-14 12:35:46 +00:00
2014-08-25 19:46:52 +00:00
if ( do_import_dkek_share & & import_dkek_share ( card , opt_filename , opt_iter , opt_password , opt_password_shares_total ) )
goto fail ;
2012-10-14 12:35:46 +00:00
2016-07-10 12:08:48 +00:00
if ( do_print_dkek_share & & print_dkek_share ( card , opt_filename , opt_iter , opt_password , opt_password_shares_total ) )
goto fail ;
2014-08-25 19:46:52 +00:00
if ( do_wrap_key & & wrap_key ( card , opt_key_reference , opt_filename , opt_pin ) )
goto fail ;
2012-10-14 12:35:46 +00:00
2014-08-25 19:46:52 +00:00
if ( do_unwrap_key & & unwrap_key ( card , opt_key_reference , opt_filename , opt_pin , opt_force ) )
goto fail ;
2012-10-14 12:35:46 +00:00
if ( action_count = = 0 ) {
print_info ( card , file ) ;
}
2014-08-25 19:46:52 +00:00
err = 0 ;
goto end ;
fail :
err = 1 ;
2012-10-14 12:35:46 +00:00
end :
if ( card ) {
sc_disconnect_card ( card ) ;
}
if ( ctx )
sc_release_context ( ctx ) ;
ERR_print_errors_fp ( stderr ) ;
return err ;
}