diff options
author | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-24 02:27:47 -0500 |
---|---|---|
committer | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-26 11:43:54 -0500 |
commit | 621d9e5c413e561293d7484b93882d985b3fe15f (patch) | |
tree | 638f3d75761c121d9a8fb50b52a12a6686c5ac5c /base/native-tools/src/tkstool/key.c | |
parent | 40d3643b8d91886bf210aa27f711731c81a11e49 (diff) | |
download | pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.gz pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.xz pki-621d9e5c413e561293d7484b93882d985b3fe15f.zip |
Removed unnecessary pki folder.
Previously the source code was located inside a pki folder.
This folder was created during svn migration and is no longer
needed. This folder has now been removed and the contents have
been moved up one level.
Ticket #131
Diffstat (limited to 'base/native-tools/src/tkstool/key.c')
-rw-r--r-- | base/native-tools/src/tkstool/key.c | 1350 |
1 files changed, 1350 insertions, 0 deletions
diff --git a/base/native-tools/src/tkstool/key.c b/base/native-tools/src/tkstool/key.c new file mode 100644 index 000000000..4fd37963b --- /dev/null +++ b/base/native-tools/src/tkstool/key.c @@ -0,0 +1,1350 @@ +/* --- BEGIN COPYRIGHT BLOCK --- + * 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; version 2 of the License. + * + * 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; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + +#include "tkstool.h" + +/*******************************/ +/** local private functions **/ +/*******************************/ + +/* returns 0 for success, -1 for failure (EOF encountered) */ +static int +InputHexSessionKey( char *sessionKeyShareName, + SECItem *hexSessionKeyShare ) +{ + int fd; + int i; + int count; + int c; + int rv = 0; +#ifdef XP_UNIX + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; +#endif + + PR_fprintf( PR_STDOUT, + "Type in the %s session key share (or ^C to break):\n\n", + sessionKeyShareName ); + PR_fprintf( PR_STDOUT, + "[ ] [ ] [ ] [ ] " + "[ ] [ ] [ ] [ ]\r" ); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno( stdin ); + +#if defined( XP_UNIX ) && !defined( VMS ) + tcgetattr( fd, &tio ); + orig_lflag = tio.c_lflag; + orig_cc_min = tio.c_cc[VMIN]; + orig_cc_time = tio.c_cc[VTIME]; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~ICANON; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + /* Get user input from keyboard strokes */ + count = 0; + while( count < HEX_SESSION_KEY_BUF_LENGTH ) { +#ifdef VMS + c = GENERIC_GETCHAR_NOECHO(); +#elif XP_UNIX + c = getc( stdin ); +#else + c = getch(); +#endif + /* break on EOF */ + if( c == EOF ) { + rv = -1; + break; + } + + /* break on ^C */ + if( c == CTRL_C ) { + rv = -1; + break; + } + + /* save acceptable hex characters; silently throw anything else away */ + switch( c ) { + case '\010': /* backspace */ + /* acceptable character; save it as a NULL value */ + hexSessionKeyShare->data[count] = '\0'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* acceptable character; save it as typed */ + hexSessionKeyShare->data[count] = c; + break; + case 'A': + case 'a': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'A'; + break; + case 'B': + case 'b': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'B'; + break; + case 'C': + case 'c': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'C'; + break; + case 'D': + case 'd': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'D'; + break; + case 'E': + case 'e': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'E'; + break; + case 'F': + case 'f': + /* acceptable character; save uppercase version */ + hexSessionKeyShare->data[count] = 'F'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + + /* adjust the character count appropriately */ + if( c != '\010' ) { + /* only increment the character count if everything is OK */ + count++; + } else { + /* only decrement the character count if a backspace was entered */ + if( count > 0 ) { + count--; + } + } + + /* redisplay the left bracket */ + PR_fprintf( PR_STDOUT, + "\r[" ); + + /* display the characters input so far */ + for( i = 0 ; i < count ; i++ ) { + PR_fprintf( PR_STDOUT, + "%c", + hexSessionKeyShare->data[i] ); + if( ( i > 0 ) && + ( ( ( i + 1 ) % 4 ) == 0 ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + } + } + + /* display a "cursor" pointing to the next character */ + PR_fprintf( PR_STDOUT, + "/" ); + + /* display spaces to pad the remainder */ + for( i = ( count + 1 ); + i < HEX_SESSION_KEY_BUF_LENGTH; + i++ ) { + if( ( i % 4 ) != 0 ) { + PR_fprintf( PR_STDOUT, " " ); + } else { + if( ( i > 0 ) && + ( ( i + 1 ) < HEX_SESSION_KEY_BUF_LENGTH ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + PR_fprintf( PR_STDOUT, " " ); + } + } + } + + /* redisplay the right bracket */ + PR_fprintf( PR_STDOUT, + "]" ); + } + + /* Null terminate the entered character sequence */ + hexSessionKeyShare->data[count] = '\0'; + + + /**************************************/ + /* Print the final character sequence */ + /**************************************/ + + /* Clear input line by outputting 78 blank */ + /* spaces from the beginning of this line */ + PR_fprintf( PR_STDOUT, + "\r" + " " + " " ); + + /* Print appropriate key share name */ + PR_fprintf( PR_STDOUT, + "\r %s session key share: ", + sessionKeyShareName ); + + /* Print first DES_LENGTH bytes */ + count = ( ( hexSessionKeyShare->len - 1 ) / 2 ); + for( i = 0; i < count; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare->data[i], + hexSessionKeyShare->data[i + 1], + hexSessionKeyShare->data[i + 2], + hexSessionKeyShare->data[i + 3] ); + } + + /* Print appropriate key share padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( sessionKeyShareName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print second DES_LENGTH bytes */ + for( i = count; i < hexSessionKeyShare->len; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare->data[i], + hexSessionKeyShare->data[i + 1], + hexSessionKeyShare->data[i + 2], + hexSessionKeyShare->data[i + 3] ); + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + +#if defined( XP_UNIX ) && !defined( VMS ) + /* set back termio the way it was */ + tio.c_lflag = orig_lflag; + tio.c_cc[VMIN] = orig_cc_min; + tio.c_cc[VTIME] = orig_cc_time; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + return rv; +} + + +/* returns 0 for success, -1 for failure (EOF encountered) */ +static int +InputHexKCV( char *sessionKeyShareName, + PRUint8 *hexKCV ) +{ + int fd; + int i; + int count; + int c; + int rv = 0; +#ifdef XP_UNIX + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; +#endif + + PR_fprintf( PR_STDOUT, + "Type in the corresponding KCV for the " + "%s session key share (or ^C to break):\n\n", + sessionKeyShareName ); + PR_fprintf( PR_STDOUT, + "[ ] [ ]\r" ); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno( stdin ); + +#if defined( XP_UNIX ) && !defined( VMS ) + tcgetattr( fd, &tio ); + orig_lflag = tio.c_lflag; + orig_cc_min = tio.c_cc[VMIN]; + orig_cc_time = tio.c_cc[VTIME]; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~ICANON; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + /* Get user input from keyboard strokes */ + count = 0; + while( count < HEX_SESSION_KEY_KCV_BUF_LENGTH ) { +#ifdef VMS + c = GENERIC_GETCHAR_NOECHO(); +#elif XP_UNIX + c = getc( stdin ); +#else + c = getch(); +#endif + /* break on EOF */ + if( c == EOF ) { + rv = -1; + break; + } + + /* break on ^C */ + if( c == CTRL_C ) { + rv = -1; + break; + } + + /* save acceptable hex characters; silently throw anything else away */ + switch( c ) { + case '\010': /* backspace */ + /* acceptable character; save it as a NULL value */ + hexKCV[count] = '\0'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* acceptable character; save it as typed */ + hexKCV[count] = c; + break; + case 'A': + case 'a': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'A'; + break; + case 'B': + case 'b': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'B'; + break; + case 'C': + case 'c': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'C'; + break; + case 'D': + case 'd': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'D'; + break; + case 'E': + case 'e': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'E'; + break; + case 'F': + case 'f': + /* acceptable character; save uppercase version */ + hexKCV[count] = 'F'; + break; + default: + /* unacceptable character; don't save it */ + continue; + } + + /* adjust the character count appropriately */ + if( c != '\010' ) { + /* only increment the character count if everything is OK */ + count++; + } else { + /* only decrement the character count if a backspace was entered */ + if( count > 0 ) { + count--; + } + } + + /* redisplay the left bracket */ + PR_fprintf( PR_STDOUT, + "\r[" ); + + /* display the characters input so far */ + for( i = 0 ; i < count ; i++ ) { + PR_fprintf( PR_STDOUT, + "%c", + hexKCV[i] ); + if( ( i > 0 ) && + ( ( ( i + 1 ) % 4 ) == 0 ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + } + } + + /* display a "cursor" pointing to the next character */ + PR_fprintf( PR_STDOUT, + "/" ); + + /* display spaces to pad the remainder */ + for( i = ( count + 1 ); + i < HEX_SESSION_KEY_KCV_BUF_LENGTH; + i++ ) { + if( ( i % 4 ) != 0 ) { + PR_fprintf( PR_STDOUT, " " ); + } else { + if( ( i > 0 ) && + ( ( i + 1 ) < HEX_SESSION_KEY_KCV_BUF_LENGTH ) ) { + PR_fprintf( PR_STDOUT, "] [" ); + PR_fprintf( PR_STDOUT, " " ); + } + } + } + + /* redisplay the right bracket */ + PR_fprintf( PR_STDOUT, + "]" ); + } + + /* Null terminate the entered character sequence */ + hexKCV[count] = '\0'; + + + /**************************************/ + /* Print the final character sequence */ + /**************************************/ + + /* Clear input line by outputting 78 blank */ + /* spaces from the beginning of this line */ + PR_fprintf( PR_STDOUT, + "\r" + " " + " " ); + + /* display this session key share's entered KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + "\r %s session key share KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + sessionKeyShareName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + +#if defined( XP_UNIX ) && !defined( VMS ) + /* set back termio the way it was */ + tio.c_lflag = orig_lflag; + tio.c_cc[VMIN] = orig_cc_min; + tio.c_cc[VTIME] = orig_cc_time; + tcsetattr( fd, TCSAFLUSH, &tio ); +#endif + + return rv; +} + + +/************************************/ +/** public session key functions **/ +/************************************/ + +SECStatus +TKS_ComputeAndDisplayKCV( PRUint8 *newKey, + PRIntn newKeyLen, + PRUint8 *KCV, + PRIntn KCVLen, + PK11SymKey *symKey, + char *keyName, + char *keyType, + PRBool displayKCV, + PRUint8 *expectedHexKCV ) +{ + int len; + unsigned char value[8]; + PK11SymKey *key = NULL; + PK11SlotInfo *slot = NULL; + PK11Context *context = NULL; + PRIntn hexKCVLen = ( 2 * KCVLen ) + 1; + PRUint8 *hexKCV = NULL; + PRUint8 *keyData = NULL; + SECItem keyItem = { siBuffer, + NULL, + 0 }; + SECItem noParams = { siBuffer, + NULL, + 0 }; + SECStatus s = SECFailure; + SECStatus status = SECFailure; + + /* for all keys except keys that are resident/wrapped/unwrapped . . . */ + if( ( PL_strcmp( keyType, RESIDENT_KEY ) != 0 ) && + ( PL_strcmp( keyType, UNWRAPPED_KEY ) != 0 ) && + ( PL_strcmp( keyType, WRAPPED_KEY ) != 0 ) ) { + slot = PK11_GetInternalKeySlot(); + + if( newKeyLen == ( 2 * DES_LENGTH ) ) { +#if defined(PAD_DES2_KEY_LENGTH) + /* double-DES key */ + keyData = ( PRUint8 * ) PORT_ZAlloc( newKeyLen + DES_LENGTH ); + + keyItem.type = ( SECItemType ) siBuffer; + keyItem.data = ( unsigned char * ) keyData; + keyItem.len = ( unsigned int ) ( newKeyLen + DES_LENGTH ); + + /* convert 16-byte double-DES key to 24-byte triple-DES key */ + PORT_Memcpy( keyData, newKey, newKeyLen ); + PORT_Memcpy( ( keyData + ( 2 * DES_LENGTH ) ), + newKey, DES_LENGTH ); +#else + /* double-DES key */ + keyData = ( PRUint8 * ) PORT_ZAlloc( newKeyLen ); + + keyItem.type = ( SECItemType ) siBuffer; + keyItem.data = ( unsigned char * ) keyData; + keyItem.len = ( unsigned int ) newKeyLen; + + PORT_Memcpy( keyData, newKey, newKeyLen ); +#endif + } else if( newKeyLen == ( 3 * DES_LENGTH ) ) { + /* triple-DES key */ + keyData = ( PRUint8 * ) PORT_ZAlloc( newKeyLen ); + + keyItem.type = ( SECItemType ) siBuffer; + keyItem.data = ( unsigned char * ) keyData; + keyItem.len = ( unsigned int ) newKeyLen; + + PORT_Memcpy( keyData, newKey, newKeyLen ); + } else { + /* invalid key size */ + PR_fprintf( PR_STDOUT, + "Attempting to perform KCV on invalid key length!\n\n\n" ); + status = SECFailure; + goto done; + } + + key = PK11_ImportSymKeyWithFlags( + /* slot */ slot, + /* mechanism type */ CKM_DES3_ECB, + /* origin */ PK11_OriginGenerated, + /* operation */ CKA_ENCRYPT, + /* key */ &keyItem, + /* flags */ CKF_ENCRYPT, + /* isPerm */ PR_FALSE, + /* wincx */ 0 ); + + if( ! key ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to import %s key!\n\n\n", + keyType ); + status = SECFailure; + goto done; + } + } else { + /* since resident/wrapped/unwrapped keys are already present . . . */ + key = symKey; + } + + PORT_Memset( value, 0, sizeof( value ) ); + + context = PK11_CreateContextBySymKey( + /* mechanism type */ CKM_DES3_ECB, + /* operation */ CKA_ENCRYPT, + /* symmetric key */ key, + /* param */ &noParams ); + + if( ! context ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to create crypto context!\n\n\n" ); + status = SECFailure; + goto done; + } + + s = PK11_CipherOp( + /* context */ context, + /* output */ &value[0], + /* output length */ &len, + /* maximum output length */ DES_LENGTH, + /* input */ &value[0], + /* input length */ DES_LENGTH ); + if( s != SECSuccess) { + PR_fprintf( PR_STDERR, + "ERROR: CipherOp Failed!\n\n\n" ); + status = SECFailure; + goto done; + } + + KCV = ( PRUint8 * ) PORT_ZAlloc( KCVLen ); + + PORT_Memcpy( KCV, value, KCVLen ); + + /* Create a clean new display buffer for this */ + /* symmetric key/session key share KCV */ + hexKCV = ( PRUint8 * ) PORT_ZAlloc( hexKCVLen ); + if( hexKCV == NULL ) { + status = SECFailure; + goto done; + } + + /* Display the symmetric key/session key share KCV (in hex digits) */ + TKS_StringToHex( ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + ( PRUint8 * ) hexKCV, + ( PRIntn ) hexKCVLen ); + + if( displayKCV != PR_FALSE ) { + /********************************************/ + /* The following code is ONLY relevant to: */ + /* */ + /* (1) resident, */ + /* (2) session, */ + /* (3) symmetric, and */ + /* (4) transport keys. */ + /* */ + /********************************************/ + + if( PL_strcmp( keyType, RESIDENT_KEY ) == 0 ) { + /* display this resident key's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s key KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } else if( PL_strcmp( keyType, SESSION_KEY ) == 0 ) { + /* display this session key share's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s session key share KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } else if( PL_strcmp( keyType, SYMMETRIC_KEY ) == 0 ) { + /* display this symmetric key's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s key KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } else if( PL_strcmp( keyType, TRANSPORT_KEY ) == 0 ) { + /* display this transport key's computed KCV value (in hex) */ + PR_fprintf( PR_STDOUT, + " %s key KCV: " + "%c%c%c%c %c%c%c%c\n\n\n", + keyName, + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + } + } else { + /**********************************************/ + /* The following code is ONLY relevant to: */ + /* */ + /* (1) session keys, */ + /* (2) keys that have been unwrapped, and */ + /* (3) keys that will be wrapped. */ + /* */ + /**********************************************/ + + if( PL_strcmp( keyType, SESSION_KEY ) == 0 ) { + /* compare this session key share's computed KCV value (in hex) */ + /* with the expected KCV value (in hex) */ + if( PL_strcmp( ( const char * ) hexKCV, + ( const char * ) expectedHexKCV ) == 0 ) { + PR_fprintf( PR_STDOUT, + "Congratulations, the %s session key share KCV " + "value entered CORRESPONDS\nto the %s session key " + "share value entered!\n", + keyName, + keyName ); + + /* Wait for the user to type "proceed" to continue */ + TKS_TypeProceedToContinue(); + } else { + PR_fprintf( PR_STDOUT, + "Unfortunately, a MISMATCH exists between the %s " + "session key share entered\nand the %s session key " + "share KCV entered. Please try again . . .\n", + keyName, + keyName ); + + /* Wait for the user to type "proceed" to continue */ + TKS_TypeProceedToContinue(); + + status = SECFailure; + goto done; + } + } else if( PL_strcmp( keyType, UNWRAPPED_KEY ) == 0 ) { + PR_fprintf( PR_STDOUT, + " master key KCV: " + "%c%c%c%c %c%c%c%c\n (computed KCV of the " + "master key residing inside the wrapped data)\n\n\n", + hexKCV[0], + hexKCV[1], + hexKCV[2], + hexKCV[3], + hexKCV[4], + hexKCV[5], + hexKCV[6], + hexKCV[7] ); + + PR_fprintf( PR_STDOUT, + " master key KCV: " + "%c%c%c%c %c%c%c%c\n (pre-computed KCV of the " + "master key residing inside the wrapped data)\n\n\n", + expectedHexKCV[0], + expectedHexKCV[1], + expectedHexKCV[2], + expectedHexKCV[3], + expectedHexKCV[4], + expectedHexKCV[5], + expectedHexKCV[6], + expectedHexKCV[7] ); + + /* compare this wrapped key's computed KCV value (in hex) */ + /* with the expected KCV value (in hex) -- silently */ + if( PL_strcmp( ( const char * ) hexKCV, + ( const char * ) expectedHexKCV ) != 0 ) { + PR_fprintf( PR_STDOUT, + "Unfortunately, a MISMATCH exists between the " + "wrapped data read in\nfrom the input file " + "and the master key KCV that was recomputed.\n\n", + keyName, + keyName ); + status = SECFailure; + goto done; + } + } else if( PL_strcmp( keyType, WRAPPED_KEY ) == 0 ) { + /* store this master key's computed KCV value (in hex) */ + expectedHexKCV[0] = hexKCV[0]; + expectedHexKCV[1] = hexKCV[1]; + expectedHexKCV[2] = hexKCV[2]; + expectedHexKCV[3] = hexKCV[3]; + expectedHexKCV[4] = hexKCV[4]; + expectedHexKCV[5] = hexKCV[5]; + expectedHexKCV[6] = hexKCV[6]; + expectedHexKCV[7] = hexKCV[7]; + } + } + + status = SECSuccess; + +done: + if( keyItem.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + keyItem.data, + keyItem.len ); + keyItem.data = NULL; + keyItem.len = 0; + } + + if( hexKCV != NULL ) { + PORT_ZFree( ( PRUint8 * ) + hexKCV, + hexKCVLen ); + } + + if( context ) { + PK11_DestroyContext( + /* context */ context, + /* free it */ PR_TRUE ); + } + + if( slot ) { + PK11_FreeSlot( /* slot */ slot ); + } + + /* for all keys except keys that are resident/wrapped/unwrapped . . . */ + if( ( PL_strcmp( keyType, RESIDENT_KEY ) != 0 ) && + ( PL_strcmp( keyType, UNWRAPPED_KEY ) != 0 ) && + ( PL_strcmp( keyType, WRAPPED_KEY ) != 0 ) ) { + if( key ) { + PK11_FreeSymKey( /* symmetric key */ key ); + } + } + + return status; +} + + +SECStatus +TKS_GenerateSessionKeyShare( char *sessionKeyShareName, + SECItem *sessionKeyShare ) +{ + PRIntn count = 0; + PRIntn i = 0; + PRIntn KCVLen = KCV_LENGTH; + PRUint8 *KCV = NULL; + SECItem hexSessionKeyShare = { siBuffer, + NULL, + 0 }; + SECStatus rvKCV = SECFailure; + SECStatus sessionKeyShareStatus = SECFailure; + SECStatus status = SECFailure; + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Generate a new session key share */ + PR_fprintf( PR_STDOUT, + "\nGenerating the %s session key share . . .\n\n\n", + sessionKeyShareName ); + + sessionKeyShareStatus = PK11_GenerateRandom( ( unsigned char * ) + /* data */ sessionKeyShare->data, + /* length */ sessionKeyShare->len ); + if( sessionKeyShareStatus != SECSuccess ) { + goto destroyHexSessionKeyShare; + } + + /* Create a clean new display buffer for this session key share */ + hexSessionKeyShare.type = ( SECItemType ) siBuffer; + hexSessionKeyShare.len = ( ( sessionKeyShare->len * 2 ) + 1 ); + hexSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( hexSessionKeyShare.len ); + if( hexSessionKeyShare.data == NULL ) { + goto destroyHexSessionKeyShare; + } + + /* Convert this session key share into hex digits */ + TKS_StringToHex( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) hexSessionKeyShare.data, + ( PRIntn ) hexSessionKeyShare.len ); + + /* Adjust the first DES-sized (8-byte) chunk */ + TKS_AdjustOddParity( ( PRUint8 * ) sessionKeyShare->data ); + + /* Adjust the second DES-sized (8-byte) chunk */ + TKS_AdjustOddParity( ( PRUint8 * ) ( sessionKeyShare->data + DES_LENGTH ) ); + + /* Finally, display this session key share */ + /* (adjusted for odd parity in hex digits) */ + TKS_StringToHex( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) hexSessionKeyShare.data, + ( PRIntn ) hexSessionKeyShare.len ); + + if( ( ( hexSessionKeyShare.len - 1 ) % 4 ) != 0 ) { + /* invalid key length */ + PR_fprintf( PR_STDERR, + "ERROR: Invalid session key share length " + "of %d bytes!\n\n\n", + hexSessionKeyShare.len ); + goto destroyHexSessionKeyShare; + } else { + /* Print appropriate key share name */ + PR_fprintf( PR_STDOUT, + " %s session key share: ", + sessionKeyShareName ); + + /* Print first DES_LENGTH bytes */ + count = ( ( hexSessionKeyShare.len - 1 ) / 2 ); + for( i = 0; i < count; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare.data[i], + hexSessionKeyShare.data[i + 1], + hexSessionKeyShare.data[i + 2], + hexSessionKeyShare.data[i + 3] ); + } + + /* Print appropriate key share padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( sessionKeyShareName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print second DES_LENGTH bytes */ + for( i = count; i < hexSessionKeyShare.len; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSessionKeyShare.data[i], + hexSessionKeyShare.data[i + 1], + hexSessionKeyShare.data[i + 2], + hexSessionKeyShare.data[i + 3] ); + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + } + + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + sessionKeyShareName, + SESSION_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to compute KCV of " + "this %s session key share!\n\n", + sessionKeyShareName ); + goto destroyHexSessionKeyShare; + } + + PR_fprintf( PR_STDOUT, + "(1) Write down and save the value " + "for this %s session key share.\n\n", + sessionKeyShareName ); + + PR_fprintf( PR_STDOUT, + "(2) Write down and save the KCV value " + "for this %s session key share.\n", + sessionKeyShareName ); + + /* Wait for the user to type "proceed" to continue */ + TKS_TypeProceedToContinue(); + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Report success */ + status = SECSuccess; + +destroyHexSessionKeyShare: + /* Destroy the hex session key share */ + if( hexSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexSessionKeyShare.data, + hexSessionKeyShare.len ); + hexSessionKeyShare.data = NULL; + hexSessionKeyShare.len = 0; + } + + return status; +} + +SECStatus +TKS_InputSessionKeyShare( char *sessionKeyShareName, + SECItem *sessionKeyShare ) +{ + int rv = 0; + PRIntn KCVLen = KCV_LENGTH; + PRUint8 *KCV = NULL; + SECItem hexSessionKeyShare; + PRIntn hexKCVLen = ( 2 * KCVLen ) + 1; + PRUint8 *hexKCV = NULL; + SECStatus rvKCV = SECFailure; + SECStatus status = SECFailure; + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Enter a new session key share */ + PR_fprintf( PR_STDOUT, + "\nEnter the %s session key share . . .\n\n\n", + sessionKeyShareName ); + + /* Create a clean new display buffer for this session key share */ + hexSessionKeyShare.type = ( SECItemType ) siBuffer; + hexSessionKeyShare.len = ( ( sessionKeyShare->len * 2 ) + 1 ); + hexSessionKeyShare.data = ( unsigned char * ) + PORT_ZAlloc( hexSessionKeyShare.len ); + if( hexSessionKeyShare.data == NULL ) { + goto destroyHexSessionKeyShare; + } + + rv = InputHexSessionKey( sessionKeyShareName, + &hexSessionKeyShare ); + if( rv ) { + PORT_SetError( PR_END_OF_FILE_ERROR ); + return SECFailure; + } + + /* Convert these hex digits into a session key share */ + TKS_ConvertStringOfHexCharactersIntoBitStream( ( char * ) hexSessionKeyShare.data, + ( hexSessionKeyShare.len - 1 ), + sessionKeyShare->data ); + + /* Create a clean new display buffer for this session key share KCV */ + hexKCV = ( PRUint8 * ) PORT_ZAlloc( hexKCVLen ); + if( hexKCV == NULL ) { + goto destroyHexSessionKeyShare; + } + + rv = InputHexKCV( sessionKeyShareName, + hexKCV ); + if( rv ) { + PORT_SetError( PR_END_OF_FILE_ERROR ); + return SECFailure; + } + + /* Enter the corresponding KCV */ + PR_fprintf( PR_STDOUT, + "Verifying that this session key share and KCV " + "correspond to each other . . .\n\n\n" ); + + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) sessionKeyShare->data, + ( PRIntn ) sessionKeyShare->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + sessionKeyShareName, + SESSION_KEY, + PR_FALSE, + hexKCV ); + if( rvKCV != SECSuccess ) { + goto destroyHexSessionKeyShare; + } + + /* Clear the screen */ + TKS_ClearScreen(); + + /* Report success */ + status = SECSuccess; + +destroyHexSessionKeyShare: + /* Destroy the hex session key share */ + if( hexSessionKeyShare.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexSessionKeyShare.data, + hexSessionKeyShare.len ); + hexSessionKeyShare.data = NULL; + hexSessionKeyShare.len = 0; + } + + if( hexKCV != NULL ) { + PORT_ZFree( ( PRUint8 * ) + hexKCV, + hexKCVLen ); + } + + return status; +} + + +/**************************************/ +/** public symmetric key functions **/ +/**************************************/ + +PK11SymKey * +TKS_ImportSymmetricKey( char *symmetricKeyName, + PK11SlotInfo *slot, + CK_MECHANISM_TYPE mechanism, + CK_ATTRIBUTE_TYPE operation, + SECItem *sessionKeyShare, + secuPWData *pwdata ) +{ + PK11Origin origin = PK11_OriginGenerated; + PK11SymKey *symKey = NULL; + + if( slot == NULL ) { + return NULL; + } + + PR_fprintf( PR_STDOUT, + "\n" ); + PR_fprintf( PR_STDOUT, + "Generating %s symmetric key . . .\n\n", + symmetricKeyName ); + + symKey = PK11_ImportSymKeyWithFlags( + /* slot */ slot, + /* mechanism type */ mechanism, + /* origin */ origin, + /* operation */ operation, + /* key */ sessionKeyShare, + /* flags */ 0, + /* isPerm */ PR_FALSE, + /* wincx */ pwdata ); + return symKey; +} + + +PK11SymKey * +TKS_DeriveSymmetricKey( char *symmetricKeyName, + PK11SymKey *symKey, + CK_MECHANISM_TYPE derive, + SECItem *sessionKeyShare, + CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, + int keysize ) +{ + PK11SymKey *newSymKey = NULL; + + if( symKey == NULL ) { + return NULL; + } + + if( keysize <= 0 ) { + return NULL; + } + + PR_fprintf( PR_STDOUT, + "Generating %s symmetric key . . .\n\n", + symmetricKeyName ); + + newSymKey = PK11_Derive( + /* base symmetric key */ symKey, + /* mechanism derive type */ derive, + /* param */ sessionKeyShare, + /* target */ target, + /* operation */ operation, + /* key size */ keysize ); + return newSymKey; +} + + +SECStatus +TKS_StoreSymmetricKeyAndNameIt( char *symmetricKeyName, + char *keyname, + PK11SlotInfo *slot, + CK_ATTRIBUTE_TYPE operation, + CK_FLAGS flags, + PK11SymKey *symKey ) +{ + PK11SymKey *newSymKey = NULL; + PRIntn KCVLen = KCV_LENGTH; + PRUint8 *KCV = NULL; + SECItem *symmetricKey = NULL; + SECStatus rvExtractSymmetricKey = SECFailure; + SECStatus rvKCV = SECFailure; + SECStatus rvSymmetricKeyname = SECFailure; + SECStatus status = SECFailure; +#if defined(DEBUG) + PRIntn firstCount = 0; + PRIntn secondCount = 0; + PRIntn thirdCount = 0; + PRIntn i = 0; + SECItem hexSymmetricKey; +#endif + + PR_fprintf( PR_STDOUT, + "Extracting %s key from operational token . . .\n\n", + symmetricKeyName ); + + rvExtractSymmetricKey = PK11_ExtractKeyValue( /* symmetric key */ symKey ); + if( rvExtractSymmetricKey != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to extract the %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + + /* If present, retrieve the raw key data */ + symmetricKey = PK11_GetKeyData( /* symmetric key */ symKey ); + +#if defined(DEBUG) + /* For convenience, display the final symmetric key and */ + /* its associated KCV to the user in DEBUG mode ONLY!!! */ + if( symmetricKey != NULL ) { + + /* Create a clean new display buffer for this symmetric key */ + hexSymmetricKey.type = ( SECItemType ) siBuffer; + hexSymmetricKey.len = ( ( symmetricKey->len * 2 ) + 1 ); + hexSymmetricKey.data = ( unsigned char * ) + PORT_ZAlloc( hexSymmetricKey.len ); + if( hexSymmetricKey.data == NULL ) { + goto destroyHexSymmetricKey; + } + + /* Convert this symmetric key into hex digits */ + TKS_StringToHex( ( PRUint8 * ) symmetricKey->data, + ( PRIntn ) symmetricKey->len, + ( PRUint8 * ) hexSymmetricKey.data, + ( PRIntn ) hexSymmetricKey.len ); + + /* Display this final symmetric key */ + if( ( ( hexSymmetricKey.len - 1 ) % 4 ) != 0 ) { + /* invalid key length */ + PR_fprintf( PR_STDERR, + "ERROR: Invalid symmetric key length " + "of %d bytes!\n\n\n", + hexSymmetricKey.len ); + goto destroyHexSymmetricKey; + } else { + /* Print appropriate key name */ + PR_fprintf( PR_STDOUT, + "\n %s key: ", + symmetricKeyName ); + + /* Print first DES_LENGTH bytes */ + if( symmetricKey->len == ( 3 * DES_LENGTH ) ) { + firstCount = ( ( hexSymmetricKey.len - 1 ) / 3 ); + } else { + firstCount = ( ( hexSymmetricKey.len - 1 ) / 2 ); + } + for( i = 0; i < firstCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSymmetricKey.data[i], + hexSymmetricKey.data[i + 1], + hexSymmetricKey.data[i + 2], + hexSymmetricKey.data[i + 3] ); + } + + /* Print appropriate key padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( symmetricKeyName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print second DES_LENGTH bytes */ + secondCount = firstCount * 2; + for( i = firstCount; i < secondCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSymmetricKey.data[i], + hexSymmetricKey.data[i + 1], + hexSymmetricKey.data[i + 2], + hexSymmetricKey.data[i + 3] ); + } + + /* print out last 8 bytes of triple-DES keys */ + if( symmetricKey->len == ( 3 * DES_LENGTH ) ) { + /* Print appropriate key padding length */ + PR_fprintf( PR_STDOUT, "\n " ); + for( i = 0; i < PL_strlen( symmetricKeyName ); i++ ) { + PR_fprintf( PR_STDOUT, " " ); + } + + /* Print third DES_LENGTH bytes */ + thirdCount = hexSymmetricKey.len; + for( i = secondCount; i < thirdCount; i += 4 ) { + PR_fprintf( PR_STDOUT, + "%c%c%c%c ", + hexSymmetricKey.data[i], + hexSymmetricKey.data[i + 1], + hexSymmetricKey.data[i + 2], + hexSymmetricKey.data[i + 3] ); + } + } + + /* Print appropriate vertical spacing */ + PR_fprintf( PR_STDOUT, "\n\n\n" ); + } + + /* Compute and display this final symmetric key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) symmetricKey->data, + ( PRIntn ) symmetricKey->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + symmetricKeyName, + SYMMETRIC_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to compute KCV of this %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + } +#else + /* Display the final symmetric key's associated KCV to the user . . . */ + if( symmetricKey != NULL ) { + /* . . . if and only if this is the transport key!!! */ + if( PL_strcmp( symmetricKeyName, TRANSPORT_KEY ) == 0 ) { + /* Compute and display this transport key's KCV */ + rvKCV = TKS_ComputeAndDisplayKCV( ( PRUint8 * ) symmetricKey->data, + ( PRIntn ) symmetricKey->len, + ( PRUint8 * ) KCV, + ( PRIntn ) KCVLen, + NULL, + symmetricKeyName, + TRANSPORT_KEY, + PR_TRUE, + NULL ); + if( rvKCV != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to compute KCV of this %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + } + } +#endif + + PR_fprintf( PR_STDOUT, + "Storing %s key on final specified token . . .\n\n", + symmetricKeyName ); + + newSymKey = PK11_MoveSymKey( + /* slot */ slot, + /* operation */ operation, + /* flags */ flags, + /* permanence */ PR_TRUE, + /* symmetric key */ symKey ); + if( newSymKey == NULL ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to store the %s key: %d!\n\n", + symmetricKeyName, + PR_GetError() ); + goto destroyHexSymmetricKey; + } + + + PR_fprintf( PR_STDOUT, + "Naming %s key \"%s\" . . .\n\n", + symmetricKeyName, + keyname ); + + rvSymmetricKeyname = PK11_SetSymKeyNickname( + /* symmetric key */ newSymKey, + /* nickname */ keyname ); + if( rvSymmetricKeyname != SECSuccess ) { + PR_fprintf( PR_STDERR, + "ERROR: Failed to name the %s key!\n\n", + symmetricKeyName ); + goto destroyHexSymmetricKey; + } + + status = SECSuccess; + + +destroyHexSymmetricKey: + +#if defined(DEBUG) + /* Destroy the hex symmetric key */ + if( hexSymmetricKey.data != NULL ) { + PORT_ZFree( ( unsigned char * ) + hexSymmetricKey.data, + hexSymmetricKey.len ); + hexSymmetricKey.data = NULL; + hexSymmetricKey.len = 0; + } +#endif + + return status; +} + |