diff --git a/security/jss/lib/jss.def b/security/jss/lib/jss.def index 1d527eaa6df5..a92ea65ebe2b 100644 --- a/security/jss/lib/jss.def +++ b/security/jss/lib/jss.def @@ -272,3 +272,10 @@ Java_org_mozilla_jss_pkcs11_PK11Cipher_initContextWithKeyBits; ;+ local: ;+ *; ;+}; +;+JSS_3.5 { # JSS 3.5 release +;+ global: +Java_org_mozilla_jss_SecretDecoderRing_KeyManager_generateUniqueNamedKeyNative; +Java_org_mozilla_jss_SecretDecoderRing_KeyManager_lookupUniqueNamedKeyNative; +;+ local: +;+ *; +;+}; diff --git a/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.c b/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.c index c89dee785a6b..c10c8e1961d7 100644 --- a/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.c +++ b/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.c @@ -101,6 +101,80 @@ finish: return; } +JNIEXPORT void JNICALL +Java_org_mozilla_jss_SecretDecoderRing_KeyManager_generateUniqueNamedKeyNative + (JNIEnv *env, jobject this, jobject tokenObj, jobject algObj, + jbyteArray keyIDba, jint keySize, jstring nickname) +{ + PK11SlotInfo *slot = NULL; + CK_MECHANISM_TYPE mech; + PK11SymKey *symk = NULL; + SECItem *keyID = NULL; + const char *keyname = NULL; + SECStatus status; + + /* get the slot */ + if( JSS_PK11_getTokenSlotPtr(env, tokenObj, &slot) != PR_SUCCESS ) { + goto finish; + } + + if( PK11_Authenticate(slot, PR_TRUE /*load certs*/, NULL /*wincx*/) + != SECSuccess) + { + JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, + "Failed to login to token"); + goto finish; + } + + /* get the key ID */ + keyID = JSS_ByteArrayToSECItem(env, keyIDba); + if( keyID == NULL ) { + ASSERT_OUTOFMEM(env); + goto finish; + } + + /* get the algorithm */ + mech = JSS_getPK11MechFromAlg(env, algObj); + if( mech == CKM_INVALID_MECHANISM) { + JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, "Failed to find PKCS #11 " + "mechanism for key generation algorithm"); + goto finish; + } + + /* generate the key */ + symk = PK11_TokenKeyGen(slot, mech, NULL /*param*/, keySize, keyID, + PR_TRUE /* isToken */, NULL /*wincx*/); + if( symk == NULL ) { + JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, + "Failed to generate token symmetric key"); + goto finish; + } + + /* convert the Java String into a native "C" string */ + keyname = (*env)->GetStringUTFChars( env, nickname, 0 ); + + /* name the key */ + status = PK11_SetSymKeyNickname( symk, keyname ); + if( status != SECSuccess ) { + JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, + "Failed to name token symmetric key"); + } + + +finish: + if( symk != NULL ) { + PK11_FreeSymKey(symk); + } + if( keyID != NULL ) { + SECITEM_FreeItem(keyID, PR_TRUE /*freeit*/); + } + if( keyname != NULL ) { + /* free the native "C" string */ + (*env)->ReleaseStringUTFChars(env, nickname, keyname); + } + return; +} + JNIEXPORT jobject JNICALL Java_org_mozilla_jss_SecretDecoderRing_KeyManager_lookupKeyNative (JNIEnv *env, jobject this, jobject tokenObj, jobject algObj, @@ -155,6 +229,129 @@ finish: return symkObj; } +JNIEXPORT jobject JNICALL +Java_org_mozilla_jss_SecretDecoderRing_KeyManager_lookupUniqueNamedKeyNative + (JNIEnv *env, jobject this, jobject tokenObj, jobject algObj, + jstring nickname) +{ + PK11SlotInfo *slot = NULL; + CK_MECHANISM_TYPE mech; + const char *keyname = NULL; + char *name = NULL; + int count = 0; + int keys_found = 0; + PK11SymKey *symKey = NULL; + PK11SymKey *nextSymKey = NULL; + jobject symKeyObj = NULL; + + /* get the slot */ + if( JSS_PK11_getTokenSlotPtr(env, tokenObj, &slot) != PR_SUCCESS ) { + goto finish; + } + + if( PK11_Authenticate(slot, PR_TRUE /*load certs*/, NULL /*wincx*/) + != SECSuccess) + { + JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, + "Failed to login to token"); + goto finish; + } + + /* get the algorithm -- although this is not currently used */ + mech = JSS_getPK11MechFromAlg(env, algObj); + if( mech == CKM_INVALID_MECHANISM) { + JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, "Failed to find PKCS #11 " + "mechanism for key generation algorithm"); + goto finish; + } + + /* convert the Java String into a native "C" string */ + keyname = (*env)->GetStringUTFChars( env, nickname, 0 ); + + /* initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( + /* slot */ slot, + /* nickname */ NULL, + /* wincx */ NULL ); + + /* iterate through the symmetric key list. */ + while( symKey != NULL ) { + name = PK11_GetSymKeyNickname( /* symmetric key */ symKey ); + if( name != NULL ) { + if( keyname != NULL ) { + if( PL_strcmp( keyname, name ) == 0 ) { + keys_found++; + } + } + } + + nextSymKey = PK11_GetNextSymKey( /* symmetric key */ symKey ); + PK11_FreeSymKey( /* symmetric key */ symKey ); + symKey = nextSymKey; + + count++; + } + + /* case 1: the token is empty */ + if( count == 0 ) { + /* the specified token is empty */ + symKeyObj = NULL; + goto finish; + } + + /* case 2: the specified key is not on this token */ + if( ( keyname != NULL ) && + ( keys_found == 0 ) ) { + /* the key called "keyname" could not be found */ + symKeyObj = NULL; + goto finish; + } + + /* case 3: the specified key exists more than once on this token */ + if( keys_found != 1 ) { + /* more than one key called "keyname" was found on this token */ + symKeyObj = NULL; + JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, + "Duplicate named keys exist on this token"); + goto finish; + } else { + /* Re-initialize the symmetric key list. */ + symKey = PK11_ListFixedKeysInSlot( + /* slot */ slot, + /* nickname */ NULL, + /* wincx */ NULL ); + + /* Reiterate through the symmetric key list once more, */ + /* this time returning an actual reference to the key. */ + while( symKey != NULL ) { + name = PK11_GetSymKeyNickname( /* symmetric key */ symKey ); + if( name != NULL ) { + if( keyname != NULL ) { + if( PL_strcmp( keyname, name ) == 0 ) { + symKeyObj = JSS_PK11_wrapSymKey(env, &symKey); + goto finish; + } + } + } + + nextSymKey = PK11_GetNextSymKey( /* symmetric key */ symKey ); + PK11_FreeSymKey( /* symmetric key */ symKey ); + symKey = nextSymKey; + } + } + + +finish: + if( symKey != NULL ) { + PK11_FreeSymKey(symKey); + } + if( keyname != NULL ) { + /* free the native "C" string */ + (*env)->ReleaseStringUTFChars(env, nickname, keyname); + } + return symKeyObj; +} + JNIEXPORT void JNICALL Java_org_mozilla_jss_SecretDecoderRing_KeyManager_deleteKeyNative (JNIEnv *env, jobject this, jobject tokenObj, jobject key) diff --git a/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.java b/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.java index 8cd2ca7896c6..7f565d336276 100644 --- a/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.java +++ b/security/jss/org/mozilla/jss/SecretDecoderRing/KeyManager.java @@ -115,6 +115,63 @@ public class KeyManager { private native void generateKeyNative(CryptoToken token, KeyGenAlgorithm alg, byte[] keyID, int keySize); + /** + * Generates an SDR key with the default algorithm and key size. + * and names it with the specified nickname. + * The default algorithm is stored in the constant DEFAULT_KEYGEN_ALG. + * The default key size is stored in the constant DEFAULT_KEYSIZE. + * @param nickname the name of the symmetric key. Duplicate keynames + * will be checked for, and are not allowed. + * @return The keyID of the generated key. A random keyID will be chosen + * that is not currently used on the token. The keyID must be stored + * by the application in order to use this key for encryption in the + * future. + */ + public byte[] generateUniqueNamedKey(String nickname) + throws TokenException { + return generateUniqueNamedKey(DEFAULT_KEYGEN_ALG, DEFAULT_KEYSIZE, + nickname); + } + + /** + * Generates an SDR key with the given algorithm, key size, and nickname. + * @param alg The algorithm that this key will be used for. + * This is necessary because it will be stored along with the + * key for later use by the security library. + * @param keySize Length of key in bytes. This is only relevant for + * algorithms that take more than one key size. Otherwise it can just + * be set to 0. + * @param nickname the name of the symmetric key. Duplicate keynames + * will be checked for, and are not allowed. + * @return The keyID of the generated key. A random keyID will be chosen + * that is not currently used on the token. The keyID must be stored + * by the application in order to use this key for encryption in the + * future. + */ + public byte[] generateUniqueNamedKey(KeyGenAlgorithm alg, int keySize, + String nickname) + throws TokenException + { + if( alg == null ) { + throw new NullPointerException("alg is null"); + } + // disallow duplicates (i. e. - symmetric keys with the same name) + if( uniqueNamedKeyExists(nickname) ) { + throw new NullPointerException("duplicate symmetric key"); + } + byte[] keyID = generateUnusedKeyID(); + generateUniqueNamedKeyNative(token, alg, keyID, keySize, nickname); + return keyID; + } + + /** + * @param keySize Key length in bytes. + * @param nickname the name of the symmetric key. Duplicate keynames + * will be checked for, and are not allowed. + */ + private native void generateUniqueNamedKeyNative(CryptoToken token, + KeyGenAlgorithm alg, byte[] keyID, int keySize, String nickname); + /** * Generates a key ID that is currently unused on this token. * The caller is responsible for synchronization issues that may arise @@ -166,6 +223,43 @@ public class KeyManager { private native SymmetricKey lookupKeyNative(CryptoToken token, EncryptionAlgorithm alg, byte[] keyid) throws TokenException; + private boolean uniqueNamedKeyExists(String nickname) + throws TokenException + { + return (lookupUniqueNamedKey(Encryptor.DEFAULT_ENCRYPTION_ALG, + nickname) != null); + } + + /** + * Looks up the key on this token with the given algorithm and nickname. + * @param alg The algorithm that this key will be used for. + * This is necessary because it will be stored along with the + * key for later use by the security library. It should match + * the actual algorithm of the key you are looking for. If you + * pass in a different algorithm and try to use the key that is returned, + * the results are undefined. + * @param nickname the name of the symmetric key. Duplicate keynames + * will be checked for, and are not allowed. + * @return The key, or null if the key is not found. + */ + public SecretKey lookupUniqueNamedKey(EncryptionAlgorithm alg, + String nickname) + throws TokenException + { + if( alg == null || nickname == null || nickname.equals("") ) { + throw new NullPointerException(); + } + SymmetricKey k = lookupUniqueNamedKeyNative(token, alg, nickname); + if( k == null ) { + return null; + } else { + return new SecretKeyFacade(k); + } + } + + private native SymmetricKey lookupUniqueNamedKeyNative(CryptoToken token, + EncryptionAlgorithm alg, String nickname) throws TokenException; + /** * Deletes the key with the given keyID from this token. * @throws InvalidKeyException If the key does not exist on this token. @@ -176,6 +270,20 @@ public class KeyManager { deleteKey(lookupKey(Encryptor.DEFAULT_ENCRYPTION_ALG, keyID)); } + /** + * If it exists, delete the key with the specified nickname from this + * token. + */ + public void deleteUniqueNamedKey(String nickname) throws TokenException, + InvalidKeyException + { + // only delete this symmetric key if it exists + if( uniqueNamedKeyExists(nickname) ) { + deleteKey(lookupUniqueNamedKey(Encryptor.DEFAULT_ENCRYPTION_ALG, + nickname)); + } + } + /** * Deletes this key from this token. * @throws InvalidKeyException If the key does not reside on this token,