# HG changeset patch
# User Fraser Tweedale <ftweedal@redhat.com>
# Date 1493324725 25200
# Thu Apr 27 13:25:25 2017 -0700
# Node ID c8885dd6787639d74a1c9d634fd289ff17fa6f02
# Parent b2306481f30dcc8c0c060520805d405dd2546d14
Bug 1355358 - CryptoStore: add methods for importing and exporting EncryptedPrivateKeyInfo, r=cfu
diff --git a/lib/jss.def b/lib/jss.def
--- a/lib/jss.def
+++ b/lib/jss.def
@@ -324,3 +324,9 @@
;+ local:
;+ *;
;+};
+;+JSS_4.4.1 { # JSS 4.4.1 release
+;+ global:
+Java_org_mozilla_jss_pkcs11_PK11Store_importEncryptedPrivateKeyInfo;
+;+ local:
+;+ *;
+;+};
diff --git a/org/mozilla/jss/crypto/Algorithm.c b/org/mozilla/jss/crypto/Algorithm.c
--- a/org/mozilla/jss/crypto/Algorithm.c
+++ b/org/mozilla/jss/crypto/Algorithm.c
@@ -86,7 +86,13 @@
/* 55 */ {SEC_OID_PKCS5_PBMAC1, SEC_OID_TAG},
/* 56 */ {SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST, SEC_OID_TAG},
/* 57 */ {CKM_NSS_AES_KEY_WRAP, PK11_MECH},
-/* 58 */ {CKM_NSS_AES_KEY_WRAP_PAD, PK11_MECH}
+/* 58 */ {CKM_NSS_AES_KEY_WRAP_PAD, PK11_MECH},
+/* 59 */ {SEC_OID_AES_128_ECB, SEC_OID_TAG},
+/* 60 */ {SEC_OID_AES_128_CBC, SEC_OID_TAG},
+/* 61 */ {SEC_OID_AES_192_ECB, SEC_OID_TAG},
+/* 62 */ {SEC_OID_AES_192_CBC, SEC_OID_TAG},
+/* 63 */ {SEC_OID_AES_256_ECB, SEC_OID_TAG},
+/* 64 */ {SEC_OID_AES_256_CBC, SEC_OID_TAG}
/* REMEMBER TO UPDATE NUM_ALGS!!! */
};
diff --git a/org/mozilla/jss/crypto/Algorithm.h b/org/mozilla/jss/crypto/Algorithm.h
--- a/org/mozilla/jss/crypto/Algorithm.h
+++ b/org/mozilla/jss/crypto/Algorithm.h
@@ -24,7 +24,7 @@
JSS_AlgType type;
} JSS_AlgInfo;
-#define NUM_ALGS 59
+#define NUM_ALGS 65
extern JSS_AlgInfo JSS_AlgTable[];
extern CK_ULONG JSS_symkeyUsage[];
diff --git a/org/mozilla/jss/crypto/Algorithm.java b/org/mozilla/jss/crypto/Algorithm.java
--- a/org/mozilla/jss/crypto/Algorithm.java
+++ b/org/mozilla/jss/crypto/Algorithm.java
@@ -212,4 +212,12 @@
protected static final short SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST=56;
protected static final short CKM_NSS_AES_KEY_WRAP=57;
protected static final short CKM_NSS_AES_KEY_WRAP_PAD=58;
+
+ // AES Encryption Algorithms
+ protected static final short SEC_OID_AES_128_ECB = 59;
+ protected static final short SEC_OID_AES_128_CBC = 60;
+ protected static final short SEC_OID_AES_192_ECB = 61;
+ protected static final short SEC_OID_AES_192_CBC = 62;
+ protected static final short SEC_OID_AES_256_ECB = 63;
+ protected static final short SEC_OID_AES_256_CBC = 64;
}
diff --git a/org/mozilla/jss/crypto/CryptoStore.java b/org/mozilla/jss/crypto/CryptoStore.java
--- a/org/mozilla/jss/crypto/CryptoStore.java
+++ b/org/mozilla/jss/crypto/CryptoStore.java
@@ -4,6 +4,7 @@
package org.mozilla.jss.crypto;
+import org.mozilla.jss.CryptoManager;
import org.mozilla.jss.util.*;
import java.security.*;
import java.security.cert.CertificateEncodingException;
@@ -68,9 +69,50 @@
public void deletePrivateKey(org.mozilla.jss.crypto.PrivateKey key)
throws NoSuchItemOnTokenException, TokenException;
+ /**
+ * Get an encrypted private key for the given cert.
+ *
+ * @param cert Certificate of key to be exported
+ * @param pbeAlg The PBEAlgorithm to use
+ * @param pw The password to encrypt with
+ * @param iteration Iteration count; default of 2000 if le 0
+ */
+ public byte[] getEncryptedPrivateKeyInfo(X509Certificate cert,
+ PBEAlgorithm pbeAlg, Password pw, int iteration)
+ throws CryptoManager.NotInitializedException,
+ ObjectNotFoundException, TokenException;
- public byte[] getEncryptedPrivateKeyInfo(X509Certificate cert,
- PBEAlgorithm pbeAlg, Password pw, int iteration);
+ /**
+ * Get an encrypted private key, with optional password
+ * conversion.
+ *
+ * @param conv Password converter. If null, pw.getByteCopy()
+ * will be used to get password bytes.
+ * @param pw The password
+ * @param alg The encryption algorithm
+ * @param n Iteration count; default of 2000 if le 0
+ * @param k The private key
+ */
+ public byte[] getEncryptedPrivateKeyInfo(
+ KeyGenerator.CharToByteConverter conv,
+ Password pw,
+ Algorithm alg,
+ int n,
+ PrivateKey k);
+
+ /**
+ * @param conv Password converter. If null, pw.getByteCopy()
+ * will be used to get password bytes.
+ * @param pw The password
+ * @param nickname Nickname to use for private key
+ * @param pubKey Public key corresponding to private key
+ */
+ public void importEncryptedPrivateKeyInfo(
+ KeyGenerator.CharToByteConverter conv,
+ Password pw,
+ String nickname,
+ PublicKey pubKey,
+ byte[] epkiBytes);
////////////////////////////////////////////////////////////
// Certs
diff --git a/org/mozilla/jss/crypto/EncryptionAlgorithm.java b/org/mozilla/jss/crypto/EncryptionAlgorithm.java
--- a/org/mozilla/jss/crypto/EncryptionAlgorithm.java
+++ b/org/mozilla/jss/crypto/EncryptionAlgorithm.java
@@ -347,12 +347,14 @@
{ 2, 16, 840, 1, 101, 3, 4, 1 } );
public static final EncryptionAlgorithm
- AES_128_ECB = new EncryptionAlgorithm(CKM_AES_ECB, Alg.AES, Mode.ECB,
+ AES_128_ECB = new EncryptionAlgorithm(SEC_OID_AES_128_ECB,
+ Alg.AES, Mode.ECB,
Padding.NONE, (Class)null, 16,
AES_ROOT_OID.subBranch(1), 128);
public static final EncryptionAlgorithm
- AES_128_CBC = new EncryptionAlgorithm(CKM_AES_CBC, Alg.AES, Mode.CBC,
+ AES_128_CBC = new EncryptionAlgorithm(SEC_OID_AES_128_CBC,
+ Alg.AES, Mode.CBC,
Padding.NONE, IVParameterSpecClasses, 16,
AES_ROOT_OID.subBranch(2), 128);
@@ -361,11 +363,13 @@
Padding.PKCS5, IVParameterSpecClasses, 16, null, 128); // no oid
public static final EncryptionAlgorithm
- AES_192_ECB = new EncryptionAlgorithm(CKM_AES_ECB, Alg.AES, Mode.ECB,
+ AES_192_ECB = new EncryptionAlgorithm(SEC_OID_AES_192_ECB,
+ Alg.AES, Mode.ECB,
Padding.NONE, (Class)null, 16, AES_ROOT_OID.subBranch(21), 192);
public static final EncryptionAlgorithm
- AES_192_CBC = new EncryptionAlgorithm(CKM_AES_CBC, Alg.AES, Mode.CBC,
+ AES_192_CBC = new EncryptionAlgorithm(SEC_OID_AES_192_CBC,
+ Alg.AES, Mode.CBC,
Padding.NONE, IVParameterSpecClasses, 16,
AES_ROOT_OID.subBranch(22), 192);
@@ -374,11 +378,13 @@
Padding.PKCS5, IVParameterSpecClasses, 16, null, 192); // no oid
public static final EncryptionAlgorithm
- AES_256_ECB = new EncryptionAlgorithm(CKM_AES_ECB, Alg.AES, Mode.ECB,
+ AES_256_ECB = new EncryptionAlgorithm(SEC_OID_AES_256_ECB,
+ Alg.AES, Mode.ECB,
Padding.NONE, (Class)null, 16, AES_ROOT_OID.subBranch(41), 256);
public static final EncryptionAlgorithm
- AES_256_CBC = new EncryptionAlgorithm(CKM_AES_CBC, Alg.AES, Mode.CBC,
+ AES_256_CBC = new EncryptionAlgorithm(SEC_OID_AES_256_CBC,
+ Alg.AES, Mode.CBC,
Padding.NONE, IVParameterSpecClasses, 16,
AES_ROOT_OID.subBranch(42), 256);
diff --git a/org/mozilla/jss/pkcs11/PK11Store.c b/org/mozilla/jss/pkcs11/PK11Store.c
--- a/org/mozilla/jss/pkcs11/PK11Store.c
+++ b/org/mozilla/jss/pkcs11/PK11Store.c
@@ -31,6 +31,8 @@
char *data;
} secuPWData;
+SECItem *preparePassword(JNIEnv *env, jobject conv, jobject pwObj);
+
/**********************************************************************
* PK11Store.putSymKeysInVector
*/
@@ -533,103 +535,293 @@
JNIEXPORT jbyteArray JNICALL
-Java_org_mozilla_jss_pkcs11_PK11Store_getEncryptedPrivateKeyInfo
-(JNIEnv *env, jobject this, jobject certObj, jobject algObj,
- jobject pwObj, jint iteration)
+Java_org_mozilla_jss_pkcs11_PK11Store_getEncryptedPrivateKeyInfo(
+ JNIEnv *env,
+ jobject this,
+ jobject conv,
+ jobject pwObj,
+ jobject algObj,
+ jint iterations,
+ jobject key)
+{
+ // initialisations so we can goto finish
+ SECItem *pwItem = NULL;
+ SECKEYEncryptedPrivateKeyInfo *epki = NULL;
+ SECItem epkiItem;
+ epkiItem.data = NULL;
+ epkiItem.len = 0;
-{
- SECKEYEncryptedPrivateKeyInfo *epki = NULL;
- jbyteArray encodedEpki = NULL;
+ PR_ASSERT(env != NULL && this != NULL);
+
+ if (pwObj == NULL || algObj == NULL || key == NULL) {
+ JSS_throw(env, NULL_POINTER_EXCEPTION);
+ goto finish;
+ }
+
+ if (iterations <= 0) {
+ iterations = 2000; // set default iterations
+ }
+
+ // get slot
PK11SlotInfo *slot = NULL;
- SECOidTag algTag;
- jclass passwordClass = NULL;
- jmethodID getByteCopyMethod = NULL;
- jbyteArray pwArray = NULL;
- jbyte* pwchars = NULL;
- SECItem pwItem;
- CERTCertificate *cert = NULL;
- SECItem epkiItem;
-
- epkiItem.data = NULL;
-
- /* get slot */
if( JSS_PK11_getStoreSlotPtr(env, this, &slot) != PR_SUCCESS) {
ASSERT_OUTOFMEM(env);
goto finish;
}
PR_ASSERT(slot!=NULL);
-
- /* get algorithm */
- algTag = JSS_getOidTagFromAlg(env, algObj);
- if( algTag == SEC_OID_UNKNOWN ) {
- JSS_throwMsg(env, NO_SUCH_ALG_EXCEPTION, "Unrecognized PBE algorithm");
+
+ // get algorithm
+ SECOidTag algTag = JSS_getOidTagFromAlg(env, algObj);
+ if (algTag == SEC_OID_UNKNOWN) {
+ JSS_throwMsg(env, NO_SUCH_ALG_EXCEPTION, "Unrecognized algorithm");
goto finish;
}
- /*
- * get password
- */
- passwordClass = (*env)->GetObjectClass(env, pwObj);
- if(passwordClass == NULL) {
- ASSERT_OUTOFMEM(env);
- goto finish;
- }
- getByteCopyMethod = (*env)->GetMethodID(
- env,
- passwordClass,
- PW_GET_BYTE_COPY_NAME,
- PW_GET_BYTE_COPY_SIG);
- if(getByteCopyMethod==NULL) {
+ pwItem = preparePassword(env, conv, pwObj);
+ if (pwItem == NULL) {
ASSERT_OUTOFMEM(env);
goto finish;
}
- pwArray = (*env)->CallObjectMethod( env, pwObj, getByteCopyMethod);
- pwchars = (*env)->GetByteArrayElements(env, pwArray, NULL);
- /* !!! Include the NULL byte or not? */
- pwItem.data = (unsigned char*) pwchars;
- pwItem.len = strlen((const char*)pwchars) + 1;
- /*
- * get cert
- */
- if( JSS_PK11_getCertPtr(env, certObj, &cert) != PR_SUCCESS ) {
- /* exception was thrown */
+ // get key
+ SECKEYPrivateKey *privk;
+ if (JSS_PK11_getPrivKeyPtr(env, key, &privk) != PR_SUCCESS) {
+ PR_ASSERT( (*env)->ExceptionOccurred(env) != NULL);
goto finish;
}
- /*
- * export the epki
- */
- epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algTag, &pwItem,
- cert, iteration, NULL /*wincx*/);
-
+ // export the epki
+ epki = PK11_ExportEncryptedPrivKeyInfo(
+ slot, algTag, pwItem, privk, iterations, NULL /*wincx*/);
- /*
- * DER-encode the epki
- */
- epkiItem.data = NULL;
- epkiItem.len = 0;
- if( SEC_ASN1EncodeItem(NULL, &epkiItem, epki,
- SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate) ) == NULL ) {
- JSS_throwMsg(env, TOKEN_EXCEPTION, "Failed to ASN1-encode "
- "EncryptedPrivateKeyInfo");
+ // DER-encode the epki
+ if (SEC_ASN1EncodeItem(NULL, &epkiItem, epki,
+ SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate)) == NULL) {
+ JSS_throwMsg(
+ env, TOKEN_EXCEPTION,
+ "Failed to ASN1-encode EncryptedPrivateKeyInfo");
goto finish;
}
- /*
- * convert to Java byte array
- */
- encodedEpki = JSS_SECItemToByteArray(env, &epkiItem);
+ // convert to Java byte array
+ jbyteArray encodedEpki = JSS_SECItemToByteArray(env, &epkiItem);
finish:
- if( epki != NULL ) {
+ if (epki != NULL) {
SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE /*freeit*/);
}
- if( pwchars != NULL ) {
- (*env)->ReleaseByteArrayElements(env, pwArray, pwchars, JNI_ABORT);
+ if (epkiItem.data != NULL) {
+ SECITEM_FreeItem(&epkiItem, PR_FALSE /*freeit*/);
}
- if(epkiItem.data != NULL) {
- PR_Free(epkiItem.data);
+ if (pwItem != NULL) {
+ SECITEM_FreeItem(pwItem, PR_TRUE /*freeit*/);
}
return encodedEpki;
}
+
+
+JNIEXPORT void JNICALL
+Java_org_mozilla_jss_pkcs11_PK11Store_importEncryptedPrivateKeyInfo(
+ JNIEnv *env,
+ jobject this,
+ jobject conv,
+ jobject pwObj,
+ jstring nickname,
+ jobject pubKeyObj,
+ jbyteArray epkiBytes)
+{
+ // initialisations so we can goto finish
+ SECItem *epkiItem = NULL;
+ SECKEYEncryptedPrivateKeyInfo *epki = NULL;
+ SECItem *pwItem = NULL;
+ SECItem *spkiItem = NULL;
+ CERTSubjectPublicKeyInfo *spki = NULL;
+ SECKEYPublicKey *pubKey = NULL;
+ const char *nicknameChars = NULL;
+
+ PR_ASSERT(env != NULL && this != NULL);
+
+ if (pwObj == NULL || nickname == NULL || pubKeyObj == NULL) {
+ JSS_throw(env, NULL_POINTER_EXCEPTION);
+ goto finish;
+ }
+
+ // get slot
+ PK11SlotInfo *slot = NULL;
+ if (JSS_PK11_getStoreSlotPtr(env, this, &slot) != PR_SUCCESS) {
+ ASSERT_OUTOFMEM(env);
+ goto finish;
+ }
+ PR_ASSERT(slot != NULL);
+
+ // decode EncryptedPrivateKeyInfo
+ epkiItem = JSS_ByteArrayToSECItem(env, epkiBytes);
+ epki = PR_Calloc(1, sizeof(SECKEYEncryptedPrivateKeyInfo));
+ if (SEC_ASN1DecodeItem(
+ NULL,
+ epki,
+ SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate),
+ epkiItem
+ ) != SECSuccess) {
+ JSS_throwMsg(env, INVALID_DER_EXCEPTION,
+ "Failed to decode EncryptedPrivateKeyInfo");
+ goto finish;
+ }
+
+ pwItem = preparePassword(env, conv, pwObj);
+ if (pwItem == NULL) {
+ ASSERT_OUTOFMEM(env);
+ goto finish;
+ }
+
+ // get public key value
+ jclass pubKeyClass = (*env)->GetObjectClass(env, pubKeyObj);
+ if (pubKeyClass == NULL) {
+ ASSERT_OUTOFMEM(env);
+ goto finish;
+ }
+ jmethodID getEncoded = (*env)->GetMethodID(
+ env, pubKeyClass, "getEncoded", "()[B");
+ if (getEncoded == NULL) {
+ ASSERT_OUTOFMEM(env);
+ goto finish;
+ }
+ jbyteArray spkiBytes = (*env)->CallObjectMethod(
+ env, pubKeyObj, getEncoded);
+ spkiItem = JSS_ByteArrayToSECItem(env, spkiBytes);
+ spki = PR_Calloc(1, sizeof(CERTSubjectPublicKeyInfo));
+ if (SEC_ASN1DecodeItem(
+ NULL,
+ spki,
+ SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate),
+ spkiItem
+ ) != SECSuccess) {
+ JSS_throwMsg(env, INVALID_DER_EXCEPTION,
+ "Failed to decode SubjectPublicKeyInfo");
+ goto finish;
+ }
+
+ pubKey = SECKEY_ExtractPublicKey(spki);
+ if (pubKey == NULL) {
+ JSS_throwMsgPrErr(env, INVALID_DER_EXCEPTION,
+ "Failed to extract public key from SubjectPublicKeyInfo");
+ goto finish;
+ }
+
+ SECItem *pubValue;
+ switch (pubKey->keyType) {
+ case dsaKey:
+ pubValue = &pubKey->u.dsa.publicValue;
+ break;
+ case dhKey:
+ pubValue = &pubKey->u.dh.publicValue;
+ break;
+ case rsaKey:
+ pubValue = &pubKey->u.rsa.modulus;
+ break;
+ case ecKey:
+ pubValue = &pubKey->u.ec.publicValue;
+ break;
+ default:
+ pubValue = NULL;
+ }
+
+ // prepare nickname
+ nicknameChars = (*env)->GetStringUTFChars(env, nickname, NULL);
+ if (nicknameChars == NULL) {
+ ASSERT_OUTOFMEM(env);
+ goto finish;
+ }
+ SECItem nickItem;
+ nickItem.data = nicknameChars;
+ nickItem.len = (*env)->GetStringUTFLength(env, nickname);
+
+ // if keyUsage = 0, defaults to signing and encryption/key agreement.
+ // see pk11akey.c in NSS
+ int keyUsage = 0;
+
+ // perform import
+ SECStatus result = PK11_ImportEncryptedPrivateKeyInfo(
+ slot, epki, pwItem, &nickItem, pubValue,
+ PR_TRUE /* isperm */, PR_TRUE /* isprivate */,
+ pubKey->keyType, keyUsage, NULL /* wincx */);
+ if (result != SECSuccess) {
+ JSS_throwMsg(
+ env, TOKEN_EXCEPTION,
+ "Failed to import EncryptedPrivateKeyInfo to token");
+ goto finish;
+ }
+
+finish:
+ if (epkiItem != NULL) {
+ SECITEM_FreeItem(epkiItem, PR_TRUE /*freeit*/);
+ }
+ if (epki != NULL) {
+ SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE /*freeit*/);
+ }
+ if (spkiItem != NULL) {
+ SECITEM_FreeItem(spkiItem, PR_TRUE /*freeit*/);
+ }
+ if (spki != NULL) {
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ }
+ if (pwItem != NULL) {
+ SECITEM_FreeItem(pwItem, PR_TRUE /*freeit*/);
+ }
+ if (pubKey != NULL) {
+ SECKEY_DestroyPublicKey(pubKey);
+ }
+ if (nicknameChars != NULL) {
+ (*env)->ReleaseStringUTFChars(env, nickname, nicknameChars);
+ }
+}
+
+/* Process the given password through the given PasswordConverter,
+ * returning a new SECItem* on success.
+ *
+ * After use, the caller should free the SECItem:
+ *
+ * SECITEM_FreeItem(pwItem, PR_TRUE).
+ */
+SECItem *preparePassword(JNIEnv *env, jobject conv, jobject pwObj) {
+ jclass passwordClass = (*env)->GetObjectClass(env, pwObj);
+ if (passwordClass == NULL) {
+ ASSERT_OUTOFMEM(env);
+ return NULL;
+ }
+
+ jbyteArray pwBytes;
+
+ if (conv == NULL) {
+ jmethodID getByteCopy = (*env)->GetMethodID(
+ env, passwordClass, PW_GET_BYTE_COPY_NAME, PW_GET_BYTE_COPY_SIG);
+ if (getByteCopy == NULL) {
+ ASSERT_OUTOFMEM(env);
+ return NULL;
+ }
+ pwBytes = (*env)->CallObjectMethod(env, pwObj, getByteCopy);
+ } else {
+ jmethodID getChars = (*env)->GetMethodID(
+ env, passwordClass, "getChars", "()[C");
+ if (getChars == NULL) {
+ ASSERT_OUTOFMEM(env);
+ return NULL;
+ }
+ jcharArray pwChars = (*env)->CallObjectMethod(env, pwObj, getChars);
+
+ jclass convClass = (*env)->GetObjectClass(env, conv);
+ if (conv == NULL) {
+ ASSERT_OUTOFMEM(env);
+ return NULL;
+ }
+ jmethodID convert = (*env)->GetMethodID(
+ env, convClass, "convert", "([C)[B");
+ if (convert == NULL) {
+ ASSERT_OUTOFMEM(env);
+ return NULL;
+ }
+ pwBytes = (*env)->CallObjectMethod(env, conv, convert, pwChars);
+ }
+
+ return JSS_ByteArrayToSECItem(env, pwBytes);
+}
diff --git a/org/mozilla/jss/pkcs11/PK11Store.java b/org/mozilla/jss/pkcs11/PK11Store.java
--- a/org/mozilla/jss/pkcs11/PK11Store.java
+++ b/org/mozilla/jss/pkcs11/PK11Store.java
@@ -4,8 +4,10 @@
package org.mozilla.jss.pkcs11;
+import org.mozilla.jss.CryptoManager;
import org.mozilla.jss.crypto.*;
import org.mozilla.jss.util.*;
+import java.security.PublicKey;
import java.security.cert.CertificateEncodingException;
import java.util.Vector;
@@ -53,8 +55,35 @@
public native void deletePrivateKey(PrivateKey key)
throws NoSuchItemOnTokenException, TokenException;
- public native byte[] getEncryptedPrivateKeyInfo(X509Certificate cert,
- PBEAlgorithm pbeAlg, Password pw, int iteration);
+ public byte[] getEncryptedPrivateKeyInfo(
+ X509Certificate cert,
+ PBEAlgorithm pbeAlg,
+ Password pw,
+ int iteration)
+ throws CryptoManager.NotInitializedException,
+ ObjectNotFoundException, TokenException {
+ return getEncryptedPrivateKeyInfo(
+ null,
+ pw,
+ pbeAlg,
+ iteration,
+ CryptoManager.getInstance().findPrivKeyByCert(cert)
+ );
+ }
+
+ public native byte[] getEncryptedPrivateKeyInfo(
+ KeyGenerator.CharToByteConverter conv,
+ Password pw,
+ Algorithm alg,
+ int n,
+ PrivateKey k);
+
+ public native void importEncryptedPrivateKeyInfo(
+ KeyGenerator.CharToByteConverter conv,
+ Password pw,
+ String nickname,
+ PublicKey pubKey,
+ byte[] epkiBytes);
////////////////////////////////////////////////////////////
// Certs
diff --git a/org/mozilla/jss/util/jss_exceptions.h b/org/mozilla/jss/util/jss_exceptions.h
--- a/org/mozilla/jss/util/jss_exceptions.h
+++ b/org/mozilla/jss/util/jss_exceptions.h
@@ -47,6 +47,8 @@
#define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
+#define INVALID_DER_EXCEPTION "org/mozilla/jss/crypto/InvalidDERException"
+
#define INVALID_NICKNAME_EXCEPTION "org/mozilla/jss/util/InvalidNicknameException"
#define INVALID_KEY_FORMAT_EXCEPTION "org/mozilla/jss/crypto/InvalidKeyFormatException"
# HG changeset patch
# User Fraser Tweedale <ftweedal@redhat.com>
# Date 1493335326 25200
# Thu Apr 27 16:22:06 2017 -0700
# Node ID ead2ea094c98ddc708169c3de411ca8d8883cab8
# Parent c8885dd6787639d74a1c9d634fd289ff17fa6f02
Bug 1359731 - CryptoStore.importPrivateKey enhancements, r=cfu
- Enhance CryptoStore.importPrivateKey to support temporary import, and
- returning the private key to the caller.
- Also remove some validation of the unused keyType argument.
diff --git a/org/mozilla/jss/crypto/CryptoStore.java b/org/mozilla/jss/crypto/CryptoStore.java
--- a/org/mozilla/jss/crypto/CryptoStore.java
+++ b/org/mozilla/jss/crypto/CryptoStore.java
@@ -21,17 +21,30 @@
////////////////////////////////////////////////////////////
/**
- * Imports a raw private key into this token.
+ * Imports a raw private key into this token (permanently).
*
* @param key The private key.
* @exception TokenException If the key cannot be imported to this token.
* @exception KeyAlreadyImportedException If the key already exists on this token.
*/
- public void
+ public PrivateKey
importPrivateKey( byte[] key,
PrivateKey.Type type )
throws TokenException, KeyAlreadyImportedException;
+ /**
+ * Imports a raw private key into this token.
+ *
+ * @param key The private key.
+ * @param temporary Whether the key should be temporary.
+ * @exception TokenException If the key cannot be imported to this token.
+ * @exception KeyAlreadyImportedException If the key already exists on this token.
+ */
+ public PrivateKey
+ importPrivateKey( byte[] key,
+ PrivateKey.Type type, boolean temporary)
+ throws TokenException, KeyAlreadyImportedException;
+
/**
* Returns all private keys stored on this token.
diff --git a/org/mozilla/jss/pkcs11/PK11Store.c b/org/mozilla/jss/pkcs11/PK11Store.c
--- a/org/mozilla/jss/pkcs11/PK11Store.c
+++ b/org/mozilla/jss/pkcs11/PK11Store.c
@@ -429,22 +429,22 @@
int PK11_NumberObjectsFor(PK11SlotInfo*, CK_ATTRIBUTE*, int);
/***********************************************************************
- * importPrivateKey
+ * PK11Store.importdPrivateKey
*/
-static void
-importPrivateKey
+JNIEXPORT jobject JNICALL
+Java_org_mozilla_jss_pkcs11_PK11Store_importPrivateKey
( JNIEnv *env,
jobject this,
jbyteArray keyArray,
jobject keyTypeObj,
- PRBool temporary )
+ jboolean temporary )
{
SECItem derPK;
PK11SlotInfo *slot;
jthrowable excep;
- KeyType keyType;
SECStatus status;
SECItem nickname;
+ jobject privkObj = NULL;
/*
* initialize so we can goto finish
@@ -452,13 +452,6 @@
derPK.data = NULL;
derPK.len = 0;
-
- keyType = JSS_PK11_getKeyType(env, keyTypeObj);
- if( keyType == nullKey ) {
- /* exception was thrown */
- goto finish;
- }
-
PR_ASSERT(env!=NULL && this!=NULL);
if(keyArray == NULL) {
@@ -492,14 +485,22 @@
nickname.len = 0;
nickname.data = NULL;
- status = PK11_ImportDERPrivateKeyInfo(slot, &derPK, &nickname,
- NULL /*public value*/, PR_TRUE /*isPerm*/,
- PR_TRUE /*isPrivate*/, 0 /*keyUsage*/, NULL /*wincx*/);
+ SECKEYPrivateKey *privk = NULL;
+ status = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot, &derPK, &nickname,
+ NULL /*public value*/, !temporary /*isPerm*/,
+ PR_TRUE /*isPrivate*/, 0 /*keyUsage*/,
+ &privk, NULL /*wincx*/);
if(status != SECSuccess) {
JSS_throwMsg(env, TOKEN_EXCEPTION, "Failed to import private key info");
goto finish;
}
+ privkObj = JSS_PK11_wrapPrivKey(env, &privk);
+ if (privkObj == NULL) {
+ goto finish;
+ }
+
finish:
/* Save any exceptions */
if( (excep=(*env)->ExceptionOccurred(env)) ) {
@@ -515,24 +516,11 @@
if( excep ) {
(*env)->Throw(env, excep);
}
+ return privkObj;
}
extern const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[];
-/***********************************************************************
- * PK11Store.importdPrivateKey
- */
-JNIEXPORT void JNICALL
-Java_org_mozilla_jss_pkcs11_PK11Store_importPrivateKey
- ( JNIEnv *env,
- jobject this,
- jbyteArray keyArray,
- jobject keyTypeObj )
-{
- importPrivateKey(env, this, keyArray,
- keyTypeObj, PR_FALSE /* not temporary */);
-}
-
JNIEXPORT jbyteArray JNICALL
Java_org_mozilla_jss_pkcs11_PK11Store_getEncryptedPrivateKeyInfo(
diff --git a/org/mozilla/jss/pkcs11/PK11Store.java b/org/mozilla/jss/pkcs11/PK11Store.java
--- a/org/mozilla/jss/pkcs11/PK11Store.java
+++ b/org/mozilla/jss/pkcs11/PK11Store.java
@@ -23,9 +23,15 @@
* @exception TokenException If the key cannot be imported to this token.
* @exception KeyAlreadyImportedException If the key already on this token.
*/
- public native void
- importPrivateKey( byte[] key,
- PrivateKey.Type type )
+ public PrivateKey
+ importPrivateKey(byte[] key, PrivateKey.Type type)
+ throws TokenException,KeyAlreadyImportedException {
+ return importPrivateKey(key, type, false);
+ }
+
+ public native PrivateKey
+ importPrivateKey(
+ byte[] key, PrivateKey.Type type, boolean temporary)
throws TokenException,KeyAlreadyImportedException;
public synchronized PrivateKey[]
# HG changeset patch
# User Matthew Harmsen <mharmsen@redhat.com>
# Date 1493389838 25200
# Fri Apr 28 07:30:38 2017 -0700
# Node ID 4ee5af07d6d8fd7efe60d130d3e7593f6e12e642
# Parent ead2ea094c98ddc708169c3de411ca8d8883cab8
Bug 1352476 - RFE: Document on the README how to create a release tag, r=emaldona
diff --git a/README b/README
--- a/README
+++ b/README
@@ -158,7 +158,40 @@
be necessary.
-(7) Known Issues
+(7) Tagging the Source Code for a Release
+
+ During development, several releases may be made. Consequently, it is
+ good practice to create a "regular tag" to the source code at these
+ various points in time using the following format:
+
+ # hg tag -m "message" JSS_<major>_<minor>_YYYYMMDD
+
+ where: <major> = JSS Major Version Number
+ <minor> = JSS Minor Version Number
+ YYYY = 4-digit year (e. g. - 2017)
+ MM = 2-digit month (e. g. - 01, ..., 12)
+ DD = 2-digit day of the month (e. g. - 01, ..., 31)
+
+ For example:
+
+ # hg id
+ b3e864205ff0+ tip
+
+ # hg tag -m "Added tag JSS_4_4_20170328 for changeset b3e864205ff0" JSS_4_4_20170328
+
+ At the appropriate time, a new major.minor version may be created. At this
+ time, it is important to create a maintenance branch for any future changes
+ to the previous major.minor version:
+
+ For example:
+
+ # hg id
+ f00f00f00f00+ tip
+
+ # hg branch -m "Created branch JSS_4_4_BRANCH for changeset f00f00f00f00" JSS_4_4_BRANCH
+
+
+(8) Known Issues
* Mozilla Bug #1346410 - Load JSS libraries appropriately