From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: 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 --- base/symkey/src/com/netscape/symkey/Base.h | 44 + base/symkey/src/com/netscape/symkey/Buffer.cpp | 183 ++ base/symkey/src/com/netscape/symkey/Buffer.h | 173 ++ base/symkey/src/com/netscape/symkey/CMakeLists.txt | 63 + .../symkey/src/com/netscape/symkey/EncryptData.cpp | 250 +++ base/symkey/src/com/netscape/symkey/SessionKey.cpp | 2005 ++++++++++++++++++++ .../symkey/src/com/netscape/symkey/SessionKey.java | 167 ++ base/symkey/src/com/netscape/symkey/SymKey.cpp | 1407 ++++++++++++++ base/symkey/src/com/netscape/symkey/SymKey.h | 55 + 9 files changed, 4347 insertions(+) create mode 100644 base/symkey/src/com/netscape/symkey/Base.h create mode 100644 base/symkey/src/com/netscape/symkey/Buffer.cpp create mode 100644 base/symkey/src/com/netscape/symkey/Buffer.h create mode 100644 base/symkey/src/com/netscape/symkey/CMakeLists.txt create mode 100644 base/symkey/src/com/netscape/symkey/EncryptData.cpp create mode 100644 base/symkey/src/com/netscape/symkey/SessionKey.cpp create mode 100644 base/symkey/src/com/netscape/symkey/SessionKey.java create mode 100644 base/symkey/src/com/netscape/symkey/SymKey.cpp create mode 100644 base/symkey/src/com/netscape/symkey/SymKey.h (limited to 'base/symkey/src/com/netscape/symkey') diff --git a/base/symkey/src/com/netscape/symkey/Base.h b/base/symkey/src/com/netscape/symkey/Base.h new file mode 100644 index 000000000..cdcf72bcf --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/Base.h @@ -0,0 +1,44 @@ +// --- 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifndef BASE_H +#define BASE_H +#include + +typedef unsigned char BYTE; + +enum nsNKeyMsgEnum { + VRFY_FAILURE, + VRFY_SUCCESS, + ENCODE_DER_PUBKEY_FAILURE, + B64ENCODE_FAILURE, + VFY_BEGIN_FAILURE, + VFY_UPDATE_FAILURE, + HTTP_REQ_EXE_FAILURE, + HTTP_ERROR_RCVD, + BASE64_DECODE_FAILURE, + REQ_TO_CA_SUCCESS, + MSG_INVALID +}; + +struct ReturnStatus { + PRStatus status; + nsNKeyMsgEnum statusNum; +}; + +#endif /* BASE_H */ diff --git a/base/symkey/src/com/netscape/symkey/Buffer.cpp b/base/symkey/src/com/netscape/symkey/Buffer.cpp new file mode 100644 index 000000000..5c687c5f5 --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/Buffer.cpp @@ -0,0 +1,183 @@ +// --- 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#include +#include +#include +#include +#include + +#include "Buffer.h" + +Buffer::Buffer(const BYTE *buf_, unsigned int len_) : len(len_), res(len_) +{ + buf = new BYTE[len]; + memcpy(buf, buf_, len); +} + +Buffer::Buffer(const Buffer& cpy) +{ + buf = 0; + *this = cpy; +} + +Buffer::Buffer(unsigned int len_) : len(len_), res(len_) +{ + buf = new BYTE[res]; + memset(buf, 0, len_); +} + +Buffer::Buffer(unsigned int len_, BYTE b) : len(len_), res(len_) +{ + buf = new BYTE[res]; + memset(buf, b, len); +} + +Buffer::~Buffer() +{ + delete [] buf; +} + +bool +Buffer::operator==(const Buffer& cmp) const +{ + if( len != cmp.len ) return false; + for( unsigned int i=0; i < len; ++i ) { + if( buf[i] != cmp.buf[i] ) { + return false; + } + } + return true; +} + +Buffer& +Buffer::operator=(const Buffer& cpy) +{ + if( this == &cpy ) return *this; + len = cpy.len; + delete [] buf; + buf = new BYTE[len]; + memcpy(buf, cpy.buf, len); + res = len; + + return *this; +} + +void +Buffer::zeroize() +{ + if( len > 0 ) { + memset( buf, 0, len ); + } +} + +Buffer +Buffer::operator+(const Buffer& addend) const +{ + Buffer result(len + addend.len); + memcpy(result.buf, buf, len); + memcpy(result.buf+len, addend.buf, addend.len); + return result; +} + +Buffer& +Buffer::operator+=(const Buffer& addend) +{ + unsigned int oldLen = len; + resize(len + addend.len); + memcpy(buf+oldLen, addend.buf, addend.len); + return *this; +} + +Buffer& +Buffer::operator+=(BYTE b) +{ + resize(len+1); + buf[len-1] = b; + return *this; +} + +void +Buffer::reserve(unsigned int n) +{ + if( n > res ) { + BYTE *newBuf = new BYTE[n]; + memcpy(newBuf, buf, len); + delete [] buf; + buf = newBuf; + res = n; + } +} + +void +Buffer::resize(unsigned int newLen) +{ + if( newLen == len ) { + return; + } else if( newLen < len ) { + len = newLen; + } else if( newLen <= res ) { + assert( newLen > len ); + memset(buf+len, 0, newLen-len); + len = newLen; + } else { + assert( newLen > len && newLen > res ); + BYTE *newBuf = new BYTE[newLen]; + memcpy(newBuf, buf, len); + memset(newBuf+len, 0, newLen-len); + delete [] buf; + buf = newBuf; + len = newLen; + res = newLen; + } +} + +Buffer +Buffer::substr(unsigned int i, unsigned int n) const +{ + assert( i < len && (i+n) <= len ); + return Buffer( buf+i, n ); +} + +void +Buffer::replace(unsigned int i, const BYTE* cpy, unsigned int n) +{ + if (len > i+n) { + resize( len); + }else { + resize( i+n ); + } + memcpy(buf+i, cpy, n); +} + +void +Buffer::dump() const +{ + unsigned int i; + + for( i=0; i < len; ++i ) { + printf("%02x ", buf[i]); + if( i % 16 == 15 ) printf("\n"); + } + printf("\n"); +} + +static const char hextbl[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; diff --git a/base/symkey/src/com/netscape/symkey/Buffer.h b/base/symkey/src/com/netscape/symkey/Buffer.h new file mode 100644 index 000000000..2e0256d87 --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/Buffer.h @@ -0,0 +1,173 @@ +// --- 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifndef BUFFER_H +#define BUFFER_H + +#include +#include "Base.h" + +/** + * This class represents a byte array. + */ +class Buffer { + + private: + BYTE *buf; + unsigned int len; + unsigned int res; + + public: + /** + * Creates an empty Buffer. + */ + Buffer() : buf(0), len(0), res(0) { } + + /** + * Creates a Buffer of length 'len', with each byte initialized to 'b'. + */ + Buffer(unsigned int len, BYTE b); + + /** + * Creates a Buffer of length 'len', initialized to zeroes. + */ + explicit Buffer(unsigned int len); + + /** + * Creates a Buffer of length 'len', initialized from 'buf'. 'buf' must + * contain at least 'len' bytes. + */ + Buffer(const BYTE* buf, unsigned int len); + + /** + * Copy constructor. + */ + Buffer(const Buffer& cpy); + + /** + * Destructor. + */ + ~Buffer(); + + /** + * Assignment operator. + */ + Buffer& operator=(const Buffer& cpy); + + /** + * Returns true if the two buffers are the same length and contain + * the same byte at each offset. + */ + bool operator==(const Buffer& cmp) const; + + /** + * Returns ! operator==(cmp). + */ + bool operator!=(const Buffer& cmp) const { return ! (*this == cmp); } + + /** + * Concatenation operator. + */ + Buffer operator+(const Buffer&addend) const; + + /** + * Append operators. + */ + Buffer& operator+=(const Buffer&addend); + Buffer& operator+=(BYTE b); + + /** + * Returns a pointer into the Buffer. This also enables the subscript + * operator, so you can say, for example, 'buf[4] = b' or 'b = buf[4]'. + */ + operator BYTE*() { return buf; } + operator const BYTE*() const { return buf; } + + /** + * The length of buffer. The actual amount of space allocated may be + * higher--see capacity(). + */ + unsigned int size() const { return len; } + + /** + * The amount of memory allocated for the buffer. This is the maximum + * size the buffer can grow before it needs to allocate more memory. + */ + unsigned int capacity() const { return res; } + + /** + * Sets all bytes in the buffer to 0. + */ + void zeroize(); + + /** + * Changes the length of the Buffer. If 'newLen' is shorter than the + * current length, the Buffer is truncated. If 'newLen' is longer, the + * new bytes are initialized to 0. If 'newLen' is the same as size(), + * this is a no-op. + */ + void resize(unsigned int newLen); + + /** + * Ensures that capacity() is at least 'reserve'. Allocates more memory + * if necessary. If 'reserve' is <= capacity(), this is a no-op. + * Does not affect size(). + */ + void reserve(unsigned int reserve); + + /** + * Returns a new Buffer that is a substring of this Buffer, starting + * from offset 'start' and continuing for 'len' bytes. This Buffer + * must have size() >= (start + len). + */ + Buffer substr(unsigned int start, unsigned int len) const; + + /** + * Replaces bytes i through i+n in this Buffer using the values in 'cpy'. + * This Buffer is resized if necessary. The 'cpy' argument can be a + * Buffer. + */ + void replace(unsigned int i, const BYTE* cpy, unsigned int n); + + /** + * returns a hex version of the buffer + */ + char *toHex(); + + /** + * Dumps this Buffer to the given file as formatted hex: 16 bytes per + * line, separated by spaces. + */ + void dump(FILE* file) const; + + /** + * returns a null-terminated string of the buf. + * should be called only by callers that are certain that buf + * is entirely representable by printable characters and wants + * a string instead. + */ + char *string(); + + /** + * dump()s this Buffer to stdout. + */ + void dump() const; + +}; + +#endif diff --git a/base/symkey/src/com/netscape/symkey/CMakeLists.txt b/base/symkey/src/com/netscape/symkey/CMakeLists.txt new file mode 100644 index 000000000..47d40a3f1 --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/CMakeLists.txt @@ -0,0 +1,63 @@ +project(symkey_library CXX) + +set(SYMKEY_PUBLIC_INCLUDE_DIRS + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + CACHE INTERNAL "symkey public include directories" +) + +set(SYMKEY_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${JNI_INCLUDE_DIRS} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(SYMKEY_SHARED_LIBRARY + symkey_library + CACHE INTERNAL "symkey shared library" +) + +set(SYMKEY_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(symkey_library_HDRS + SessionKey.h +) + +set(symkey_library_SRCS + Buffer.cpp + EncryptData.cpp + SessionKey.cpp + SymKey.cpp +) + +include_directories(${SYMKEY_PRIVATE_INCLUDE_DIRS}) + +add_custom_command( + OUTPUT + ${symkey_library_HDRS} + COMMAND + ${JAVA_HEADER} + -classpath ${SYMKEY_JAVA_OBJECT_DIR}:${JAVA_LIB_INSTALL_DIR}/jss4.jar + -jni -d ${CMAKE_CURRENT_BINARY_DIR} + com.netscape.symkey.SessionKey +) + +add_library(${SYMKEY_SHARED_LIBRARY} SHARED ${symkey_library_HDRS} ${symkey_library_SRCS}) +target_link_libraries(${SYMKEY_SHARED_LIBRARY} ${SYMKEY_LINK_LIBRARIES}) +add_dependencies(${SYMKEY_SHARED_LIBRARY} symkey) + +set_target_properties(${SYMKEY_SHARED_LIBRARY} + PROPERTIES + OUTPUT_NAME + symkey +) + +install( + TARGETS + ${SYMKEY_SHARED_LIBRARY} + LIBRARY DESTINATION ${LIB_INSTALL_DIR}/symkey +) diff --git a/base/symkey/src/com/netscape/symkey/EncryptData.cpp b/base/symkey/src/com/netscape/symkey/EncryptData.cpp new file mode 100644 index 000000000..ccb817f7c --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/EncryptData.cpp @@ -0,0 +1,250 @@ +// --- 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifdef __cplusplus +extern "C" +{ +#endif +#include "pk11func.h" +#include "nspr.h" +#ifdef __cplusplus +#include +#include +#include + +} +#endif +#include +#include +#include +#include +#include +#include +#include "Buffer.h" +#include "SymKey.h" +#define DES2_WORKAROUND + +PRFileDesc *d = NULL; + +void GetKeyName(jbyte *keyVersion, char *keyname) +{ + int index=0; + + if( !keyname || !keyVersion || + (strlen(keyname) < KEYNAMELENGTH)) { + return; + } + + if(strlen(masterKeyPrefix)!=0) + { + index= strlen(masterKeyPrefix); + strcpy(keyname,masterKeyPrefix); + } + + if( (index + 3) >= KEYNAMELENGTH) { + return; + } + + keyname[index+0]='#'; + sprintf(keyname+index+1,"%.2d", keyVersion[0]); + keyname[index+3]='#'; + sprintf(keyname+index+4,"%.2d", keyVersion[1]); +} + + +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_EncryptData +(JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring); + +extern "C" JNIEXPORT jbyteArray JNICALL +Java_com_netscape_symkey_SessionKey_EncryptData(JNIEnv * env, jclass this2, jstring j_tokenName, jstring j_keyName, jbyteArray j_in, jbyteArray keyInfo, jbyteArray CUID, jbyteArray kekKeyArray, jstring useSoftToken_s,jstring keySet) +{ + jbyte * kek_key = NULL; + + PK11SymKey *masterKey = NULL; + PK11SymKey *kekKey = NULL; + + Buffer out = Buffer(KEYLENGTH, (BYTE)0); + BYTE kekData[KEYLENGTH]; + char keyname[KEYNAMELENGTH]; + + int status = PR_FAILURE; + + jbyte *cc = NULL; + int cc_len = 0; + jbyte * cuidValue = NULL; + + if( kekKeyArray != NULL) { + kek_key = (jbyte*)(env)->GetByteArrayElements(kekKeyArray, NULL); + } else { + return NULL; + } + + PK11SlotInfo *slot = NULL; + PK11SlotInfo *internal = PK11_GetInternalKeySlot(); + + Buffer kek_buffer = Buffer((BYTE*)kek_key, KEYLENGTH); + char *keySetStringChars = NULL; + if( keySet != NULL) { + keySetStringChars = (char *) (env)->GetStringUTFChars( keySet, NULL); + } + + char *keySetString = keySetStringChars; + + if ( keySetString == NULL ) { + keySetString = (char *) DEFKEYSET_NAME; + } + + jbyte * keyVersion = NULL; + int keyVersion_len = 0; + if( keyInfo != NULL) { + keyVersion = (jbyte*)(env)->GetByteArrayElements( keyInfo, NULL); + if( keyVersion) { + keyVersion_len = (env)->GetArrayLength(keyInfo); + } + } + + if( !keyVersion || (keyVersion_len < 2) ) { + goto done; + } + + if( CUID != NULL) { + cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL); + } + + if( cuidValue == NULL) { + goto done; + } + + if( j_in != NULL) { + cc = (jbyte*)(env)->GetByteArrayElements( j_in, NULL); + cc_len = (env)->GetArrayLength(j_in); + } + + if( cc == NULL) { + goto done; + } + + GetDiversificationData(cuidValue,kekData,kek); + + PR_fprintf(PR_STDOUT,"In SessionKey: EncryptData! \n"); + + if(j_tokenName != NULL) { + char *tokenNameChars = (char *)(env)->GetStringUTFChars(j_tokenName, NULL); + slot = ReturnSlot(tokenNameChars); + (env)->ReleaseStringUTFChars(j_tokenName, (const char *)tokenNameChars); + tokenNameChars = NULL; + } + + if(j_keyName != NULL) { + char *keyNameChars= (char *)(env)->GetStringUTFChars(j_keyName, NULL); + strcpy(keyname,keyNameChars); + env->ReleaseStringUTFChars(j_keyName, (const char *)keyNameChars); + keyNameChars = NULL; + } + else { + GetKeyName(keyVersion,keyname); + } + + if ( (keyVersion[0] == 0x1 && keyVersion[1]== 0x1 && strcmp( keyname, "#01#01") == 0) || + (keyVersion[0] == -1 && strstr(keyname, "#FF") )) + { + /* default development keyset */ + Buffer devInput = Buffer((BYTE*)cc, cc_len); + Buffer empty = Buffer(); + + kekKey = ReturnDeveloperSymKey( internal, (char *) "kek", keySetString, empty); + + if ( kekKey ) { + status = EncryptData(Buffer(),kekKey,devInput, out); + } else { + status = EncryptData(kek_buffer, NULL, devInput, out); + } + } + else + { + if (slot!=NULL) + { + masterKey = ReturnSymKey( slot,keyname); + + /* We need to use internal so that the key + * can be exported by using PK11_GetKeyData() + */ + if (masterKey != NULL) + { + kekKey = ComputeCardKeyOnToken(masterKey,kekData); + if (kekKey != NULL) + { + Buffer input = Buffer((BYTE*)cc, cc_len); + status = EncryptData(Buffer(), kekKey, input, out); + } + } + } + } + +done: + + if (masterKey != NULL) { + PK11_FreeSymKey( masterKey); + masterKey = NULL; + } + + if( slot != NULL ) { + PK11_FreeSlot( slot); + slot = NULL; + } + + if( internal != NULL) { + PK11_FreeSlot( internal); + internal = NULL; + } + + if ( kekKey != NULL) { + PK11_FreeSymKey( kekKey); + kekKey = NULL; + } + + if( keySetStringChars ) { + (env)->ReleaseStringUTFChars(keySet, (const char *)keySetStringChars); + keySetStringChars = NULL; + } + + jbyteArray handleBA=NULL; + if (status != PR_FAILURE && (out.size()>0) ) { + jbyte *handleBytes=NULL; + handleBA = (env)->NewByteArray( out.size()); + handleBytes = (env)->GetByteArrayElements(handleBA, NULL); + BYTE* outp = (BYTE*)out; + memcpy(handleBytes, outp,out.size()); + env->ReleaseByteArrayElements( handleBA, handleBytes, 0); + handleBytes=NULL; + } + + if( cc != NULL) { + env->ReleaseByteArrayElements(j_in, cc, JNI_ABORT); + } + + if( keyVersion != NULL) { + env->ReleaseByteArrayElements(keyInfo, keyVersion, JNI_ABORT); + } + + if( cuidValue != NULL) { + env->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT); + } + + return handleBA; +} diff --git a/base/symkey/src/com/netscape/symkey/SessionKey.cpp b/base/symkey/src/com/netscape/symkey/SessionKey.cpp new file mode 100644 index 000000000..eb412f01a --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/SessionKey.cpp @@ -0,0 +1,2005 @@ + +// 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifdef __cplusplus +extern "C" +{ +#endif +#include "pk11func.h" +#include "seccomon.h" +#include "nspr.h" +#ifdef __cplusplus +#include +#include +#include +#include "secerr.h" + +/* +#include +#include +*/ + +} +#endif +#include +#include +#include +#include +#include + +// DRM_PROTO begins +#define PK11SYMKEY_CLASS_NAME "org/mozilla/jss/pkcs11/PK11SymKey" +#define PK11SYMKEY_CONSTRUCTOR_SIG "([B)V" +#define ALL_SYMKEY_OPS (CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP) +// DRM_PROTO ends + +#include "Buffer.h" +#include "SymKey.h" + +#define STEAL_JSS +#ifdef STEAL_JSS +// stealing code from JSS to handle DRM support +/* + * NativeProxy + */ +#define NATIVE_PROXY_CLASS_NAME "org/mozilla/jss/util/NativeProxy" +#define NATIVE_PROXY_POINTER_FIELD "mPointer" +#define NATIVE_PROXY_POINTER_SIG "[B" + +/* + * SymKeyProxy + */ +#define SYM_KEY_PROXY_FIELD "keyProxy" +#define SYM_KEY_PROXY_SIG "Lorg/mozilla/jss/pkcs11/SymKeyProxy;" + + +/*********************************************************************** + ** + ** J S S _ p t r T o B y t e A r r a y + ** + ** Turn a C pointer into a Java byte array. The byte array can be passed + ** into a NativeProxy constructor. + ** + ** Returns a byte array containing the pointer, or NULL if an exception + ** was thrown. + */ +jbyteArray +JSS_ptrToByteArray(JNIEnv *env, void *ptr) +{ + jbyteArray byteArray; + + /* Construct byte array from the pointer */ + byteArray = (env)->NewByteArray(sizeof(ptr)); + if(byteArray==NULL) + { + PR_ASSERT( (env)->ExceptionOccurred() != NULL); + return NULL; + } + (env)->SetByteArrayRegion(byteArray, 0, sizeof(ptr), (jbyte*)&ptr); + if((env)->ExceptionOccurred() != NULL) + { + PR_ASSERT(PR_FALSE); + return NULL; + } + return byteArray; +} + + +/*********************************************************************** + * + * J S S _ P K 1 1 _ w r a p S y m K e y + + * Puts a Symmetric Key into a Java object. + * (Does NOT perform a cryptographic "wrap" operation.) + * symKey: will be stored in a Java wrapper. + * Returns: a new PK11SymKey, or NULL if an exception occurred. + */ +jobject +JSS_PK11_wrapSymKey(JNIEnv *env, PK11SymKey **symKey) +{ +// return JSS_PK11_wrapSymKey(env, symKey, NULL); +// hmmm, looks like I may not need to steal code after all + return JSS_PK11_wrapSymKey(env, symKey); +} + + +jobject +JSS_PK11_wrapSymKey(JNIEnv *env, PK11SymKey **symKey, PRFileDesc *debug_fd) +{ + jclass keyClass; + jmethodID constructor; + jbyteArray ptrArray; + jobject Key=NULL; + + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey\n"); + + PR_ASSERT(env!=NULL && symKey!=NULL && *symKey!=NULL); + + /* find the class */ + keyClass = (env)->FindClass(PK11SYMKEY_CLASS_NAME); + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey called FindClass\n"); + if( keyClass == NULL ) + { + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey FindClass NULL\n"); +// ASSERT_OUTOFMEM(env); + goto finish; + } + + /* find the constructor */ + constructor = (env)->GetMethodID(keyClass, + ""/*PLAIN_CONSTRUCTOR*/, + PK11SYMKEY_CONSTRUCTOR_SIG); + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey called GetMethodID\n"); + if(constructor == NULL) + { +// ASSERT_OUTOFMEM(env); + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey GetMethodID returns NULL\n"); + goto finish; + } + + /* convert the pointer to a byte array */ + ptrArray = JSS_ptrToByteArray(env, (void*)*symKey); + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey called JSS_ptrToByteArray\n"); + if( ptrArray == NULL ) + { + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey JSS_ptrToByteArray returns NULL\n"); + goto finish; + } + + /* call the constructor */ + Key = (env)->NewObject( keyClass, constructor, ptrArray); + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey called NewObject\n"); + +finish: + if(Key == NULL) + { + if (debug_fd) + PR_fprintf(debug_fd, "DRMproto in JSS_PK11_wrapSymKey NewObject returns NULL\n"); + PK11_FreeSymKey(*symKey); + } + *symKey = NULL; + return Key; +} + + +/*********************************************************************** + ** + ** J S S _ g e t P t r F r o m P r o x y + ** + ** Given a NativeProxy, extract the pointer and store it at the given + ** address. + ** + ** nativeProxy: a JNI reference to a NativeProxy. + ** ptr: address of a void* that will receive the pointer extracted from + ** the NativeProxy. + ** Returns: PR_SUCCESS on success, PR_FAILURE if an exception was thrown. + ** + ** Example: + ** DataStructure *recovered; + ** jobject proxy; + ** JNIEnv *env; + ** [...] + ** if(JSS_getPtrFromProxy(env, proxy, (void**)&recovered) != PR_SUCCESS) { + ** return; // exception was thrown! + ** } + */ +PRStatus +JSS_getPtrFromProxy(JNIEnv *env, jobject nativeProxy, void **ptr) +{ +#ifdef DEBUG + jclass nativeProxyClass; +#endif + jclass proxyClass; + jfieldID byteArrayField; + jbyteArray byteArray; + int size; + + PR_ASSERT(env!=NULL && nativeProxy != NULL && ptr != NULL); + if( nativeProxy == NULL ) + { +// JSS_throw(env, NULL_POINTER_EXCEPTION); + return PR_FAILURE; + } + + proxyClass = (env)->GetObjectClass(nativeProxy); + PR_ASSERT(proxyClass != NULL); + +#ifdef DEBUG + nativeProxyClass = (env)->FindClass( + NATIVE_PROXY_CLASS_NAME); + if(nativeProxyClass == NULL) + { +// ASSERT_OUTOFMEM(env); + return PR_FAILURE; + } + + /* make sure what we got was really a NativeProxy object */ + PR_ASSERT( (env)->IsInstanceOf(nativeProxy, nativeProxyClass) ); +#endif + + byteArrayField = (env)->GetFieldID( + proxyClass, + NATIVE_PROXY_POINTER_FIELD, + NATIVE_PROXY_POINTER_SIG); + if(byteArrayField==NULL) + { +// ASSERT_OUTOFMEM(env); + return PR_FAILURE; + } + + byteArray = (jbyteArray) (env)->GetObjectField(nativeProxy, + byteArrayField); + PR_ASSERT(byteArray != NULL); + + size = sizeof(*ptr); + PR_ASSERT((env)->GetArrayLength( byteArray) == size); + (env)->GetByteArrayRegion(byteArray, 0, size, (jbyte*)ptr); + if( (env)->ExceptionOccurred() ) + { + PR_ASSERT(PR_FALSE); + return PR_FAILURE; + } + else + { + return PR_SUCCESS; + } +} + + +/*********************************************************************** + ** + ** J S S _ g e t P t r F r o m P r o x y O w n e r + ** + ** Given an object which contains a NativeProxy, extract the pointer + ** from the NativeProxy and store it at the given address. + ** + ** proxyOwner: an object which contains a NativeProxy member. + ** proxyFieldName: the name of the NativeProxy member. + ** proxyFieldSig: the signature of the NativeProxy member. + ** ptr: address of a void* that will receive the extract pointer. + ** Returns: PR_SUCCESS for success, PR_FAILURE if an exception was thrown. + ** + ** Example: + ** + ** public class Owner { + ** protected MyProxy myProxy; + ** [...] + ** } + ** + ** + ** DataStructure *recovered; + ** jobject owner; + ** JNIEnv *env; + ** [...] + ** if(JSS_getPtrFromProxyOwner(env, owner, "myProxy", (void**)&recovered) + ** != PR_SUCCESS) { + ** return; // exception was thrown! + ** } + */ +PRStatus +JSS_getPtrFromProxyOwner(JNIEnv *env, jobject proxyOwner, char* proxyFieldName, +char *proxyFieldSig, void **ptr) +{ + jclass ownerClass; + jfieldID proxyField; + jobject proxyObject; + + PR_ASSERT(env!=NULL && proxyOwner!=NULL && proxyFieldName!=NULL && + ptr!=NULL); + + /* + * Get proxy object + */ + ownerClass = (env)->GetObjectClass(proxyOwner); + proxyField = (env)->GetFieldID(ownerClass, proxyFieldName, + proxyFieldSig); + if(proxyField == NULL) + { + return PR_FAILURE; + } + proxyObject = (env)->GetObjectField(proxyOwner, proxyField); + PR_ASSERT(proxyObject != NULL); + + /* + * Get the pointer from the Native Reference object + */ + return JSS_getPtrFromProxy(env, proxyObject, ptr); +} + + +/*********************************************************************** + * + * J S S _ P K 1 1 _ g e t S y m K e y P t r + * + */ +PRStatus +JSS_PK11_getSymKeyPtr(JNIEnv *env, jobject symKeyObject, PK11SymKey **ptr) +{ + PR_ASSERT(env!=NULL && symKeyObject!=NULL); + + /* Get the pointer from the key proxy */ + return JSS_getPtrFromProxyOwner(env, symKeyObject, SYM_KEY_PROXY_FIELD, + SYM_KEY_PROXY_SIG, (void**)ptr); +} +#endif //STEAL_JSS +// Function takes wither a symkey OR a keybuffer (for the default keyset case) +// To derive a new key. +PK11SymKey *DeriveKey(PK11SymKey *cardKey, const Buffer& hostChallenge, const Buffer& cardChallenge) +{ + PK11SymKey *key = NULL, *master = NULL; + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PK11Context *context = NULL; + unsigned char derivationData[KEYLENGTH]; +#ifdef DES2_WORKAROUND + unsigned char keyData[DES3_LENGTH]; +#else + unsigned char keyData[KEYLENGTH]; +#endif + int i = 0; + SECStatus s = SECSuccess; + int len = 0;; + static SECItem noParams = { siBuffer, NULL, 0 }; + + /* vars for PK11_Derive section */ + SECItem param = { siBuffer, NULL, 0 }; + CK_KEY_DERIVATION_STRING_DATA string; + PK11SymKey *tmp1 = NULL; + PK11SymKey *tmp2 = NULL; + PRBool invalid_mechanism = PR_FALSE; + CK_OBJECT_HANDLE keyhandle = 0; + + PR_fprintf(PR_STDOUT,"In DeriveKey! \n"); + master = cardKey; + + if( ! master ) goto done; + + for(i = 0;i < 4;i++) + { + derivationData[i] = cardChallenge[i+4]; + derivationData[i+4] = hostChallenge[i]; + derivationData[i+8] = cardChallenge[i]; + derivationData[i+12] = hostChallenge[i+4]; + } + + string.pData = &derivationData[0]; + string.ulLen = EIGHT_BYTES; + param.data = (unsigned char*)&string; + param.len = sizeof(string); + + invalid_mechanism = PR_FALSE; + + tmp1 = PK11_Derive( master , CKM_DES_ECB_ENCRYPT_DATA , ¶m , CKM_CONCATENATE_BASE_AND_KEY , CKA_DERIVE, 0); + + if ( tmp1 == NULL) { + if ( PR_GetError() == SEC_ERROR_NO_TOKEN) + invalid_mechanism = PR_TRUE; + + PR_fprintf(PR_STDERR,"DeriveKey: Can't create key, using encrypt and derive method ! error %d \n", PR_GetError()); + } else { + PR_fprintf(PR_STDOUT,"DeriveKey: Successfully created key using encrypt and derive method! \n"); + } + + if ( invalid_mechanism == PR_FALSE) { + + string.pData = &derivationData[EIGHT_BYTES]; + string.ulLen = EIGHT_BYTES; + + tmp2 = PK11_Derive( master , CKM_DES_ECB_ENCRYPT_DATA , ¶m , CKM_CONCATENATE_BASE_AND_KEY , CKA_DERIVE , 0); + + if ( tmp2 == NULL) { + PR_fprintf(PR_STDERR,"DeriveKey: Can't derive key using CONCATENATE method! \n"); + goto done; + } else { + PR_fprintf(PR_STDOUT,"DeriveKey: Successfully created key using CONCATENATE method! \n"); + } + + keyhandle = PK11_GetSymKeyHandle(tmp2); + + param.data=(unsigned char *) &keyhandle; + param.len=sizeof(keyhandle); + + key = PK11_Derive ( tmp1 , CKM_CONCATENATE_BASE_AND_KEY , ¶m ,CKM_DES3_ECB , CKA_DERIVE , 16); + + if ( key == NULL) { + PR_fprintf(PR_STDERR,"DeriveKey: Can't create final derived key! \n"); + goto done; + } else { + PR_fprintf(PR_STDOUT,"DeriveKey: Successfully created final derived key! \n"); + } + + } else { /* We don't have access to the proper derive mechanism, use primitive mechanisms now */ + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, master, + &noParams); + + if (!context) goto done; + + s = PK11_CipherOp(context, &keyData[0], &len, EIGHT_BYTES, &derivationData[0], EIGHT_BYTES); + if (s != SECSuccess) goto done; + + s = PK11_CipherOp(context, &keyData[EIGHT_BYTES], &len, 8, &derivationData[EIGHT_BYTES], EIGHT_BYTES); + if (s != SECSuccess) goto done; + + for(i = 0;i < EIGHT_BYTES ;i++) + { + keyData[i+KEYLENGTH] = keyData[i]; + } + + key = CreateUnWrappedSymKeyOnToken( slot, master, &keyData[0] , DES3_LENGTH, PR_FALSE ); + + if ( key == NULL ) { + PR_fprintf(PR_STDERR,"DeriveKey: CreateUnWrappedSymKey failed! %d \n", PR_GetError()); + } else { + PR_fprintf(PR_STDOUT,"DeriveKey: CreateUnWrappedSymKey succeeded! \n"); + } + } + + done: + memset(keyData, 0, sizeof keyData); + if ( context != NULL) { + PK11_DestroyContext(context, PR_TRUE); + context = NULL; + } + + if (slot) { + PK11_FreeSlot(slot); + slot = NULL; + } + + if (tmp1) { + PK11_FreeSymKey(tmp1); + tmp1 = NULL; + } + + if (tmp2) { + PK11_FreeSymKey(tmp2); + tmp2 = NULL; + } + + return key; +} + +#ifdef __cplusplus +extern "C" +{ +#endif + JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeKeyCheck + (JNIEnv *, jclass, jobject deskeyObj); +#ifdef __cplusplus +} +#endif +extern "C" JNIEXPORT jbyteArray JNICALL +Java_com_netscape_symkey_SessionKey_ComputeKeyCheck +(JNIEnv* env, jclass this2, jobject deskeyObj) +{ + jbyteArray handleBA=NULL; + jbyte *handleBytes=NULL; + + PK11SymKey *key = NULL; +// PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PK11Context *context = NULL; + SECStatus s = SECFailure; + PRStatus r = PR_FAILURE; + int lenx = 0; + static SECItem noParams = { siBuffer, NULL, 0 }; + + unsigned char value[EIGHT_BYTES]; + + memset(value, 0, sizeof value); + + r = JSS_PK11_getSymKeyPtr(env, deskeyObj, &key); + + if (r != PR_SUCCESS) { + goto finish; + } + + if ( ! key ) { + goto finish; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, key, + &noParams); + if (!context) { + goto finish; + } + + s = PK11_CipherOp(context, &value[0], &lenx, EIGHT_BYTES, &value[0], EIGHT_BYTES); + if (s != SECSuccess) + { + goto finish; + } + handleBA = (env)->NewByteArray(3); + if(handleBA == NULL ) { + goto finish; + } + handleBytes = (env)->GetByteArrayElements(handleBA, NULL); + if(handleBytes==NULL) { + goto finish; + } + memcpy(handleBytes, value, 3); + + if( handleBytes != NULL) { + (env)->ReleaseByteArrayElements(handleBA, handleBytes, 0); + } + +finish: + + if ( context != NULL) { + PK11_DestroyContext(context, PR_TRUE); + context = NULL; + } + +// if ( slot != NULL) { +// PK11_FreeSlot(slot); +// slot = NULL; +// } + + return handleBA; +} + + +//================================================================================= +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: ComputeSessionKey + * Signature: ([B[B[B[B)[B + */ + JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeSessionKey + (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring, jstring); +#ifdef __cplusplus +} +#endif +#define KEYLENGTH 16 +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeSessionKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, jbyteArray macKeyArray, jstring useSoftToken_s, jstring keySet, jstring sharedSecretKeyName) +{ + /* hardcore permanent mac key */ + jbyte *mac_key = NULL; + if (macKeyArray != NULL) { + mac_key = (jbyte*)(env)->GetByteArrayElements(macKeyArray, NULL); + } else { + return NULL; + } + + char input[KEYLENGTH]; + int i = 0; + + SECItem wrappedKeyItem = { siBuffer, NULL , 0}; + SECItem noParams = { siBuffer, NULL, 0 }; + SECStatus wrapStatus = SECFailure; + + + char *keyNameChars=NULL; + char *tokenNameChars=NULL; + PK11SlotInfo *slot = NULL; + PK11SlotInfo *internal = PK11_GetInternalKeySlot(); + + PK11SymKey *symkey = NULL; + PK11SymKey *transportKey = NULL; + PK11SymKey *masterKey = NULL; + + PK11SymKey *macSymKey = NULL; + PK11SymKey *symkey16 = NULL; + PK11SymKey *macKey = NULL; + + + BYTE macData[KEYLENGTH]; + char keyname[KEYNAMELENGTH]; + + + /* Derive vars */ + + CK_ULONG bitPosition = 0; + SECItem paramsItem = { siBuffer, NULL, 0 }; + + /* Java object return vars */ + + jbyteArray handleBA=NULL; + jbyte *handleBytes=NULL; + + jbyte * cuidValue = NULL; + + jbyte *cc = NULL; + int cc_len = 0; + + int hc_len = 0; + jbyte *hc = NULL; + + jbyte * keyVersion = NULL; + int keyVersion_len = 0; + + Buffer macBuff( ( BYTE *) mac_key , KEYLENGTH ); + + char *keySetStringChars = NULL; + if( keySet != NULL ) { + keySetStringChars = (char *) (env)->GetStringUTFChars( keySet, NULL); + } + + char *keySetString = keySetStringChars; + + if ( keySetString == NULL ) { + keySetString = (char *) DEFKEYSET_NAME; + } + + char *sharedSecretKeyNameChars = NULL; + + if( sharedSecretKeyName != NULL ) { + sharedSecretKeyNameChars = (char *) (env)->GetStringUTFChars( sharedSecretKeyName, NULL); + } + + char *sharedSecretKeyNameString = sharedSecretKeyNameChars; + + if ( sharedSecretKeyNameString == NULL ) { + sharedSecretKeyNameString = (char *) TRANSPORT_KEY_NAME; + } + + GetSharedSecretKeyName(sharedSecretKeyNameString); + + if( card_challenge != NULL) { + cc = (jbyte*)(env)->GetByteArrayElements( card_challenge, NULL); + cc_len = (env)->GetArrayLength(card_challenge); + } + + if( cc == NULL) { + goto done; + } + + if( host_challenge != NULL) { + hc = (jbyte*)(env)->GetByteArrayElements( host_challenge, NULL); + hc_len = (env)->GetArrayLength( host_challenge); + } + + if( hc == NULL) { + goto done; + } + + if( keyInfo != NULL) { + keyVersion = (jbyte*)(env)->GetByteArrayElements( keyInfo, NULL); + + if( keyVersion) { + keyVersion_len = (env)->GetArrayLength(keyInfo); + } + } + + if( !keyVersion || (keyVersion_len < 2) ){ + goto done; + } + + if ( CUID != NULL ) { + cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL); + } + + if( cuidValue == NULL) { + goto done; + } + + /* copy card and host challenge into input buffer */ + for (i = 0; i < 8; i++) + { + input[i] = cc[i]; + } + for (i = 0; i < 8; i++) + { + input[8+i] = hc[i]; + } + + GetDiversificationData(cuidValue,macData,mac);//keytype is mac + + if(tokenName) + { + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + slot = ReturnSlot(tokenNameChars); + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + + if(keyName) + { + keyNameChars = (char *)(env)->GetStringUTFChars(keyName, NULL); + strncpy(keyname,keyNameChars,KEYNAMELENGTH); + (env)->ReleaseStringUTFChars(keyName, (const char *)keyNameChars); + }else + GetKeyName(keyVersion,keyname); + + PR_fprintf(PR_STDOUT,"In SessionKey.ComputeSessionKey! \n"); + + if ( (keyVersion[0] == 0x1 && keyVersion[1]== 0x1 && strcmp( keyname, "#01#01") == 0) || + (keyVersion[0] == -1 && strstr(keyname, "#FF"))) + + { + /* default manufacturers key */ + + macSymKey = ReturnDeveloperSymKey(slot, (char *) "mac" , keySetString, macBuff); + + if( macSymKey == NULL ) { + goto done; + } + + symkey = DeriveKey( //Util::DeriveKey( + macSymKey, Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len)); + + }else + { + masterKey = ReturnSymKey( slot,keyname); + if(masterKey == NULL) + { + goto done; + } + + macKey =ComputeCardKeyOnToken(masterKey,macData); + if(macKey == NULL) + { + goto done; + } + + symkey = DeriveKey(macKey, Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len)); + + if(symkey == NULL) + { + goto done; + } + } + //Now wrap the key for the trip back to TPS with shared secret transport key + + symkey16 = NULL; + transportKey = ReturnSymKey( internal, GetSharedSecretKeyName(NULL)); + if ( transportKey == NULL ) { + PR_fprintf(PR_STDERR, "Can't find shared secret transport key! \n"); + goto done; + } + + handleBA = (env)->NewByteArray( KEYLENGTH); + handleBytes = (env)->GetByteArrayElements(handleBA, NULL); + + paramsItem.data = (CK_BYTE *) &bitPosition; + paramsItem.len = sizeof bitPosition; + + symkey16 = PK11_Derive(symkey, CKM_EXTRACT_KEY_FROM_KEY, ¶msItem, CKA_ENCRYPT, + CKA_DERIVE, 16); + if ( !symkey16 ) { + PR_fprintf(PR_STDERR,"Can't derive 16 byte key from 24 byte symkey! \n"); + goto done; + } + + wrappedKeyItem.data = (unsigned char *) handleBytes; + wrappedKeyItem.len = KEYLENGTH; + wrapStatus = PK11_WrapSymKey(CKM_DES3_ECB,&noParams, transportKey, symkey16, &wrappedKeyItem); + + if(wrapStatus == SECFailure ) + { + PR_fprintf(PR_STDERR, "Can't wrap session key! Error: %d \n", PR_GetError()); + } + +done: + + if( slot) { + PK11_FreeSlot(slot); + slot = NULL; + } + + if( internal ) { + PK11_FreeSlot(internal); + internal = NULL; + } + + if ( symkey ) { + PK11_FreeSymKey( symkey); + symkey = NULL; + } + + if ( transportKey ) { + PK11_FreeSymKey( transportKey ); + transportKey = NULL; + } + + if ( symkey16 ) { + PK11_FreeSymKey( symkey16 ); + symkey16 = NULL; + } + + if( masterKey ) { + PK11_FreeSymKey( masterKey); + masterKey = NULL; + } + + if( macKey ) { + PK11_FreeSymKey( macKey); + macKey = NULL; + } + + if( macSymKey ) { + PK11_FreeSymKey( macSymKey ); + macSymKey = NULL; + } + + if( keySetStringChars ) { + (env)->ReleaseStringUTFChars(keySet, (const char *)keySetStringChars); + keySetStringChars = NULL; + } + + if( sharedSecretKeyNameChars ) { + (env)->ReleaseStringUTFChars(sharedSecretKeyName, (const char *)sharedSecretKeyNameChars); + sharedSecretKeyNameChars = NULL; + } + + if ( handleBA != NULL) { + (env)->ReleaseByteArrayElements( handleBA, handleBytes, 0); + } + + if ( cc != NULL) { + (env)->ReleaseByteArrayElements(card_challenge, cc, JNI_ABORT); + } + + if ( hc != NULL) { + (env)->ReleaseByteArrayElements(host_challenge, hc, JNI_ABORT); + } + + if( keyVersion != NULL) { + (env)->ReleaseByteArrayElements(keyInfo, keyVersion, JNI_ABORT); + } + + if ( cuidValue != NULL) { + (env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT); + } + + if( mac_key != NULL) { + (env)->ReleaseByteArrayElements(macKeyArray, mac_key, JNI_ABORT); + } + + return handleBA; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: ComputeEncSessionKey + * Signature: ([B[B[B[B)[B + */ + JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeEncSessionKey + (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring); +#ifdef __cplusplus +} +#endif +#define KEYLENGTH 16 +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeEncSessionKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, jbyteArray encKeyArray, jstring useSoftToken_s, jstring keySet) +{ + /* hardcoded permanent enc key */ + jbyte *enc_key = NULL; + if(encKeyArray != NULL ) { + enc_key = (jbyte*)(env)->GetByteArrayElements(encKeyArray, NULL); + } else { + return NULL; + } + + char input[KEYLENGTH]; + int i = 0; + + SECItem wrappedKeyItem = { siBuffer, NULL , 0}; + SECItem noParams = { siBuffer, NULL, 0 }; + SECStatus wrapStatus = SECFailure; + + char *keyNameChars = NULL; + char *tokenNameChars = NULL; + PK11SlotInfo *slot = NULL; + PK11SlotInfo *internal = PK11_GetInternalKeySlot(); + + PK11SymKey *symkey = NULL; + PK11SymKey * transportKey = NULL; + PK11SymKey *masterKey = NULL; + + PK11SymKey *encSymKey = NULL; + PK11SymKey *encKey = NULL; + PK11SymKey *symkey16 = NULL; + + BYTE encData[KEYLENGTH]; + char keyname[KEYNAMELENGTH]; + + /* Derive vars */ + CK_ULONG bitPosition = 0; + SECItem paramsItem = { siBuffer, NULL, 0 }; + + /* Java object return vars */ + + jbyteArray handleBA=NULL; + jbyte *handleBytes=NULL; + + jbyte * cuidValue = NULL; + + jbyte *cc = NULL; + int cc_len = 0; + + int hc_len = 0; + jbyte *hc = NULL; + + jbyte * keyVersion = NULL; + int keyVersion_len = 0; + + Buffer encBuff( ( BYTE *) enc_key , KEYLENGTH ); + + char *keySetStringChars = NULL; + + if( keySet != NULL ) { + keySetStringChars = (char *) (env)->GetStringUTFChars( keySet, NULL); + } + + char *keySetString = keySetStringChars; + + if ( keySetString == NULL ) { + keySetString = (char *) DEFKEYSET_NAME; + } + + if( card_challenge != NULL) { + cc = (jbyte*)(env)->GetByteArrayElements( card_challenge, NULL); + cc_len = (env)->GetArrayLength(card_challenge); + } + + if( cc == NULL) { + goto done; + } + + if( host_challenge != NULL) { + hc = (jbyte*)(env)->GetByteArrayElements( host_challenge, NULL); + hc_len = (env)->GetArrayLength( host_challenge); + } + + if( hc == NULL) { + goto done; + } + + if( keyInfo != NULL) { + keyVersion = (jbyte*)(env)->GetByteArrayElements( keyInfo, NULL); + + if( keyVersion) { + keyVersion_len = (env)->GetArrayLength(keyInfo); + } + } + + if( !keyVersion || (keyVersion_len < 2) ){ + goto done; + } + + if( CUID != NULL) { + cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL); + } + + if( cuidValue == NULL) { + goto done; + } + + /* copy card and host challenge into input buffer */ + for (i = 0; i < 8; i++) + { + input[i] = cc[i]; + } + for (i = 0; i < 8; i++) + { + input[8+i] = hc[i]; + } + + GetDiversificationData(cuidValue,encData,enc); + + if(tokenName) + { + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + slot = ReturnSlot(tokenNameChars); + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + + if(keyName) + { + keyNameChars = (char *)(env)->GetStringUTFChars(keyName, NULL); + strncpy(keyname,keyNameChars,KEYNAMELENGTH); + (env)->ReleaseStringUTFChars(keyName, (const char *)keyNameChars); + } + else { + GetKeyName(keyVersion,keyname); + } + + if ( (keyVersion[0] == 0x1 && keyVersion[1]== 0x1 &&strcmp( keyname, "#01#01") == 0) || + (keyVersion[0] == -1 && strstr(keyname, "#FF"))) + { + /* default manufacturers key */ + + encSymKey = ReturnDeveloperSymKey(slot, (char *) "auth" , keySetString, encBuff); + + if( encSymKey == NULL ) { + goto done; + } + + symkey = DeriveKey( //Util::DeriveKey( + encSymKey, Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len)); + + }else + { + masterKey = ReturnSymKey( slot,keyname); + + /* We need to use internal so that the key + * can be exported by using PK11_GetKeyData() + */ + if(masterKey == NULL) { + goto done; + } + + encKey =ComputeCardKeyOnToken(masterKey,encData); + if(encKey == NULL) { + goto done; + } + symkey = DeriveKey(encKey, Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len)); + } + + if(symkey == NULL) { + goto done; + } + + //Now wrap the key for the trip back to TPS with shared secret transport key + transportKey = ReturnSymKey( internal, GetSharedSecretKeyName(NULL)); + if ( transportKey == NULL ) { + goto done; + } + + handleBA = (env)->NewByteArray( KEYLENGTH); + handleBytes = (env)->GetByteArrayElements(handleBA, NULL); + + paramsItem.data = (CK_BYTE *) &bitPosition; + paramsItem.len = sizeof bitPosition; + + symkey16 = PK11_Derive(symkey, CKM_EXTRACT_KEY_FROM_KEY, ¶msItem, CKA_ENCRYPT, + CKA_DERIVE, KEYLENGTH); + + if ( !symkey16 ) { + PR_fprintf(PR_STDERR,"SessionKey: ComputeEncSessionKey - Can't derive 16 byte key from 24 byte symkey! \n"); + goto done; + } + + wrappedKeyItem.data = (unsigned char *) handleBytes; + wrappedKeyItem.len = KEYLENGTH; + wrapStatus = PK11_WrapSymKey(CKM_DES3_ECB,&noParams, transportKey, symkey16, &wrappedKeyItem); + + if ( wrapStatus == SECFailure ) { + PR_fprintf(PR_STDERR,"SessionKey: ComputeEncSessionKey - Can't wrap encSessionKey ! Error: %d \n", PR_GetError()); + } + +done: + + if ( slot ) { + PK11_FreeSlot ( slot ); + slot = NULL; + } + + if ( internal) { + PK11_FreeSlot( internal); + internal = NULL; + } + + if( symkey) { + PK11_FreeSymKey( symkey); + symkey = NULL; + } + + if( transportKey) { + PK11_FreeSymKey( transportKey ); + transportKey = NULL; + } + + if( masterKey) { + PK11_FreeSymKey( masterKey); + masterKey = NULL; + } + + if( symkey16) { + PK11_FreeSymKey( symkey16); + symkey16 = NULL; + } + + if ( encSymKey ) { + PK11_FreeSymKey( encSymKey); + encSymKey = NULL; + } + + if( encKey) { + PK11_FreeSymKey( encKey); + encKey = NULL; + } + + if( keySetStringChars ) { + (env)->ReleaseStringUTFChars(keySet, (const char *)keySetStringChars); + keySetStringChars = NULL; + } + + if ( handleBytes != NULL ) { + (env)->ReleaseByteArrayElements( handleBA, handleBytes, 0); + } + + if( cc != NULL ) { + (env)->ReleaseByteArrayElements(card_challenge, cc, JNI_ABORT); + } + + if( hc != NULL ) { + (env)->ReleaseByteArrayElements(host_challenge, hc, JNI_ABORT); + } + if(keyVersion != NULL ) { + (env)->ReleaseByteArrayElements(keyInfo, keyVersion, JNI_ABORT); + } + + if(cuidValue != NULL) { + (env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT); + } + + if( enc_key != NULL) { + (env)->ReleaseByteArrayElements(encKeyArray, enc_key, JNI_ABORT); + } + + return handleBA; +} + +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: ComputeKekKey + * Signature: ([B[B[B[B)[B + */ + JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_ComputeKekKey + (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring); +#ifdef __cplusplus +} +#endif +#define KEYLENGTH 16 + +extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_ComputeKekKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, jbyteArray kekKeyArray, jstring useSoftToken_s, jstring keySet) +{ + /* hardcoded permanent kek key */ + jbyte *kek_key = NULL; + if( kekKeyArray != NULL) { + kek_key = (jbyte*)(env)->GetByteArrayElements(kekKeyArray, NULL); + } else { + return NULL; + } + + Buffer kekBuff( ( BYTE *) kek_key , KEYLENGTH ); + + char *keySetStringChars = NULL; + if( keySet != NULL ) { + keySetStringChars = (char *) (env)->GetStringUTFChars( keySet, NULL); + } + + char *keySetString = keySetStringChars; + + if ( keySetString == NULL ) { + keySetString = (char *) DEFKEYSET_NAME; + } + + char input[KEYLENGTH]; + int i; + jobject keyObj = NULL; + + jbyte *cc = NULL; + jbyte *hc = NULL; + jbyte * keyVersion = NULL; + int keyVersion_len = 0; + jbyte * cuidValue = NULL; + + char *keyNameChars=NULL; + char *tokenNameChars = NULL; + PK11SlotInfo *slot = NULL; + + PK11SymKey *kekKey = NULL; + PK11SymKey *masterKey = NULL; + + BYTE kekData[KEYLENGTH]; + char keyname[KEYNAMELENGTH]; + + if( card_challenge != NULL) { + cc = (jbyte*)(env)->GetByteArrayElements( card_challenge, NULL); + } + + if( cc == NULL) { + goto done; + } + + if( host_challenge != NULL) { + hc = (jbyte*)(env)->GetByteArrayElements( host_challenge, NULL); + } + + if( hc == NULL) { + goto done; + } + + if( keyInfo != NULL) { + keyVersion = (jbyte*)(env)->GetByteArrayElements( keyInfo, NULL); + if( keyVersion) { + keyVersion_len = (env)->GetArrayLength(keyInfo); + } + } + + if( !keyVersion || (keyVersion_len < 2) ){ + goto done; + } + + if( CUID != NULL) { + cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL); + } + + if( cuidValue == NULL) { + goto done; + } + + /* copy card and host challenge into input buffer */ + for (i = 0; i < 8; i++) + { + input[i] = cc[i]; + } + for (i = 0; i < 8; i++) + { + input[8+i] = hc[i]; + } + + GetDiversificationData(cuidValue,kekData,kek);//keytype is kek + + if (tokenName) + { + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + slot = ReturnSlot(tokenNameChars); + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + + if (keyName) + { + keyNameChars = (char *)(env)->GetStringUTFChars(keyName, NULL); + strcpy(keyname,keyNameChars); + (env)->ReleaseStringUTFChars(keyName, (const char *)keyNameChars); + }else + GetKeyName(keyVersion,keyname); + + PR_fprintf(PR_STDOUT,"In SessionKey.ComputeKekKey! \n"); + + if (( keyVersion[0] == 0x1 && keyVersion[1]== 0x1 &&strcmp( keyname, "#01#01") == 0 ) || + (keyVersion[0] == -1 && strcmp(keyname, "#FF"))) + { + /* default manufacturers key */ + + kekKey = ReturnDeveloperSymKey(slot, (char *) "kek" , keySetString, kekBuff); + + } else { + masterKey = ReturnSymKey( slot,keyname); + + if(masterKey == NULL) + { + goto done; + } + + kekKey =ComputeCardKeyOnToken(masterKey,kekData); + + } + + if(kekKey == NULL) { + goto done; + } + + keyObj = JSS_PK11_wrapSymKey(env, &kekKey, NULL); + +done: + + if( keySetStringChars ) { + (env)->ReleaseStringUTFChars(keySet, (const char *)keySetStringChars); + keySetStringChars = NULL; + } + + if(masterKey) { + PK11_FreeSymKey( masterKey); + masterKey = NULL; + } + + if(kekKey) { + PK11_FreeSymKey( kekKey); + kekKey = NULL; + } + + if(slot) { + PK11_FreeSlot(slot); + slot = NULL; + } + + if (cc != NULL) { + (env)->ReleaseByteArrayElements(card_challenge, cc, JNI_ABORT); + } + + if (hc != NULL) { + (env)->ReleaseByteArrayElements(host_challenge, hc, JNI_ABORT); + } + + if( keyVersion != NULL ) { + (env)->ReleaseByteArrayElements(keyInfo, keyVersion, JNI_ABORT); + } + + if (cuidValue != NULL ) { + (env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT); + } + + return keyObj; +} + +PRStatus ComputeMAC(PK11SymKey *key, Buffer &x_input, +const Buffer &icv, Buffer &output) +{ + PRStatus rv = PR_SUCCESS; + PK11Context *context = NULL; +// NetkeyICV temp; + unsigned char result[8]; + int i; + SECStatus s; + int len; +#ifdef USE_DESMAC + CK_ULONG macLen = sizeof result; + SECItem params = { siBuffer, (unsigned char *)&macLen, sizeof macLen }; +#endif + static SECItem noParams = { siBuffer, NULL, 0 }; + static unsigned char macPad[] = + { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + BYTE *input = (BYTE *) x_input; + int inputLen = x_input.size(); + + if(key == NULL) + { + rv = PR_FAILURE; goto done; + } + +#ifdef USE_DESMAC + context = PK11_CreateContextBySymKey(CKM_DES3_MAC_GENERAL, CKA_SIGN, + key, ¶ms); + if (!context) { rv = PR_FAILURE; goto done; } + + s = PK11_DigestBegin(context); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + s = PK11_DigestOp(context, icv, 8); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + while(inputLen >= 8) + { + s = PK11_DigestOp(context, input, 8); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + input += 8; + inputLen -= 8; + } + + for (i = 0;i < inputLen;i++) + { + result[i] = input[i]; + } + + input = macPad; + for(;i < 8;i++) + { + result[i] = *input++; + } + + s = PK11_DigestOp(context, result, sizeof result); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + s = PK11_DigestFinal(context, output, (unsigned int *)&len, sizeof output); + if (1 != SECSuccess) { rv = PR_FAILURE; goto done; } + +#else + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, key, &noParams); + if (!context) { rv = PR_FAILURE; goto done; } + + memcpy(result, icv, sizeof result); + + /* Process whole blocks */ + while (inputLen >= 8) + { + for(i = 0;i < 8;i++) + { + result[i] ^= input[i]; + } + + s = PK11_CipherOp(context, result, &len, sizeof result, result, sizeof result); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + if (len != sizeof result) /* assert? */ + { +//PR_SetError(PR_UNKNOWN_ERROR, 0); + rv = PR_FAILURE; + goto done; + } + + input += 8; + inputLen -= 8; + } + +/* + * Fold in remaining data (if any) + * Set i to number of bytes processed + */ + for(i = 0;i < inputLen;i++) + { + result[i] ^= input[i]; + } + + /* + * Fill remainder of last block. There + * will be at least one byte handled here. + */ + input = macPad; + while(i < 8) + { + result[i] ^= *input++; + i++; + } + + s = PK11_CipherOp(context, result, &len, sizeof result, result, sizeof result); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + if (len != sizeof result) + { +//PR_SetError(PR_UNKNOWN_ERROR, 0); + rv = PR_FAILURE; + goto done; + } + + output.replace(0, result, sizeof result); +#endif + + done: + if (context) + { + PK11_Finalize(context); + PK11_DestroyContext(context, PR_TRUE); + } + memset(result, 0, sizeof result); + + return rv; +} /* ComputeMAC */ + + +//================================================================================= +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: ComputeCryptogram + * Signature: ([B[B[B[B)[B + */ + JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeCryptogram + (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, int, jbyteArray, jstring, jstring); +#ifdef __cplusplus +} +#endif +#define KEYLENGTH 16 +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeCryptogram(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, int type, jbyteArray authKeyArray, jstring useSoftToken_s, jstring keySet) +{ +/* hardcore permanent mac key */ + jbyte *auth_key = NULL; + if( authKeyArray != NULL) { + auth_key = (jbyte*)(env)->GetByteArrayElements(authKeyArray, NULL); + } else { + return NULL; + } + + Buffer authBuff( ( BYTE *) auth_key , KEYLENGTH ); + Buffer icv = Buffer(EIGHT_BYTES, (BYTE)0); + Buffer output = Buffer(EIGHT_BYTES, (BYTE)0); + + char *keySetStringChars = NULL; + if( keySet != NULL ) { + keySetStringChars = (char *) (env)->GetStringUTFChars( keySet, NULL); + } + + char *keySetString = keySetStringChars; + + if ( keySetString == NULL ) { + keySetString = (char *) DEFKEYSET_NAME; + } + + char input[KEYLENGTH]; + int i; + + PR_fprintf(PR_STDOUT,"In SessionKey: ComputeCryptogram! \n"); + jbyteArray handleBA=NULL; + jbyte *handleBytes=NULL; + + jbyte *cc = NULL; + jbyte *hc = NULL; + int cc_len = 0; + int hc_len = 0; + jbyte * keyVersion = NULL; + int keyVersion_len = 0; + jbyte * cuidValue = NULL; + + char *tokenNameChars = NULL; + char *keyNameChars=NULL; + PK11SlotInfo *slot = NULL; + + jbyte * session_key = NULL; + PK11SymKey *symkey = NULL; + PK11SymKey *masterKey = NULL; + PK11SymKey *authKey = NULL; + PK11SymKey *authSymKey = NULL; + + BYTE authData[KEYLENGTH]; + char keyname[KEYNAMELENGTH]; + Buffer input_x = Buffer(KEYLENGTH); + + if( card_challenge != NULL ) { + cc = (jbyte*)(env)->GetByteArrayElements( card_challenge, NULL); + cc_len = (env)->GetArrayLength(card_challenge); + } + + if( cc == NULL) { + goto done; + } + + if( host_challenge != NULL ) { + hc = (jbyte*)(env)->GetByteArrayElements( host_challenge, NULL); + hc_len = (env)->GetArrayLength( host_challenge); + } + + if( hc == NULL) { + goto done; + } + + if( keyInfo != NULL) { + keyVersion = (jbyte*)(env)->GetByteArrayElements( keyInfo, NULL); + if( keyVersion) { + keyVersion_len = (env)->GetArrayLength(keyInfo); + } + } + + if( !keyVersion || (keyVersion_len < 2) ){ + goto done; + } + + if( CUID != NULL) { + cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL); + } + + if( cuidValue == NULL) { + goto done; + } + + if (type == 0) // compute host cryptogram + { + /* copy card and host challenge into input buffer */ + for (i = 0; i < EIGHT_BYTES; i++) + { + input[i] = cc[i]; + } + for (i = 0; i < EIGHT_BYTES; i++) + { + input[EIGHT_BYTES +i] = hc[i]; + } + } // compute card cryptogram + else if (type == 1) + { + for (i = 0; i < EIGHT_BYTES; i++) + { + input[i] = hc[i]; + } + for (i = 0; i < EIGHT_BYTES; i++) + { + input[EIGHT_BYTES+i] = cc[i]; + } + } + + input_x.replace(0, (BYTE*) input, KEYLENGTH); + + GetDiversificationData(cuidValue,authData,enc); + + if (tokenName) + { + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + slot = ReturnSlot(tokenNameChars); + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + + if (keyName) + { + keyNameChars = (char *)(env)->GetStringUTFChars(keyName, NULL); + strcpy(keyname,keyNameChars); + (env)->ReleaseStringUTFChars(keyName, (const char *)keyNameChars); + }else + GetKeyName(keyVersion,keyname); + + if ( (keyVersion[0] == 0x1 && keyVersion[1]== 0x1 &&strcmp( keyname, "#01#01") == 0 ) || + (keyVersion[0] == -1 && strstr(keyname, "#FF"))) + { + + /* default manufacturers key */ + + authSymKey = ReturnDeveloperSymKey(slot, (char *) "auth" , keySetString, authBuff); + if( authSymKey == NULL ) { + goto done; + } + + symkey = DeriveKey( + authSymKey, Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len)); + } + else + { + masterKey = ReturnSymKey( slot,keyname); + if (masterKey == NULL) + { + goto done; + } + + authKey = ComputeCardKeyOnToken(masterKey,authData); + if (authKey == NULL) + { + goto done; + } + + symkey = DeriveKey(authKey, + Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len)); + + } + + ComputeMAC(symkey, input_x, icv, output); + session_key = (jbyte *) (BYTE*)output; + + handleBA = (env)->NewByteArray( EIGHT_BYTES); + handleBytes = (env)->GetByteArrayElements(handleBA, NULL); + if( handleBytes ) { + memcpy(handleBytes, session_key, EIGHT_BYTES); + } + +done: + + if( slot ) { + PK11_FreeSlot( slot ); + slot = NULL; + } + + if( symkey ) { + PK11_FreeSymKey( symkey ); + symkey = NULL; + } + + if( authSymKey ) { + PK11_FreeSymKey( authSymKey ); + authSymKey = NULL; + } + + if( authKey) { + PK11_FreeSymKey( authKey); + authKey = NULL; + } + + if( masterKey) { + PK11_FreeSymKey( masterKey); + masterKey = NULL; + } + + if( keySetStringChars ) { + (env)->ReleaseStringUTFChars(keySet, (const char *)keySetStringChars); + keySetStringChars = NULL; + } + + if( handleBytes != NULL) { + (env)->ReleaseByteArrayElements( handleBA, handleBytes, 0); + } + + if( cc != NULL) { + (env)->ReleaseByteArrayElements(card_challenge, cc, JNI_ABORT); + } + + if( hc != NULL) { + (env)->ReleaseByteArrayElements(host_challenge, hc, JNI_ABORT); + } + + if( keyVersion != NULL) { + (env)->ReleaseByteArrayElements(keyInfo, keyVersion, JNI_ABORT); + } + + if( cuidValue != NULL) { + (env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT); + } + + return handleBA; +} + + +//================================================================================= + +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_ECBencrypt + * Method: ECBencrypt + * Signature: ([B[B[B[B)[B + */ + JNIEXPORT jbyteArray JNICALL + Java_com_netscape_symkey_SessionKey_ECBencrypt + (JNIEnv*, jclass, jobject, jobject); +#ifdef __cplusplus +} +#endif +extern "C" JNIEXPORT jbyteArray JNICALL +Java_com_netscape_symkey_SessionKey_ECBencrypt +(JNIEnv* env, jclass this2, jobject symkeyObj, jobject deskeyObj ) +{ + jbyteArray handleBA=NULL; + jint dlen=KEYLENGTH; // applet only supports 16 bytes + jbyte *handleBytes=NULL; + + PK11SymKey *symkey = NULL; + PK11SymKey *deskey = NULL; + PK11SymKey *newdeskey = NULL; + PRStatus r = PR_FAILURE; + static SECItem noParams = { siBuffer, NULL, 0 }; + SECItem wrappedKeyItem = { siBuffer, NULL, 0 }; + SECStatus wrapStatus = SECFailure; + + /* PK11_Derive vars. */ + + SECItem paramsItem = { siBuffer, NULL, 0 }; + CK_ULONG bitPosition = 0; + + PR_fprintf(PR_STDOUT,"In SessionKey: ECBencrypt! \n"); + + if( !symkeyObj || !deskeyObj) { + goto finish; + } + + r = JSS_PK11_getSymKeyPtr(env, symkeyObj, &symkey); + if (r != PR_SUCCESS) { + goto finish; + } + + r = JSS_PK11_getSymKeyPtr(env, deskeyObj, &deskey); + if (r != PR_SUCCESS) { + goto finish; + } + // Instead of playing with raw keys, let's derive the 16 byte des2 key from + // the 24 byte des2 key. + + bitPosition = 0; + paramsItem.data = (CK_BYTE *) &bitPosition; + paramsItem.len = sizeof bitPosition; + + newdeskey = PK11_Derive(deskey, CKM_EXTRACT_KEY_FROM_KEY, ¶msItem, CKA_ENCRYPT, + CKA_DERIVE, 16); + + if ( ! newdeskey ) { + goto finish; + } + + dlen = KEYLENGTH; // applet suports only 16 bytes + + handleBA = (env)->NewByteArray(dlen); + if(handleBA == NULL ) + { + goto finish; + } + handleBytes = (jbyte *)(env)->GetByteArrayElements(handleBA, NULL); + + if(handleBytes==NULL) + { + goto finish; + } + + //Wrap the new 16 bit key with the input symkey. + + wrappedKeyItem.data = (unsigned char *) handleBytes; + wrappedKeyItem.len = dlen; + wrapStatus = PK11_WrapSymKey(CKM_DES3_ECB,&noParams, symkey, newdeskey, &wrappedKeyItem); + + if( wrapStatus == SECSuccess) { + PR_fprintf(PR_STDERR, "ECBencrypt wrapStatus %d wrappedKeySize %d \n", wrapStatus, wrappedKeyItem.len); + } else { + PR_fprintf(PR_STDERR, "ECBecrypt wrap failed! Error %d \n", PR_GetError()); + } + +finish: + + if( handleBytes != NULL) { + (env)->ReleaseByteArrayElements( handleBA, handleBytes, 0); + } + + if ( newdeskey ) { + PK11_FreeSymKey( newdeskey ); + newdeskey = NULL; + } + + return handleBA; +} + + +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_GenerateSymkey + * Method: GenerateSymkey + * Signature: ([B[B[B[B)[B + */ + JNIEXPORT jobject JNICALL + Java_com_netscape_symkey_SessionKey_GenerateSymkey + (JNIEnv*, jclass, jstring); +#ifdef __cplusplus +} +#endif +extern "C" JNIEXPORT jobject JNICALL +Java_com_netscape_symkey_SessionKey_GenerateSymkey +(JNIEnv* env, jclass this2, jstring tokenName) +{ + jobject keyObj = NULL; + PK11SymKey *okey = NULL; + PK11SymKey *okeyFirstEight = NULL; + PK11SymKey *concatKey = NULL; + PK11SymKey *finalKey = NULL; + + char *tokenNameChars = NULL; + PK11SlotInfo *slot = NULL; + CK_ULONG bitPosition = 0; + SECItem paramsItem = { siBuffer, NULL, 0 }; + CK_OBJECT_HANDLE keyhandle = 0; + + PR_fprintf(PR_STDOUT,"In SessionKey GenerateSymkey!\n"); + if (tokenName) + { + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + if ( tokenNameChars && !strcmp(tokenNameChars, "internal")) { + slot = PK11_GetInternalSlot(); + } else { + slot = ReturnSlot(tokenNameChars); + } + + PR_fprintf(PR_STDOUT,"SessinKey: GenerateSymkey slot %p name %s tokenName %s \n",slot, PK11_GetSlotName(slot), PK11_GetTokenName(slot)); + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + + //Generate original 16 byte DES2 key + okey = PK11_TokenKeyGen(slot, CKM_DES2_KEY_GEN,0, 0, 0, PR_FALSE, NULL); + + if (okey == NULL) { + goto finish; + } + + // Extract first eight bytes from generated key into another key. + bitPosition = 0; + paramsItem.data = (CK_BYTE *) &bitPosition; + paramsItem.len = sizeof bitPosition; + + okeyFirstEight = PK11_Derive(okey, CKM_EXTRACT_KEY_FROM_KEY, ¶msItem, CKA_ENCRYPT , CKA_DERIVE, 8); + if (okeyFirstEight == NULL ) { + goto finish; + } + + //Concatenate 8 byte key to the end of the original key, giving new 24 byte key + keyhandle = PK11_GetSymKeyHandle(okeyFirstEight); + paramsItem.data=(unsigned char *) &keyhandle; + paramsItem.len=sizeof(keyhandle); + + concatKey = PK11_Derive ( okey , CKM_CONCATENATE_BASE_AND_KEY , ¶msItem ,CKM_DES3_ECB , CKA_DERIVE , 0); + if ( concatKey == NULL ) { + goto finish; + } + + //Make sure we move this to the orig token, in case it got moved by NSS + //during the derive phase. + + finalKey = PK11_MoveSymKey ( slot, CKA_ENCRYPT, 0, PR_FALSE, concatKey); + + /* wrap the symkey in java object. This sets symkey to NULL. */ + keyObj = JSS_PK11_wrapSymKey(env, &finalKey, NULL); + +finish: + if ( slot != NULL) { + PK11_FreeSlot(slot); + slot = NULL; + } + + if ( okey != NULL) { + PK11_FreeSymKey(okey); + okey = NULL; + } + + if ( okeyFirstEight != NULL) { + PK11_FreeSymKey(okeyFirstEight); + okeyFirstEight = NULL; + } + + if ( concatKey != NULL) { + PK11_FreeSymKey(concatKey); + concatKey = NULL; + } + + if ( finalKey != NULL) { + PK11_FreeSymKey(finalKey); + finalKey = NULL; + } + + return keyObj; +} + +// begin DRM proto + +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: bytes2PK11SymKey + * Signature: + */ + JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_bytes2PK11SymKey + (JNIEnv *, jclass, jbyteArray); +#ifdef __cplusplus +} +#endif + +#ifdef DRM_SUPPORT_DEBUG +extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_bytes2PK11SymKey(JNIEnv * env, jclass this2, jbyteArray symKeyBytes) +{ + PK11SlotInfo *slot=NULL; + jobject keyObj = NULL; + PK11SymKey *symKey=NULL; + +// how about do unwrap (decrypt of the symkey in here?? + +// DRM proto just use internal slot + slot = PK11_GetInternalKeySlot(); + + BYTE masterKeyData[24]; + SECItem masterKeyItem = {siBuffer, masterKeyData, sizeof(masterKeyData)}; + + memcpy(masterKeyData, (char*)symKeyBytes, 16); + memcpy(masterKeyData+16, (char*)symKeyBytes, 8); + + // ToDo: possibly get rid of whole function, not used + // For now , no need to get rid of PK11_ImportSymKeyWithFlags call. + + symKey = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, + PK11_OriginUnwrap, CKA_ENCRYPT, &masterKeyItem, + ALL_SYMKEY_OPS /*CKF_ENCRYPT*/, PR_FALSE, 0); + + /* wrap the symkey in java object. This sets symkey to NULL. */ + keyObj = JSS_PK11_wrapSymKey(env, &symKey, debug_fd); + +finish: + return keyObj; +} + + +// end DRM proto +#endif // DRM_SUPPORT_DEBUG diff --git a/base/symkey/src/com/netscape/symkey/SessionKey.java b/base/symkey/src/com/netscape/symkey/SessionKey.java new file mode 100644 index 000000000..47f9385f7 --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/SessionKey.java @@ -0,0 +1,167 @@ +// --- 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +package com.netscape.symkey; + +import org.mozilla.jss.pkcs11.PK11SymKey; + +/** + * This object contains the OS independent interfaces. + */ +public class SessionKey { + static boolean tryLoad(String filename) { + try { + System.load(filename); + } catch (Exception e) { + return false; + } catch (UnsatisfiedLinkError e) { + return false; + } + + return true; + } + + // Load native library + static { + boolean mNativeLibrariesLoaded = false; + String os = System.getProperty("os.name"); + if ((os.equals("Linux"))) { + // Check for 64-bit library availability + // prior to 32-bit library availability. + mNativeLibrariesLoaded = + tryLoad("/usr/lib64/symkey/libsymkey.so"); + if (mNativeLibrariesLoaded) { + System.out.println("64-bit symkey library loaded"); + } else { + // REMINDER: May be trying to run a 32-bit app + // on 64-bit platform. + mNativeLibrariesLoaded = + tryLoad("/usr/lib/symkey/libsymkey.so"); + if (mNativeLibrariesLoaded) { + System.out.println("32-bit symkey library loaded"); + } else { + System.out.println("FAILED loading symkey library!"); + System.exit(-1); + } + } + } else { + try { + System.loadLibrary("symkey"); + System.out.println("symkey library loaded"); + mNativeLibrariesLoaded = true; + } catch (Throwable t) { + // This is bad news, the program is doomed at this point + t.printStackTrace(); + } + } + } + + // external calls from RA + public static native byte[] ComputeKeyCheck(PK11SymKey desKey); /* byte data[] ); */ + + public static native byte[] ComputeSessionKey(String tokenName, + String keyName, + byte[] card_challenge, + byte[] host_challenge, + byte[] keyInfo, + byte[] CUID, + byte[] macKeyArray, + String useSoftToken, + String keySet, + String sharedSecretKeyName); + + public static native byte[] ComputeEncSessionKey(String tokenName, + String keyName, + byte[] card_challenge, + byte[] host_challenge, + byte[] keyInfo, + byte[] CUID, + byte[] encKeyArray, + String useSoftToken, + String keySet); + + public static native PK11SymKey ComputeKekSessionKey(String tokenName, + String keyName, + byte[] card_challenge, + byte[] host_challenge, + byte[] keyInfo, + byte[] CUID, + byte[] kekKeyArray, + String useSoftToken, + String keySet); + + public static native PK11SymKey ComputeKekKey(String tokenName, + String keyName, + byte[] card_challenge, + byte[] host_challenge, + byte[] keyInfo, + byte[] CUID, + byte[] kekKeyArray, + String useSoftToken, String keySet); + + public static native byte[] ECBencrypt(PK11SymKey key, + PK11SymKey desKey); //byte[] data ); + + public static native PK11SymKey GenerateSymkey(String tokenName); + + /* + * DRM_SUPPORT_DEBUG + */ + + // public static native PK11SymKey bytes2PK11SymKey( byte[] symKeyBytes ); + + public static native byte[] ComputeCryptogram(String tokenName, + String keyName, + byte[] card_challenge, + byte[] host_challenge, + byte[] keyInfo, + byte[] CUID, + int type, + byte[] authKeyArray, + String useSoftToken, String keySet); + + public static native byte[] EncryptData(String tokenName, + String keyName, + byte[] in, + byte[] keyInfo, + byte[] CUID, + byte[] kekKeyArray, + String useSoftToken, String keySet); + + public static native byte[] DiversifyKey(String tokenName, + String newTokenName, + String oldMasterKeyName, + String newMasterKeyName, + String keyInfo, + byte[] CUIDValue, + byte[] kekKeyArray, + String useSoftToken, String keySet); + + // internal calls from config TKS keys tab + public static native String GenMasterKey(String token, + String keyName); + + public static native String DeleteSymmetricKey(String token, + String keyName); + + public static native String ListSymmetricKeys(String token); + + // set when called from the config TKS tab to create master key + // get when called from the RA to create session key + public static native void SetDefaultPrefix(String masterPrefix); +} diff --git a/base/symkey/src/com/netscape/symkey/SymKey.cpp b/base/symkey/src/com/netscape/symkey/SymKey.cpp new file mode 100644 index 000000000..c300d1ada --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/SymKey.cpp @@ -0,0 +1,1407 @@ +// --- 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +#if defined(WIN32) +#include "fcntl.h" +#include "io.h" +#endif + +#if defined(XP_UNIX) +#include +#include +#include +#endif + +#if defined(XP_WIN) || defined (XP_PC) +#include +#include +#endif + +#include "nspr.h" +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" +#include "pk11func.h" +#include "secasn1.h" +#include "cert.h" +#include "cryptohi.h" +#include "secoid.h" +#include "certdb.h" +#include "nss.h" + +#include "nspr.h" +#ifdef __cplusplus +#include +#include +#include + +} +#endif +#include +#include +#include +#include +#include + +#include "Buffer.h" +#include "SymKey.h" + +typedef unsigned char BYTE; + +typedef struct +{ + enum + { + PW_NONE = 0, + PW_FROMFILE = 1, + PW_PLAINTEXT = 2, + PW_EXTERNAL = 3 + } source; + char *data; +} secuPWData; + +char masterKeyPrefix[PREFIXLENGHT]; +char masterKeyNickName[KEYNAMELENGTH]; +char masterNewKeyNickName[KEYNAMELENGTH]; +char sharedSecretSymKeyName[KEYNAMELENGTH] = { 0 }; + +//================================================================================= +#ifdef __cplusplus +extern "C" +{ +#endif +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: ListSymmetricKeys + * Signature: (Ljava/lang/String;)Ljava/lang/String; + */ + JNIEXPORT jstring JNICALL Java_com_netscape_symkey_SessionKey_ListSymmetricKeys + (JNIEnv *, jclass, jstring); + +#ifdef __cplusplus +} +#endif + +PK11SlotInfo *ReturnSlot(char *tokenNameChars) +{ + if( tokenNameChars == NULL) + { + return NULL; + } + PK11SlotInfo *slot=NULL; + + if(!strcmp( tokenNameChars, "internal" ) || !strcmp( tokenNameChars, "Internal Key Storage Token")) + { + slot = PK11_GetInternalKeySlot(); + } + else + { + slot = PK11_FindSlotByName( tokenNameChars ); + } + return slot; +} + + +/* Find the Symmetric key with the given nickname + Returns null if the key could not be found + Steve wrote this code to replace the old impl */ + +PK11SymKey * ReturnSymKey( PK11SlotInfo *slot, char *keyname) +{ + char *name = NULL; + PK11SymKey *foundSymKey= NULL; + PK11SymKey *firstSymKey= NULL; + PK11SymKey *sk = NULL; + PK11SymKey *nextSymKey = NULL; + secuPWData pwdata; + + pwdata.source = secuPWData::PW_NONE; + pwdata.data = (char *) NULL; + PR_fprintf(PR_STDOUT,"In ReturnSymKey name %s \n",keyname); + if (keyname == NULL) + { + goto cleanup; + } + if (slot== NULL) + { + goto cleanup; + } + /* Initialize the symmetric key list. */ + firstSymKey = PK11_ListFixedKeysInSlot( slot , NULL, ( void *) &pwdata ); + /* scan through the symmetric key list for a key matching our nickname */ + sk = firstSymKey; + while( sk != NULL ) + { + /* get the nickname of this symkey */ + name = PK11_GetSymKeyNickname( sk ); + + /* if the name matches, make a 'copy' of it */ + if ( name != NULL && !strcmp( keyname, name )) + { + if (foundSymKey == NULL) + { + foundSymKey = PK11_ReferenceSymKey(sk); + } + PORT_Free(name); + } + + sk = PK11_GetNextSymKey( sk ); + } + + /* We're done with the list now, let's free all the keys in it + It's okay to free our key, because we made a copy of it */ + + sk = firstSymKey; + while( sk != NULL ) + { + nextSymKey = PK11_GetNextSymKey(sk); + PK11_FreeSymKey(sk); + sk = nextSymKey; + } + + cleanup: + return foundSymKey; +} + + +extern "C" JNIEXPORT jstring +JNICALL Java_com_netscape_symkey_SessionKey_DeleteKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName) + +{ + char *tokenNameChars; + char *keyNameChars; + int count = 0; + int keys_deleted = 0; + PK11SymKey *symKey = NULL; + PK11SymKey *nextSymKey = NULL; + PK11SlotInfo *slot = NULL; + SECStatus rv; + secuPWData pwdata; + pwdata.source = secuPWData::PW_NONE; + pwdata.data = (char *) NULL; + jstring retval = NULL; + + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + keyNameChars = (char *)(env)->GetStringUTFChars(keyName, NULL); + char *result= (char *)malloc(1); + + result[0] = '\0'; + if( tokenNameChars == NULL || keyNameChars==NULL) + { + goto finish; + } + if(strcmp( tokenNameChars, "internal" ) == 0 ) + { + slot = PK11_GetInternalKeySlot(); + } + else if( tokenNameChars != NULL ) + { + slot = PK11_FindSlotByName( tokenNameChars ); + } + /* Initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( slot , NULL, ( void *) &pwdata ); + + /* Iterate through the symmetric key list. */ + while( symKey != NULL ) + { + char *name = NULL; + rv = SECFailure; + name = PK11_GetSymKeyNickname( symKey ); + + if( strcmp( keyNameChars, name ) == 0 ) + { + rv = PK11_DeleteTokenSymKey( symKey ); + } + PORT_Free(name); + + if( rv != SECFailure ) + { + keys_deleted++; + } + + nextSymKey = PK11_GetNextSymKey( symKey ); + PK11_FreeSymKey( symKey ); + symKey = nextSymKey; + + count++; + } + + if( keys_deleted == 0 ) + { + + rv = SECFailure; + } + else + { + + rv = SECSuccess; + } + + finish: + if (slot) + { + PK11_FreeSlot(slot); + } + if(tokenNameChars) + { + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + if(keyNameChars) + { + (env)->ReleaseStringUTFChars(keyName, (const char *)keyNameChars); + } + retval = (env)->NewStringUTF( result); + free(result); + return retval; +} + + +#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ +(x)->pValue=(v); (x)->ulValueLen = (l); + +extern "C" JNIEXPORT jstring +JNICALL Java_com_netscape_symkey_SessionKey_ListSymmetricKeys(JNIEnv * env, jclass this2, jstring tokenName) +{ + char *tokenNameChars; + jstring retval = NULL; + PK11SymKey *symKey = NULL; + PK11SymKey *nextSymKey = NULL; + secuPWData pwdata; + pwdata.source = secuPWData::PW_NONE; + pwdata.data = (char *) NULL; + PK11SlotInfo *slot = NULL; + + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + char *result= (char *)malloc(1); + result[0] = '\0'; + if( tokenNameChars == NULL ) + { + goto finish; + } + if(strcmp( tokenNameChars, "internal" ) == 0 ) + { + slot = PK11_GetInternalKeySlot(); + } + else if( tokenNameChars != NULL ) + { + slot = PK11_FindSlotByName( tokenNameChars ); + } + + /* Initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( slot , NULL, (void *)&pwdata ); + + /* Iterate through the symmetric key list. */ + while (symKey != NULL) + { + int count = 0; + char *name = NULL; + char *temp = NULL; + name = PK11_GetSymKeyNickname( symKey ); + temp = result; + result = (char*)malloc( strlen(name) + strlen(temp) + 2 ); + result[0]='\0'; + strcat(result, temp); + strcat(result, ","); + strcat(result, name); + free(temp); + + PORT_Free(name); + + nextSymKey = PK11_GetNextSymKey( symKey ); + PK11_FreeSymKey( symKey ); + symKey = nextSymKey; + + count++; + } + + finish: + if (slot) + { + PK11_FreeSlot(slot); + } + if(tokenNameChars) + { + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + retval = (env)->NewStringUTF(result); + free(result); + return retval; +} + + +/* DES KEY Parity conversion table. Takes each byte/2 as an index, returns + * that byte with the proper parity bit set */ +static const unsigned char parityTable[256] = +{ +/* Even...0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e */ + /* E */ 0x01,0x02,0x04,0x07,0x08,0x0b,0x0d,0x0e, +/* Odd....0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e */ + /* O */ 0x10,0x13,0x15,0x16,0x19,0x1a,0x1c,0x1f, +/* Odd....0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e */ + /* O */ 0x20,0x23,0x25,0x26,0x29,0x2a,0x2c,0x2f, +/* Even...0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e */ + /* E */ 0x31,0x32,0x34,0x37,0x38,0x3b,0x3d,0x3e, +/* Odd....0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e */ + /* O */ 0x40,0x43,0x45,0x46,0x49,0x4a,0x4c,0x4f, +/* Even...0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e */ + /* E */ 0x51,0x52,0x54,0x57,0x58,0x5b,0x5d,0x5e, +/* Even...0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e */ + /* E */ 0x61,0x62,0x64,0x67,0x68,0x6b,0x6d,0x6e, +/* Odd....0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e */ + /* O */ 0x70,0x73,0x75,0x76,0x79,0x7a,0x7c,0x7f, +/* Odd....0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e */ + /* O */ 0x80,0x83,0x85,0x86,0x89,0x8a,0x8c,0x8f, +/* Even...0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e */ + /* E */ 0x91,0x92,0x94,0x97,0x98,0x9b,0x9d,0x9e, +/* Even...0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae */ + /* E */ 0xa1,0xa2,0xa4,0xa7,0xa8,0xab,0xad,0xae, +/* Odd....0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe */ + /* O */ 0xb0,0xb3,0xb5,0xb6,0xb9,0xba,0xbc,0xbf, +/* Even...0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce */ + /* E */ 0xc1,0xc2,0xc4,0xc7,0xc8,0xcb,0xcd,0xce, +/* Odd....0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde */ + /* O */ 0xd0,0xd3,0xd5,0xd6,0xd9,0xda,0xdc,0xdf, +/* Odd....0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee */ + /* O */ 0xe0,0xe3,0xe5,0xe6,0xe9,0xea,0xec,0xef, +/* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */ + /* E */ 0xf1,0xf2,0xf4,0xf7,0xf8,0xfb,0xfd,0xfe, +}; + +void +pk11_FormatDESKey(unsigned char *key, int length) +{ + int i; + + /* format the des key */ + for (i=0; i < length; i++) + { + key[i] = parityTable[key[i]>>1]; + } +} + + +static secuPWData pwdata = { secuPWData::PW_NONE, 0 }; + +/** + * Internal token is required when we are doing key diversification + * where raw key material needs to be accessed + */ +PK11SymKey *ComputeCardKeyOnSoftToken(PK11SymKey *masterKey, unsigned char *data) +{ + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PK11SymKey *key = ComputeCardKey(masterKey, data, slot); + if( slot != NULL) { + PK11_FreeSlot(slot); + slot = NULL; + } + + return key; +} + +PK11SymKey *ComputeCardKey(PK11SymKey *masterKey, unsigned char *data, PK11SlotInfo *slot) +{ + PK11SymKey *key = NULL; + PK11Context *context = NULL; + int keysize = DES3_LENGTH; + unsigned char *keyData = NULL; + SECStatus s = SECSuccess; + int i = 0; + int len = 0; + static SECItem noParams = { siBuffer, NULL, 0 }; + unsigned char *in = data; + PK11SymKey *tmpkey = NULL; + unsigned char wrappedkey[DES3_LENGTH]; + SECItem wrappeditem = { siBuffer, NULL, 0 }; + + keyData = (unsigned char*)malloc(keysize); + + for (i = 0;i < keysize; i++) + { + keyData[i] = 0x0; + } + + if (masterKey == NULL) { + PR_fprintf(PR_STDERR,"ComputeCardKey: master key is null.\n"); + goto done; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, + masterKey, + &noParams); + + if (context == NULL) { + PR_fprintf(PR_STDERR,"ComputeCardKey: failed to create context.\n"); + goto done; + } + + /* Part 1 */ + s = PK11_CipherOp(context, &keyData[0], &len, 8, in, 8); + if (s != SECSuccess) { + PR_fprintf(PR_STDERR,"ComputeCardKey: failed to encrypt #1\n"); + goto done; + } + pk11_FormatDESKey(&keyData[0], EIGHT_BYTES); /* set parity */ + + /* Part 2 */ + s = PK11_CipherOp(context, &keyData[EIGHT_BYTES], &len, EIGHT_BYTES, in+EIGHT_BYTES, EIGHT_BYTES); + if (s != SECSuccess) { + PR_fprintf(PR_STDERR,"ComputeCardKey: failed to encryp #2.\n"); + goto done; + } + pk11_FormatDESKey(&keyData[EIGHT_BYTES], EIGHT_BYTES); + + /* Part 3 */ + for(i = 0;i < EIGHT_BYTES;i++) + { + keyData[i+KEYLENGTH] = keyData[i]; + } + +#define CKF_KEY_OPERATION_FLAGS 0x000e7b00UL + + /* generate a tmp key to import the sym key */ + tmpkey = PK11_TokenKeyGenWithFlags(slot, + CKM_DES3_KEY_GEN, 0, 0, 0, + (CKF_WRAP | CKF_UNWRAP | CKF_ENCRYPT | CKF_DECRYPT) & CKF_KEY_OPERATION_FLAGS, + PR_FALSE, &pwdata); + + if (tmpkey == NULL) { + PR_fprintf(PR_STDERR,"ComputeCardKey: failed to keygen. \n"); + goto done; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, + tmpkey, + &noParams); + + if (context == NULL) { + PR_fprintf(PR_STDERR,"ComputeCardKey: failed to set context. \n"); + goto done; + } + + /* encrypt the key with the master key */ + s = PK11_CipherOp(context, wrappedkey, &len, 24, keyData, 24); + if (s != SECSuccess) + { + PR_fprintf(PR_STDERR,"ComputeCardKey: failed to encrypt #3.\n"); + goto done; + } + + wrappeditem.data = wrappedkey; + wrappeditem.len = len; + + key = PK11_UnwrapSymKeyWithFlags(tmpkey, CKM_DES3_ECB, &noParams, + &wrappeditem, CKM_DES3_KEY_GEN, CKA_DECRYPT, 24, + (CKA_ENCRYPT | CKA_DECRYPT) & CKF_KEY_OPERATION_FLAGS ); + +done: + if (keyData != NULL) + { + free(keyData); + } + if (context != NULL) + { + PK11_DestroyContext(context, PR_TRUE); + context = NULL; + } + if (tmpkey != NULL) + { + PK11_FreeSymKey(tmpkey); + tmpkey = NULL; + } + + return key; +} + +PK11SymKey * ComputeCardKeyOnToken(PK11SymKey *masterKey, BYTE* data) +{ + PK11SlotInfo *slot = PK11_GetSlotFromKey(masterKey); + PK11SymKey *key = ComputeCardKey(masterKey, data, slot); + + if( slot) { + PK11_FreeSlot(slot); + slot = NULL; + } + + return key; +} + +// Either encrypt data with a provided SymKey OR a key buffer array (for the Default keyset case). +PRStatus EncryptData(const Buffer &kek_key,PK11SymKey *cardKey, Buffer &input, Buffer &output) +{ + PRStatus rv = PR_FAILURE; + + PK11SymKey *master = NULL; + PK11SymKey *transportKey = NULL; + PK11SlotInfo *slot = NULL; + PK11Context *context = NULL; + int i = 0; + SECStatus s = SECFailure; + int len = 0; + static SECItem noParams = { siBuffer, NULL, 0 }; +#ifdef DES2_WORKAROUND + unsigned char masterKeyData[DES3_LENGTH]; +#else + unsigned char masterKeyData[KEYLENGTH]; +#endif + unsigned char result[EIGHT_BYTES]; + + slot = PK11_GetInternalKeySlot(); + + if (slot == NULL) { + goto done; + } + + if ( cardKey == NULL ) { /* Developer key set mode.*/ + transportKey = ReturnSymKey( slot, GetSharedSecretKeyName(NULL)); + + /* convert 16-byte to 24-byte triple-DES key */ + memcpy(masterKeyData, kek_key, 16); + memcpy(masterKeyData+16, kek_key, 8); + + master = CreateUnWrappedSymKeyOnToken( slot, transportKey, masterKeyData, sizeof(masterKeyData), PR_FALSE); + + } else { + master = cardKey; + } + + if( master == NULL) { + goto done; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, master, + &noParams); + + if (context == NULL) { + goto done; + } + + for(i = 0;i < (int)input.size();i += EIGHT_BYTES) + { + s = PK11_CipherOp(context, result, &len, EIGHT_BYTES, + (unsigned char *)(((BYTE*)input)+i), EIGHT_BYTES); + + if (s != SECSuccess) { + goto done; + } + output.replace(i, result, EIGHT_BYTES); + } + + rv = PR_SUCCESS; + +done: + + memset(masterKeyData, 0, sizeof masterKeyData); + if (context) + { + PK11_DestroyContext(context, PR_TRUE); + context = NULL; + } + if (slot) + { + PK11_FreeSlot(slot); + slot = NULL; + } + if (master && cardKey == NULL) + { + PK11_FreeSymKey(master); + master = NULL; + } + + return rv; +} + +PRStatus ComputeKeyCheckWithSymKey(PK11SymKey * newKey, Buffer& output) +{ + PK11SymKey *key = NULL; + PRStatus status = PR_FAILURE ; + PK11SlotInfo *slot = NULL; + PK11Context *context = NULL; + SECStatus s = SECFailure; + int len = 0; + static SECItem noParams = { siBuffer, NULL, 0 }; + unsigned char value[EIGHT_BYTES]; + + if ( newKey == NULL ) { + return status; + } + + memset(value, 0, sizeof value); + + slot = PK11_GetInternalKeySlot(); + if (slot != NULL) + { + key = newKey ; + if( key != NULL ) + { + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, key, + &noParams); + if (context != NULL) + { + s = PK11_CipherOp(context, &value[0], &len, 8, &value[0], 8); + + if (s == SECSuccess) + { + output.resize(3); + output.replace(0, value, 3); + status = PR_SUCCESS; + } + PK11_DestroyContext(context, PR_TRUE); + context = NULL; + } + //PK11_FreeSymKey(key); + //key = NULL; + + } + if( slot != NULL) { + PK11_FreeSlot(slot); + slot = NULL; + } + } + + return status; +} + +// Create key set data with the help of either a provided old_keyk_ke2_sym key or key buffer (for the Default keyset case). +PRStatus CreateKeySetDataWithSymKeys( Buffer &newMasterVer,const Buffer &old_kek_key2, PK11SymKey *old_kek_key2_sym, PK11SymKey *new_auth_key, PK11SymKey *new_mac_key, PK11SymKey *new_kek_key, Buffer &output) +{ + PRStatus rv = PR_FAILURE; + static SECItem noParams = { siBuffer, NULL, 0 }; + PK11SymKey *transportKey = NULL; + PK11SymKey *wrappingKey = NULL; + BYTE masterKeyData[DES3_LENGTH]; + + /* Wrapping vars */ + SECItem wrappedKeyItem = { siBuffer, NULL , 0 }; + SECStatus wrapStatus = SECFailure; + PK11SlotInfo *slot = NULL; + /* Extracting vars */ + + CK_ULONG bitPosition = 0; + SECItem paramsItem = { siBuffer, NULL, 0 }; + paramsItem.data = (CK_BYTE *) &bitPosition; + paramsItem.len = sizeof bitPosition; + + PK11SymKey *macKey16 = NULL; + PK11SymKey *authKey16 = NULL; + PK11SymKey *kekKey16 = NULL; + + Buffer encrypted_auth_key(KEYLENGTH); + Buffer encrypted_mac_key(KEYLENGTH); + Buffer encrypted_kek_key(KEYLENGTH); + + Buffer kc_auth_key(3); + Buffer kc_mac_key(3); + Buffer kc_kek_key(3); + Buffer result; + + PR_fprintf(PR_STDOUT,"In CreateKeySetDataWithSymKeys!\n"); + + if ( new_auth_key == NULL || new_mac_key == NULL || new_kek_key == NULL) { + return rv; + } + + slot = PK11_GetSlotFromKey(new_auth_key); + if ( old_kek_key2_sym == NULL ) { /* perm key mode */ + /* Find transport key, shared secret */ + transportKey = ReturnSymKey( slot, GetSharedSecretKeyName(NULL)); + if ( transportKey == NULL ) { + goto done; + } + + /* convert 16-byte to 24-byte triple-DES key */ + memcpy(masterKeyData, old_kek_key2, KEYLENGTH); + memcpy(masterKeyData+16, old_kek_key2, EIGHT_BYTES); + + wrappingKey = CreateUnWrappedSymKeyOnToken( slot, transportKey, masterKeyData, sizeof(masterKeyData), PR_FALSE); + + } else { /* card key mode */ + wrappingKey = old_kek_key2_sym; + } + + //Now derive 16 byte versions of the provided symkeys + authKey16 = PK11_Derive(new_auth_key, CKM_EXTRACT_KEY_FROM_KEY, ¶msItem, CKA_ENCRYPT, + CKA_DERIVE, 16); + + if ( authKey16 == NULL ) { + PR_fprintf(PR_STDERR,"Error deriving authKey16. Error %d \n", PR_GetError()); + goto done; + } + + wrappedKeyItem.data = (unsigned char *) encrypted_auth_key; + wrappedKeyItem.len = encrypted_auth_key.size(); + wrapStatus = PK11_WrapSymKey(CKM_DES3_ECB,&noParams, wrappingKey, authKey16, &wrappedKeyItem); + if ( wrapStatus == SECFailure ) { + PR_fprintf(PR_STDERR,"Error wrapping authKey16. Error %d \n", PR_GetError()); + goto done; + } + + macKey16 = PK11_Derive(new_mac_key, CKM_EXTRACT_KEY_FROM_KEY, ¶msItem, CKA_ENCRYPT, CKA_DERIVE, 16); + + if ( macKey16 == NULL ) { + PR_fprintf(PR_STDERR,"Error deriving macKey16. Error %d \n", PR_GetError()); + goto done; + } + + wrappedKeyItem.data = (unsigned char *) encrypted_mac_key; + wrappedKeyItem.len = encrypted_mac_key.size(); + wrapStatus = PK11_WrapSymKey(CKM_DES3_ECB,&noParams, wrappingKey, macKey16, &wrappedKeyItem); + if ( wrapStatus == SECFailure) { + PR_fprintf(PR_STDERR,"Error wrapping macKey16. Error %d \n", PR_GetError()); + goto done; + } + + kekKey16 = PK11_Derive(new_kek_key, CKM_EXTRACT_KEY_FROM_KEY, ¶msItem, CKA_ENCRYPT, + CKA_DERIVE, 16); + + if ( kekKey16 == NULL ) { + goto done; + PR_fprintf(PR_STDERR,"Error deriving kekKey16. Error %d \n", PR_GetError()); + } + + wrappedKeyItem.data = (unsigned char *) encrypted_kek_key; + wrappedKeyItem.len = encrypted_mac_key.size(); + wrapStatus = PK11_WrapSymKey(CKM_DES3_ECB,&noParams, wrappingKey, kekKey16, &wrappedKeyItem); + if ( wrapStatus == SECFailure) { + PR_fprintf(PR_STDERR,"Error wrapping kekKey16. Error %d \n", PR_GetError()); + goto done; + } + + ComputeKeyCheckWithSymKey(new_auth_key, kc_auth_key); + + ComputeKeyCheckWithSymKey(new_mac_key, kc_mac_key); + + ComputeKeyCheckWithSymKey(new_kek_key, kc_kek_key); + + result = newMasterVer + + Buffer(1, (BYTE)0x81) + + Buffer(1, (BYTE)0x10) + + encrypted_auth_key + + Buffer(1, (BYTE)0x03) + + kc_auth_key + + Buffer(1, (BYTE)0x81) + + Buffer(1, (BYTE)0x10) + + encrypted_mac_key + + Buffer(1, (BYTE)0x03) + + kc_mac_key + + Buffer(1, (BYTE)0x81) + + Buffer(1, (BYTE)0x10) + + encrypted_kek_key + + Buffer(1, (BYTE)0x03) + + kc_kek_key; + output = result; + + rv = PR_SUCCESS; + +done: + + if ( kekKey16 != NULL) { + PK11_FreeSymKey( kekKey16); + kekKey16 = NULL; + } + + if ( authKey16 != NULL) { + PK11_FreeSymKey( authKey16); + authKey16 = NULL; + } + + if ( macKey16 != NULL) { + PK11_FreeSymKey( macKey16); + macKey16 = NULL; + } + + if ( slot != NULL ) { + PK11_FreeSlot( slot); + slot = NULL; + } + + if ( transportKey != NULL ) { + PK11_FreeSymKey( transportKey); + transportKey = NULL; + } + + return rv; +} + +void GetDiversificationData(jbyte *cuidValue,BYTE *KDC,keyType keytype) +{ + if( ( cuidValue == NULL) || ( KDC == NULL)) { + return; + } + + BYTE *lastTwoBytesOfAID = (BYTE *)cuidValue; +// BYTE *ICFabricationDate = (BYTE *)cuidValue + 2; + BYTE *ICSerialNumber = (BYTE *)cuidValue + 4; +// BYTE *ICBatchIdentifier = (BYTE *)cuidValue + 8; + +// Last 2 bytes of AID + KDC[0]= (BYTE)lastTwoBytesOfAID[0]; + KDC[1]= (BYTE)lastTwoBytesOfAID[1]; + KDC[2]= (BYTE)ICSerialNumber[0]; + KDC[3]= (BYTE)ICSerialNumber[1]; + KDC[4]= (BYTE)ICSerialNumber[2]; + KDC[5]= (BYTE)ICSerialNumber[3]; + KDC[6]= 0xF0; + KDC[7]= 0x01; + KDC[8]= (BYTE)lastTwoBytesOfAID[0]; + KDC[9]= (BYTE)lastTwoBytesOfAID[1]; + KDC[10]= (BYTE)ICSerialNumber[0]; + KDC[11]= (BYTE)ICSerialNumber[1]; + KDC[12]= (BYTE)ICSerialNumber[2]; + KDC[13]= (BYTE)ICSerialNumber[3]; + KDC[14]= 0x0F; + KDC[15]= 0x01; + if(keytype == enc) + return; + + KDC[6]= 0xF0; + KDC[7]= 0x02; + KDC[14]= 0x0F; + KDC[15]= 0x02; + if(keytype == mac) + return; + + KDC[6]= 0xF0; + KDC[7]= 0x03; + KDC[14]= 0x0F; + KDC[15]= 0x03; + if(keytype == kek) + return; + +} + +static int getMasterKeyVersion(char *newMasterKeyNameChars) +{ + if( newMasterKeyNameChars == NULL || + strlen( newMasterKeyNameChars) < 3) { + return 0; + } + + char masterKeyVersionNumber[3]; + masterKeyVersionNumber[0]=newMasterKeyNameChars[1]; + masterKeyVersionNumber[1]=newMasterKeyNameChars[2]; + masterKeyVersionNumber[2]=0; + int newMasterKeyVesion = atoi(masterKeyVersionNumber); + return newMasterKeyVesion; +} + +char *GetSharedSecretKeyName(char *newKeyName) { + if ( newKeyName && strlen( newKeyName ) > 0 ) { + if( strlen( sharedSecretSymKeyName) == 0) { + strncpy( sharedSecretSymKeyName, newKeyName, KEYNAMELENGTH); + } + } + + return (char *) sharedSecretSymKeyName ; +} + +void getFullName(char * fullMasterKeyName, char * masterKeyNameChars ) +{ + if( fullMasterKeyName == NULL || masterKeyNameChars == NULL + || ( strlen(fullMasterKeyName) + strlen(masterKeyNameChars)) > KEYNAMELENGTH) { + return; + } + fullMasterKeyName[0]='\0'; + if(strlen(masterKeyPrefix)>0) + strncpy(fullMasterKeyName,masterKeyPrefix, KEYNAMELENGTH); + strcat(fullMasterKeyName,masterKeyNameChars); +} + + +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: DiversifyKey + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[B)[B + */ +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_DiversifyKey +(JNIEnv *, jclass, jstring, jstring, jstring, jstring, jstring, jbyteArray, jbyteArray, jstring, jstring); + +extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_DiversifyKey( JNIEnv * env, jclass this2, jstring tokenName,jstring newTokenName, jstring oldMasterKeyName, jstring newMasterKeyName, jstring keyInfo, jbyteArray CUIDValue, jbyteArray kekKeyArray, jstring useSoftToken_s, jstring keySet) +{ + PK11SymKey *encKey = NULL; + PK11SymKey *macKey = NULL; + PK11SymKey *kekKey = NULL; + Buffer encKeyBuff; + Buffer macKeyBuff; + Buffer kekKeyBuff; + char * oldMasterKeyNameChars=NULL; + Buffer old_kek_key_buff; + Buffer newMasterKeyBuffer; + char fullMasterKeyName[KEYNAMELENGTH]; + char fullNewMasterKeyName[KEYNAMELENGTH]; + PRBool specified_key_is_present = PR_TRUE; + PK11SymKey *old_kek_sym_key = NULL; + + char *keySetStringChars = NULL; + if ( keySet != NULL ) { + keySetStringChars = (char *) (env)->GetStringUTFChars( keySet, NULL); + } + + char *keySetString = keySetStringChars; + + if ( keySetString == NULL ) { + keySetString = (char *) DEFKEYSET_NAME; + } + + jbyteArray handleBA=NULL; + jbyte *handleBytes=NULL; + int newMasterKeyVesion = 1; + + /* find slot */ + char *tokenNameChars = NULL; + char * newMasterKeyNameChars = NULL; + PK11SlotInfo *slot = NULL; + PK11SlotInfo *internal = PK11_GetInternalKeySlot(); + + Buffer output; + PK11SlotInfo *newSlot =NULL; + char * newTokenNameChars = NULL; + char *keyInfoChars = NULL; + + jbyte * cuidValue = NULL; + jbyte * old_kek_key = NULL; + + PK11SymKey * masterKey = NULL; + PK11SymKey * oldMasterKey = NULL; + + BYTE KDCenc[KEYLENGTH]; + BYTE KDCmac[KEYLENGTH]; + BYTE KDCkek[KEYLENGTH]; + + if( CUIDValue != NULL) { + cuidValue = (jbyte*)(env)->GetByteArrayElements( CUIDValue, NULL); + } + + if( cuidValue == NULL) { + goto done; + } + + if( kekKeyArray != NULL) { + old_kek_key = (jbyte*)(env)->GetByteArrayElements(kekKeyArray, NULL); + } + + if( old_kek_key == NULL) { + goto done; + } + + PR_fprintf(PR_STDOUT,"In SessionKey.DiversifyKey! \n"); + + GetDiversificationData(cuidValue,KDCenc,enc); + GetDiversificationData(cuidValue,KDCmac,mac); + GetDiversificationData(cuidValue,KDCkek,kek); + + if(tokenName) + { + tokenNameChars = (char *)(env)->GetStringUTFChars(tokenName, NULL); + slot = ReturnSlot(tokenNameChars); + PR_fprintf(PR_STDOUT,"DiversifyKey: tokenNameChars %s slot %p \n", tokenNameChars,slot); + if( tokenNameChars != NULL) { + (env)->ReleaseStringUTFChars(tokenName, (const char *)tokenNameChars); + } + } + + if(newMasterKeyName) + { + /* newMasterKeyNameChars #02#01 */ + newMasterKeyNameChars= (char *)(env)->GetStringUTFChars(newMasterKeyName, NULL); + } + /* fullNewMasterKeyName - no prefix #02#01 */ + getFullName(fullNewMasterKeyName,newMasterKeyNameChars); + PR_fprintf(PR_STDOUT,"DiversifyKey: fullNewMasterKeyName %s . \n", fullNewMasterKeyName); + + if(newTokenName) + { + newTokenNameChars = (char *)(env)->GetStringUTFChars(newTokenName, NULL); + newSlot = ReturnSlot(newTokenNameChars); + PR_fprintf(PR_STDOUT,"DiversifyKey: newTokenNameChars %s newSlot %p . \n", newTokenNameChars,newSlot); + if( newTokenNameChars != NULL) { + (env)->ReleaseStringUTFChars(newTokenName, (const char *)newTokenNameChars); + } + } + + masterKey = ReturnSymKey(newSlot,fullNewMasterKeyName); + + if(newMasterKeyNameChars) { + (env)->ReleaseStringUTFChars(newMasterKeyName, (const char *)newMasterKeyNameChars); + } + + /* packing return */ + if( keyInfo != NULL) { + keyInfoChars = (char *)(env)->GetStringUTFChars(keyInfo, NULL); + } + + newMasterKeyVesion = getMasterKeyVersion(keyInfoChars); + + if(keyInfoChars) + { + (env)->ReleaseStringUTFChars(keyInfo, (const char *)keyInfoChars); + } + + /* NEW MASTER KEY VERSION */ + newMasterKeyBuffer = Buffer((unsigned int) 1, (BYTE)newMasterKeyVesion); + if(oldMasterKeyName) + { + oldMasterKeyNameChars = (char *)(env)->GetStringUTFChars(oldMasterKeyName, NULL); + PR_fprintf(PR_STDOUT,"DiversifyKey oldMasterKeyNameChars %s \n", oldMasterKeyNameChars); + } + getFullName(fullMasterKeyName,oldMasterKeyNameChars); + PR_fprintf(PR_STDOUT,"DiversifyKey fullMasterKeyName %s \n", fullMasterKeyName); + if(newSlot == NULL) { + newSlot = slot; + } + if(strcmp( oldMasterKeyNameChars, "#01#01") == 0 || strcmp( oldMasterKeyNameChars, "#FF#01") == 0) + { + old_kek_key_buff = Buffer((BYTE*)old_kek_key, KEYLENGTH); + }else if(strcmp( oldMasterKeyNameChars, "#00#00") == 0) + { + /* print Debug message - do not create real keysetdata */ + old_kek_key_buff = Buffer((BYTE*)"#00#00", 6); + output = Buffer((BYTE*)old_kek_key, KEYLENGTH); + } + else + { + oldMasterKey = ReturnSymKey(slot,fullMasterKeyName); + old_kek_sym_key = ComputeCardKeyOnToken(oldMasterKey,KDCkek); + if (oldMasterKey) { + PK11_FreeSymKey( oldMasterKey ); + oldMasterKey = NULL; + } + } + if(oldMasterKeyNameChars) { + (env)->ReleaseStringUTFChars(oldMasterKeyName, (const char *)oldMasterKeyNameChars); + } + + /* special case #01#01 */ + if (fullNewMasterKeyName != NULL && strcmp(fullNewMasterKeyName, "#01#01") == 0) + { + Buffer empty = Buffer(); + + encKey = ReturnDeveloperSymKey(internal,(char *) "auth", keySetString, empty); + + if ( encKey == NULL ) { + goto done; + } + PR_fprintf(PR_STDOUT, "Special case dev key set for DiversifyKey!\n"); + + macKey = ReturnDeveloperSymKey(internal, (char *) "mac", keySetString, empty); + if ( macKey == NULL ) { + goto done; + } + + kekKey = ReturnDeveloperSymKey(internal, (char *) "kek", keySetString, empty); + + if ( kekKey == NULL ) { + goto done; + } + + } else { + PR_fprintf(PR_STDOUT,"DiversifyKey: Compute card key on token case ! \n"); + /* compute card key */ + encKey = ComputeCardKeyOnSoftToken(masterKey, KDCenc); + macKey = ComputeCardKeyOnSoftToken(masterKey, KDCmac); + kekKey = ComputeCardKeyOnSoftToken(masterKey, KDCkek); + + /* Fixes Bugscape Bug #55855: TKS crashes if specified key + * is not present -- for each portion of the key, check if + * the PK11SymKey is NULL before sending it to PK11_GetKeyData()! + */ + if( encKey == NULL) { + PR_fprintf(PR_STDERR,"Can't create encKey in DiversifyKey! \n"); + specified_key_is_present = PR_FALSE; + goto done; + } + if( macKey == NULL) { + PR_fprintf(PR_STDERR,"Can't create macKey in DiversifyKey! \n"); + specified_key_is_present = PR_FALSE; + goto done; + } + if( kekKey == NULL) { + PR_fprintf(PR_STDERR,"Can't create kekKey in DiversifyKey! \n"); + specified_key_is_present = PR_FALSE; + goto done; + } + } + + if (old_kek_sym_key != NULL) { + CreateKeySetDataWithSymKeys(newMasterKeyBuffer, Buffer(), + old_kek_sym_key, + encKey, + macKey, + kekKey, + output); } + else { + old_kek_sym_key = ReturnDeveloperSymKey(slot, (char *) "kek", keySetString, old_kek_key_buff); + CreateKeySetDataWithSymKeys(newMasterKeyBuffer, Buffer(), + old_kek_sym_key, + encKey, + macKey, + kekKey, + output); + } + +done: + if (masterKey != NULL) { + PK11_FreeSymKey( masterKey); + masterKey = NULL; + } + + if (encKey != NULL) { + PK11_FreeSymKey( encKey ); + encKey = NULL; + } + + if (macKey != NULL) { + PK11_FreeSymKey( macKey ); + macKey = NULL; + } + + if (kekKey != NULL) { + PK11_FreeSymKey( kekKey ); + kekKey = NULL; + } + + if( keySetStringChars ) { + (env)->ReleaseStringUTFChars(keySet, (const char *)keySetStringChars); + keySetStringChars = NULL; + } + + if( specified_key_is_present ) + { + if(output.size()>0) + handleBA = (env)->NewByteArray( output.size()); + else + handleBA = (env)->NewByteArray(1); + handleBytes = (env)->GetByteArrayElements(handleBA, NULL); + memcpy(handleBytes, (BYTE*)output,output.size()); + + if( handleBytes != NULL) { + (env)->ReleaseByteArrayElements( handleBA, handleBytes, 0); + } + } + + if( cuidValue != NULL) { + (env)->ReleaseByteArrayElements(CUIDValue, cuidValue, JNI_ABORT); + } + + if( kekKeyArray != NULL) { + (env)->ReleaseByteArrayElements(kekKeyArray, old_kek_key, JNI_ABORT); + } + + if((newSlot != slot) && newSlot) { + PK11_FreeSlot( newSlot); + newSlot = NULL; + } + + if( slot ) { + PK11_FreeSlot( slot); + slot = NULL; + } + + if( internal) { + PK11_FreeSlot( internal); + internal = NULL; + } + + return handleBA; +} + +PK11SymKey *CreateUnWrappedSymKeyOnToken( PK11SlotInfo *slot, PK11SymKey * unWrappingKey, BYTE *keyToBeUnWrapped, int sizeOfKeyToBeUnWrapped, PRBool isPerm) +{ + PK11SymKey * unWrappedSymKey = NULL; + int bufSize = 48; + unsigned char outbuf[bufSize]; + int final_len = 0; + SECStatus s = SECSuccess; + PK11Context * EncContext = NULL; + SECItem unWrappedKeyItem = { siBuffer, NULL, 0}; + PK11SymKey *unwrapper = NULL; + + PR_fprintf( PR_STDOUT, + "Creating UnWrappedSymKey on token. \n"); + + if ( (slot == NULL) || (unWrappingKey == NULL) || + (keyToBeUnWrapped == NULL) || + (sizeOfKeyToBeUnWrapped != DES3_LENGTH) + ) { + return NULL; + } + + PK11SlotInfo *unwrapKeySlot = PK11_GetSlotFromKey( unWrappingKey ); + + if ( unwrapKeySlot != slot ) { + unwrapper = PK11_MoveSymKey ( slot, CKA_ENCRYPT, 0, PR_FALSE, unWrappingKey); + } + + SECItem *SecParam = PK11_ParamFromIV(CKM_DES3_ECB, NULL); + if ( SecParam == NULL) { + goto done; + } + + EncContext = PK11_CreateContextBySymKey(CKM_DES3_ECB, + CKA_ENCRYPT, + unWrappingKey, SecParam); + + if ( EncContext == NULL) { + goto done; + } + + s = PK11_CipherOp(EncContext, outbuf, &final_len, sizeof( outbuf), keyToBeUnWrapped, + sizeOfKeyToBeUnWrapped); + + if ( s != SECSuccess) { + goto done; + } + + if ( final_len != DES3_LENGTH ) { + goto done; + } + + unWrappedKeyItem.data = outbuf; + unWrappedKeyItem.len = final_len; + + + /* Now try to unwrap our key into the token */ + unWrappedSymKey = PK11_UnwrapSymKeyWithFlagsPerm(unwrapper ? unwrapper : unWrappingKey, + CKM_DES3_ECB,SecParam, &unWrappedKeyItem, + CKM_DES3_ECB, + CKA_UNWRAP, + sizeOfKeyToBeUnWrapped, 0, isPerm ); + +done: + + if( SecParam != NULL ) { + SECITEM_FreeItem(SecParam, PR_TRUE); + SecParam = NULL; + } + + if( EncContext != NULL ) { + PK11_DestroyContext(EncContext, PR_TRUE); + EncContext = NULL; + } + + if( unwrapper != NULL ) { + PK11_FreeSymKey( unwrapper ); + unwrapper = NULL; + } + + if( unwrapKeySlot != NULL) { + PK11_FreeSlot( unwrapKeySlot); + unwrapKeySlot = NULL; + } + + PR_fprintf( PR_STDOUT, + "UnWrappedSymKey on token result: %p \n",unWrappedSymKey); + + return unWrappedSymKey; +} +//Return default keyset developer key. Either auth, mac, or kek +PK11SymKey *ReturnDeveloperSymKey(PK11SlotInfo *slot, char *keyType, char *keySet, Buffer &inputKey) +{ + const int maxKeyNameSize = 56; + PK11SymKey *devSymKey = NULL; + PK11SymKey *transportKey = NULL; + char devKeyName[maxKeyNameSize]; + + SECStatus rv = SECSuccess; + + BYTE sessionKey[DES3_LENGTH]; + + if( slot == NULL || keyType == NULL || keySet == NULL) { + return NULL; + } + + snprintf(devKeyName,maxKeyNameSize,"%s-%sKey", keySet, keyType); + + devSymKey = ReturnSymKey( slot, devKeyName ); + + // Try to create the key once and leave it there. + if( devSymKey == NULL ) { + PR_fprintf(PR_STDOUT, "Can't find devSymKey, try to create it on token. \n"); + if ( inputKey.size() == DES2_LENGTH ) { //Any other size ignored + transportKey = ReturnSymKey( slot, GetSharedSecretKeyName(NULL)); + + if( transportKey == NULL) { + PR_fprintf(PR_STDERR,"Can't get transport key in ReturnDeveloperSymKey! \n"); + goto done; + } + + /* convert 16-byte to 24-byte triple-DES key */ + memcpy(sessionKey, inputKey, DES2_LENGTH); + memcpy(sessionKey+ DES2_LENGTH, inputKey, EIGHT_BYTES); + + //Unwrap this thing on there as permanent, so we don't have to create it again for a given keySet. + if( transportKey) { + devSymKey = CreateUnWrappedSymKeyOnToken( slot, transportKey, sessionKey, sizeof(sessionKey), PR_TRUE); + } + + PR_fprintf(PR_STDERR,"Tried to create devSymKey %p \n",devSymKey); + + rv = SECSuccess; + if( devSymKey ) { + rv = PK11_SetSymKeyNickname( devSymKey, devKeyName ); + + if ( rv != SECSuccess ) { + PR_fprintf(PR_STDERR, "Can't set the nickname of just written devKey! \n"); + } + } + } + } + +done: + if( transportKey ) { + PK11_FreeSymKey( transportKey ); + transportKey = NULL; + } + + // Dont' free slot , let the caller. + return devSymKey; +} + +/* + * Class: com_netscape_cms_servlet_tks_RASessionKey + * Method: SetDefaultPrefix + * Signature: (Ljava/lang/String;)V + */ +extern "C" JNIEXPORT void JNICALL Java_com_netscape_symkey_SessionKey_SetDefaultPrefix +(JNIEnv *, jclass, jstring); +extern "C" JNIEXPORT void +JNICALL Java_com_netscape_symkey_SessionKey_SetDefaultPrefix(JNIEnv * env, jclass this2, jstring masterPrefix) +{ + char *masterPrefixChars; + + masterPrefixChars = (char *)(env)->GetStringUTFChars(masterPrefix, NULL); + + if(masterPrefixChars) + strcpy(masterKeyPrefix,masterPrefixChars); + else + masterKeyPrefix[0] = '\0'; + + if(masterPrefixChars) + { + (env)->ReleaseStringUTFChars(masterPrefix, (const char *)masterPrefixChars); + } + + return; +} diff --git a/base/symkey/src/com/netscape/symkey/SymKey.h b/base/symkey/src/com/netscape/symkey/SymKey.h new file mode 100644 index 000000000..5a53d48c9 --- /dev/null +++ b/base/symkey/src/com/netscape/symkey/SymKey.h @@ -0,0 +1,55 @@ +// --- 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. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#ifndef _TKSSYMKEY_H_ +#define _TKSSYMKEY_H_ + +extern PK11SlotInfo *defaultSlot; + +typedef enum { + enc, + mac, + kek + } keyType; +#define KEYLENGTH 16 +#define PREFIXLENGHT 128 +#define DES2_LENGTH 16 +#define DES3_LENGTH 24 +#define EIGHT_BYTES 8 +#define KEYNAMELENGTH PREFIXLENGHT+7 +#define TRANSPORT_KEY_NAME "sharedSecret" +#define DEFKEYSET_NAME "defKeySet" + +extern char masterKeyPrefix[PREFIXLENGHT]; +extern char sharedSecretSymKeyName[KEYNAMELENGTH]; + +void GetDiversificationData(jbyte *cuidValue,BYTE *KDC,keyType keytype); +PK11SymKey * ReturnSymKey( PK11SlotInfo *slot, char *keyname); +void GetKeyName(jbyte *keyVersion,char *keyname); +PK11SymKey * ComputeCardKeyOnToken(PK11SymKey *masterKey, BYTE* data); +PRStatus EncryptData(const Buffer &kek_key, PK11SymKey *card_key, Buffer &input, Buffer &output); +PK11SlotInfo *ReturnSlot(char *tokenNameChars); +PK11SymKey *ComputeCardKey(PK11SymKey *masterKey, unsigned char *data, PK11SlotInfo *slot); +PK11SymKey *CreateUnWrappedSymKeyOnToken( PK11SlotInfo *slot, PK11SymKey * unWrappingKey, BYTE *keyToBeUnWrapped, int sizeOfKeyToBeUnWrapped, PRBool isPerm); +PK11SymKey *ReturnDeveloperSymKey(PK11SlotInfo *slot, char *keyType, char *keySet, Buffer &inputKey); + +char *GetSharedSecretKeyName(char *newKeyName); + +#define DES2_WORKAROUND +#endif /* _TKSSYMKEY_H_ */ + -- cgit