summaryrefslogtreecommitdiffstats
path: root/pki/base/native-tools/src/tkstool/key.c
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/native-tools/src/tkstool/key.c')
-rw-r--r--pki/base/native-tools/src/tkstool/key.c1350
1 files changed, 1350 insertions, 0 deletions
diff --git a/pki/base/native-tools/src/tkstool/key.c b/pki/base/native-tools/src/tkstool/key.c
new file mode 100644
index 000000000..4fd37963b
--- /dev/null
+++ b/pki/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;
+}
+