diff --git a/SOURCES/jss-Fixed-build-failures.patch b/SOURCES/jss-Fixed-build-failures.patch
new file mode 100644
index 0000000..af11010
--- /dev/null
+++ b/SOURCES/jss-Fixed-build-failures.patch
@@ -0,0 +1,349 @@
+From 22092d1bde94dc8a1f6e8198fa2fcc597c36c32f Mon Sep 17 00:00:00 2001
+From: "Endi S. Dewata" <edewata@redhat.com>
+Date: Wed, 9 Dec 2015 00:30:50 +0100
+Subject: [PATCH] Fixed build failures.
+
+The Javadoc on various classes have been modified to fix build
+failures on F23 and Rawhide due to stringent requirements on
+those platforms.
+
+The Debug_debug.jnot has been renamed to Debug.java to fix build
+failure in Eclipse.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1289799
+---
+ .classpath                                              |  7 +++++++
+ .project                                                | 17 +++++++++++++++++
+ mozilla/security/jss/build_java.pl                      |  2 +-
+ mozilla/security/jss/org/mozilla/jss/CryptoManager.java | 14 +++++++-------
+ .../security/jss/org/mozilla/jss/asn1/ASN1Header.java   |  2 +-
+ .../security/jss/org/mozilla/jss/pkcs11/PK11Token.java  |  2 +-
+ .../security/jss/org/mozilla/jss/pkcs12/CertBag.java    |  1 +
+ .../security/jss/org/mozilla/jss/pkcs7/ContentInfo.java |  1 -
+ .../security/jss/org/mozilla/jss/pkcs7/SignerInfo.java  | 17 ++++++++++-------
+ .../jss/org/mozilla/jss/pkix/cms/ContentInfo.java       |  1 -
+ .../jss/org/mozilla/jss/pkix/cms/SignerInfo.java        | 17 ++++++++++-------
+ .../jss/org/mozilla/jss/pkix/crmf/CertReqMsg.java       |  2 +-
+ .../jss/org/mozilla/jss/ssl/SSLServerSocket.java        |  3 ---
+ .../mozilla/jss/util/{Debug_debug.jnot => Debug.java}   |  0
+ 14 files changed, 56 insertions(+), 30 deletions(-)
+ create mode 100644 .classpath
+ create mode 100644 .project
+ rename mozilla/security/jss/org/mozilla/jss/util/{Debug_debug.jnot => Debug.java} (100%)
+
+diff --git a/.classpath b/.classpath
+new file mode 100644
+index 0000000000000000000000000000000000000000..df092d3f7d8df936b753bea75c11bf4003e1a77f
+--- /dev/null
++++ b/.classpath
+@@ -0,0 +1,7 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<classpath>
++	<classpathentry excluding="samples/" kind="src" path="mozilla/security/jss"/>
++	<classpathentry kind="src" path="mozilla/security/jss/samples"/>
++	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
++	<classpathentry kind="output" path="bin"/>
++</classpath>
+diff --git a/.project b/.project
+new file mode 100644
+index 0000000000000000000000000000000000000000..c0b616e95c7512076c9976374bda14e11d7cdd8c
+--- /dev/null
++++ b/.project
+@@ -0,0 +1,17 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<projectDescription>
++	<name>jss-4.2</name>
++	<comment></comment>
++	<projects>
++	</projects>
++	<buildSpec>
++		<buildCommand>
++			<name>org.eclipse.jdt.core.javabuilder</name>
++			<arguments>
++			</arguments>
++		</buildCommand>
++	</buildSpec>
++	<natures>
++		<nature>org.eclipse.jdt.core.javanature</nature>
++	</natures>
++</projectDescription>
+diff --git a/mozilla/security/jss/build_java.pl b/mozilla/security/jss/build_java.pl
+index c34473e0eec883323b6b100e671018a9edafe442..379a5e05dbc0599c95d2228bd14f659d3e493d0b 100644
+--- a/mozilla/security/jss/build_java.pl
++++ b/mozilla/security/jss/build_java.pl
+@@ -137,7 +137,7 @@ sub setup_vars {
+         $class_jar = "$dist_dir/$cmdline_vars{XPCLASS_DBG_JAR}";
+         $class_release_dir .= "/$cmdline_vars{SOURCE_RELEASE_CLASSES_DBG_DIR}";
+         $javac_opt_flag = "-g";
+-        $debug_source_file = "org/mozilla/jss/util/Debug_debug.jnot";
++        $debug_source_file = "org/mozilla/jss/util/Debug.java";
+     }
+     $jni_header_dir = "$dist_dir/private/jss/_jni";
+ 
+diff --git a/mozilla/security/jss/org/mozilla/jss/CryptoManager.java b/mozilla/security/jss/org/mozilla/jss/CryptoManager.java
+index 08aad8fe3c3a62ae8e233fc1035723690adf4581..6ef0256a3b777db48461f19da0fa64ec7857ed6b 100644
+--- a/mozilla/security/jss/org/mozilla/jss/CryptoManager.java
++++ b/mozilla/security/jss/org/mozilla/jss/CryptoManager.java
+@@ -600,7 +600,7 @@ public final class CryptoManager implements TokenSupplier
+      * loaded cryptographic modules for the token.
+      *
+      * @param name The name of the token.
+-     * @exception org.mozilla.jss.crypto.NoSuchTokenException If no token
++     * @exception NoSuchTokenException If no token
+      *  is found with the given name.
+      */
+     public synchronized CryptoToken getTokenByName(String name)
+@@ -855,9 +855,9 @@ public final class CryptoManager implements TokenSupplier
+      * <code>initialize()</code>.
+      *
+      * @param configDir The directory containing the security databases.
+-     * @exception org.mozilla.jss.util.KeyDatabaseException Unable to open
++     * @exception KeyDatabaseException Unable to open
+      *  the key database, or it was currupted.
+-     * @exception org.mozilla.jss.util.CertDatabaseException Unable
++     * @exception CertDatabaseException Unable
+      *  to open the certificate database, or it was currupted.
+      **/
+     public static synchronized void initialize( String configDir )
+@@ -878,9 +878,9 @@ public final class CryptoManager implements TokenSupplier
+      * <code>initialize()</code>.
+      *
+      * @param values The options with which to initialize CryptoManager.
+-     * @exception org.mozilla.jss.util.KeyDatabaseException Unable to open
++     * @exception KeyDatabaseException Unable to open
+      *  the key database, or it was currupted.
+-     * @exception org.mozilla.jss.util.CertDatabaseException Unable
++     * @exception CertDatabaseException Unable
+      *  to open the certificate database, or it was currupted.
+      **/
+     public static synchronized void initialize( InitializationValues values )
+@@ -1021,7 +1021,7 @@ public final class CryptoManager implements TokenSupplier
+      * @return The leaf certificate from the chain.
+      * @exception CertificateEncodingException If the package encoding
+      *      was not recognized.
+-     * @exception CertificateNicknameConflictException If the leaf certificate
++     * @exception NicknameConflictException If the leaf certificate
+      *      is a user certificate, and another certificate already has the
+      *      given nickname.
+      * @exception UserCertConflictException If the leaf certificate
+@@ -1059,7 +1059,7 @@ public final class CryptoManager implements TokenSupplier
+      * @return The leaf certificate from the chain.
+      * @exception CertificateEncodingException If the package encoding
+      *      was not recognized.
+-     * @exception CertificateNicknameConflictException If the leaf certificate
++     * @exception NicknameConflictException If the leaf certificate
+      *      another certificate already has the given nickname.
+      * @exception UserCertConflictException If the leaf certificate
+      *      has already been imported.
+diff --git a/mozilla/security/jss/org/mozilla/jss/asn1/ASN1Header.java b/mozilla/security/jss/org/mozilla/jss/asn1/ASN1Header.java
+index bfa37c9f5eba1c5df9bb275cad16c1bf57c9c65d..d15be4922b52d16a25e3212b2b25809cd7ddf3b6 100644
+--- a/mozilla/security/jss/org/mozilla/jss/asn1/ASN1Header.java
++++ b/mozilla/security/jss/org/mozilla/jss/asn1/ASN1Header.java
+@@ -259,7 +259,7 @@ public class ASN1Header {
+     /**
+      * This constructor is to be called when we are constructing an ASN1Value
+      * rather than decoding it.
+-     * @param contentLength Must be >=0. Although indefinite length
++     * @param contentLength Must be &gt;=0. Although indefinite length
+      *      <i>decoding</i> is supported, indefinite length <i>encoding</i>
+      *      is not.
+      */
+diff --git a/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java b/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java
+index e521b6108b90daeb7035413bba50a41e9b20ec49..98e93f0e858b09402364b4dc89c36a63e7ef0f7b 100644
+--- a/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java
++++ b/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java
+@@ -236,7 +236,7 @@ public final class PK11Token implements CryptoToken {
+      *
+      * @param ssopwcb The security officer's current password callback.
+      * @param userpwcb The user's new password callback.
+-     * @exception IncorrectPinException If the security officer PIN is
++     * @exception IncorrectPasswordException If the security officer PIN is
+      *  incorrect.
+      * @exception TokenException If the PIN was already initialized,
+      *  or there was an unspecified error in the token.
+diff --git a/mozilla/security/jss/org/mozilla/jss/pkcs12/CertBag.java b/mozilla/security/jss/org/mozilla/jss/pkcs12/CertBag.java
+index a1b08d2e9ee9dfcb4ee809e101f3074611664384..61ad979d65d5ecc6659281218c58e8ec9a48211c 100644
+--- a/mozilla/security/jss/org/mozilla/jss/pkcs12/CertBag.java
++++ b/mozilla/security/jss/org/mozilla/jss/pkcs12/CertBag.java
+@@ -91,6 +91,7 @@ public class CertBag implements ASN1Value {
+      * <li>If the type is <code>SDSI_CERT_TYPE</code>, returns
+      *      an IA5String.
+      * <li>For all other types, returns an ANY.
++     * </ul>
+      *
+      * @exception InvalidBERException If the cert is not encoded correctly.
+      */
+diff --git a/mozilla/security/jss/org/mozilla/jss/pkcs7/ContentInfo.java b/mozilla/security/jss/org/mozilla/jss/pkcs7/ContentInfo.java
+index 4db7a42c75cc21d71841e20dcb9a4c1494ff08c2..4578e9bcd8abdb4e7b6717b07aee932dd887d675 100644
+--- a/mozilla/security/jss/org/mozilla/jss/pkcs7/ContentInfo.java
++++ b/mozilla/security/jss/org/mozilla/jss/pkcs7/ContentInfo.java
+@@ -169,7 +169,6 @@ public class ContentInfo implements ASN1Value {
+      *  an OCTET_STRING will be returned.
+      * <p>If the contentType is <b>not</b> one of the six standard types,
+      *      the returned object will be an ANY.
+-     * </ul>
+      */
+     public ASN1Value getInterpretedContent() throws InvalidBERException {
+         if(contentType.equals(DATA)) {
+diff --git a/mozilla/security/jss/org/mozilla/jss/pkcs7/SignerInfo.java b/mozilla/security/jss/org/mozilla/jss/pkcs7/SignerInfo.java
+index 300e993cffd9dcadaf996609abeebf8627eafde8..c49107c80543ec94fbb3117a1a9a1088f851a6b3 100644
+--- a/mozilla/security/jss/org/mozilla/jss/pkcs7/SignerInfo.java
++++ b/mozilla/security/jss/org/mozilla/jss/pkcs7/SignerInfo.java
+@@ -129,7 +129,7 @@ public class SignerInfo implements ASN1Value {
+     /**
+      * Retrieves the DigestAlgorithm used in this SignerInfo.
+      *
+-     * @exception NoSuchAlgorithm If the algorithm is not recognized by JSS.
++     * @exception NoSuchAlgorithmException If the algorithm is not recognized by JSS.
+      */
+     public DigestAlgorithm getDigestAlgorithm()
+         throws NoSuchAlgorithmException
+@@ -402,10 +402,12 @@ public class SignerInfo implements ASN1Value {
+     /**
+      * Verifies that this SignerInfo contains a valid signature of the
+      * given message digest.  If any authenticated attributes are present,
+-     * they are also validated. The verification algorithm is as follows:<ul>
+-     * <p>Note that this does <b>not</b> verify the validity of the
+-     *  the certificate itself, only the signature.
++     * they are also validated. The verification algorithm is as follows:
+      *
++     * Note that this does <b>not</b> verify the validity of the
++     * the certificate itself, only the signature.
++     *
++     * <ul>
+      * <li>If no authenticated attributes are present, the content type is 
+      *  verified to be <i>data</i>. Then it is verified that the message
+      *  digest passed
+@@ -413,24 +415,25 @@ public class SignerInfo implements ASN1Value {
+      *  digest in the SignerInfo.
+      *
+      * <li>If authenticated attributes are present,
+-     *  two particular attributes must be present: <ul>
++     *  two particular attributes must be present:
++     * <ul>
+      *  <li>PKCS #9 Content-Type, the type of content that is being signed.
+      *      This must match the contentType parameter.
+      *  <li>PKCS #9 Message-Digest, the digest of the content that is being
+      *      signed. This must match the messageDigest parameter.
+      * </ul>
++     *
+      * After these two attributes are verified to be both present and correct,
+      * the encryptedDigest field of the SignerInfo is verified to be the
+      * signature of the contents octets of the DER encoding of the
+      * authenticatedAttributes field.
+-     *
+      * </ul>
+      *
+      * @param messageDigest The hash of the content that is signed by this
+      *  SignerInfo.
+      * @param contentType The type of the content that is signed by this
+      *  SignerInfo.
+-     * @exception NoSuchObjectException If no certificate matching the
++     * @exception ObjectNotFoundException If no certificate matching the
+      *      the issuer name and serial number can be found.
+      */
+     public void verify(byte[] messageDigest, OBJECT_IDENTIFIER contentType)
+diff --git a/mozilla/security/jss/org/mozilla/jss/pkix/cms/ContentInfo.java b/mozilla/security/jss/org/mozilla/jss/pkix/cms/ContentInfo.java
+index 91ae770c94b3a8817c13e4cb86609c432ef682b8..9f61e605b416dffc38525ccec4dcce9f380c7dcc 100644
+--- a/mozilla/security/jss/org/mozilla/jss/pkix/cms/ContentInfo.java
++++ b/mozilla/security/jss/org/mozilla/jss/pkix/cms/ContentInfo.java
+@@ -168,7 +168,6 @@ public class ContentInfo implements ASN1Value {
+      *  an OCTET_STRING will be returned.
+      * <p>If the contentType is <b>not</b> one of the six standard types,
+      *      the returned object will be an ANY.
+-     * </ul>
+      */
+     public ASN1Value getInterpretedContent() throws InvalidBERException {
+         if(contentType.equals(DATA)) {
+diff --git a/mozilla/security/jss/org/mozilla/jss/pkix/cms/SignerInfo.java b/mozilla/security/jss/org/mozilla/jss/pkix/cms/SignerInfo.java
+index ff34a554e4d5f43b6ce18acfac01899858d62117..e7feb934dc0a78fbc40a6ff7d8db87f0af9177fe 100644
+--- a/mozilla/security/jss/org/mozilla/jss/pkix/cms/SignerInfo.java
++++ b/mozilla/security/jss/org/mozilla/jss/pkix/cms/SignerInfo.java
+@@ -130,7 +130,7 @@ public class SignerInfo implements ASN1Value {
+     /**
+      * Retrieves the DigestAlgorithm used in this SignerInfo.
+      *
+-     * @exception NoSuchAlgorithm If the algorithm is not recognized by JSS.
++     * @exception NoSuchAlgorithmException If the algorithm is not recognized by JSS.
+      */
+     public DigestAlgorithm getDigestAlgorithm()
+         throws NoSuchAlgorithmException
+@@ -403,10 +403,12 @@ public class SignerInfo implements ASN1Value {
+     /**
+      * Verifies that this SignerInfo contains a valid signature of the
+      * given message digest.  If any signed attributes are present,
+-     * they are also validated. The verification algorithm is as follows:<ul>
+-     * <p>Note that this does <b>not</b> verify the validity of the
+-     *  the certificate itself, only the signature.
++     * they are also validated. The verification algorithm is as follows:
+      *
++     * Note that this does <b>not</b> verify the validity of the
++     * the certificate itself, only the signature.
++     *
++     * <ul>
+      * <li>If no signed attributes are present, the content type is 
+      *  verified to be <i>data</i>. Then it is verified that the message
+      *  digest passed
+@@ -414,24 +416,25 @@ public class SignerInfo implements ASN1Value {
+      *  digest in the SignerInfo.
+      *
+      * <li>If signed attributes are present,
+-     *  two particular attributes must be present: <ul>
++     *  two particular attributes must be present:
++     * <ul>
+      *  <li>PKCS #9 Content-Type, the type of content that is being signed.
+      *      This must match the contentType parameter.
+      *  <li>PKCS #9 Message-Digest, the digest of the content that is being
+      *      signed. This must match the messageDigest parameter.
+      * </ul>
++     *
+      * After these two attributes are verified to be both present and correct,
+      * the encryptedDigest field of the SignerInfo is verified to be the
+      * signature of the contents octets of the DER encoding of the
+      * signedAttributes field.
+-     *
+      * </ul>
+      *
+      * @param messageDigest The hash of the content that is signed by this
+      *  SignerInfo.
+      * @param contentType The type of the content that is signed by this
+      *  SignerInfo.
+-     * @exception NoSuchObjectException If no certificate matching the
++     * @exception ObjectNotFoundException If no certificate matching the
+      *      the issuer name and serial number can be found.
+      */
+     public void verify(byte[] messageDigest, OBJECT_IDENTIFIER contentType)
+diff --git a/mozilla/security/jss/org/mozilla/jss/pkix/crmf/CertReqMsg.java b/mozilla/security/jss/org/mozilla/jss/pkix/crmf/CertReqMsg.java
+index 53d162b69673caeed3e998dc9c2e221b95dfc6db..c6637039c87043f36dd1a1e449a819edbcc816e3 100644
+--- a/mozilla/security/jss/org/mozilla/jss/pkix/crmf/CertReqMsg.java
++++ b/mozilla/security/jss/org/mozilla/jss/pkix/crmf/CertReqMsg.java
+@@ -112,7 +112,7 @@ public class CertReqMsg implements ASN1Value {
+ 
+     /**
+      * Constructs a <i>CertReqmsg</i> from a <i>CertRequest</i> and, optionally,
+-     * a <i>pop>/i> and a <i>regInfo</i>.
++     * a <i>pop</i> and a <i>regInfo</i>.
+      * @param pop May be NULL.
+      * @param regInfo May be NULL.
+      */
+diff --git a/mozilla/security/jss/org/mozilla/jss/ssl/SSLServerSocket.java b/mozilla/security/jss/org/mozilla/jss/ssl/SSLServerSocket.java
+index 2043a598cf3e8d023287c0f7142045c1e4f68e4d..58d14496e5ad92aa91a966e119e14f470da4fd4a 100644
+--- a/mozilla/security/jss/org/mozilla/jss/ssl/SSLServerSocket.java
++++ b/mozilla/security/jss/org/mozilla/jss/ssl/SSLServerSocket.java
+@@ -174,9 +174,6 @@ public class SSLServerSocket extends java.net.ServerSocket {
+      * @return java.net.Socket Local socket for client communication
+      *
+      * @throws IOException  If an input or output exception occurred
+-     * @throws SocketTimeoutException  If the socket timesout trying to connect
+-     * @throws InterruptedIOException  If an input or output is interrupted
+-     * @throws SSLSocketException  JSS subclass of java.net.SocketException
+      */
+     public Socket accept() throws IOException {
+         synchronized (acceptLock) {
+diff --git a/mozilla/security/jss/org/mozilla/jss/util/Debug_debug.jnot b/mozilla/security/jss/org/mozilla/jss/util/Debug.java
+similarity index 100%
+rename from mozilla/security/jss/org/mozilla/jss/util/Debug_debug.jnot
+rename to mozilla/security/jss/org/mozilla/jss/util/Debug.java
+-- 
+2.4.3
+
diff --git a/SOURCES/jss-VerifyCertificate-enhancement.patch b/SOURCES/jss-VerifyCertificate-enhancement.patch
new file mode 100644
index 0000000..6582b41
--- /dev/null
+++ b/SOURCES/jss-VerifyCertificate-enhancement.patch
@@ -0,0 +1,204 @@
+From 3c4ca8a2010889fe292704ebcc8b922f77f2f7c2 Mon Sep 17 00:00:00 2001
+From: "Endi S. Dewata" <edewata@redhat.com>
+Date: Wed, 9 Dec 2015 00:30:50 +0100
+Subject: [PATCH] Added verifyCertificate() method.
+
+A new CryptoManager.verifyCertificate() method has been added as
+an alternative to isCertValid(). If there is a certificate
+validation problem, the method will throw a CertificateValidation
+exception that contains the NSS error message and code. The
+exception will also provide a stack trace to help troubleshoot
+validation issues.
+
+https://fedorahosted.org/pki/ticket/850
+---
+ .../jss/org/mozilla/jss/CryptoManager.java         | 54 ++++++++------
+ mozilla/security/jss/org/mozilla/jss/PK11Finder.c  | 83 +++++++++++++++++++---
+ .../jss/org/mozilla/jss/util/jss_exceptions.h      |  2 +
+ 3 files changed, 110 insertions(+), 29 deletions(-)
+
+diff --git a/mozilla/security/jss/org/mozilla/jss/CryptoManager.java b/mozilla/security/jss/org/mozilla/jss/CryptoManager.java
+index 0a4f59064bfddb42d473022550c24f251719d02b..54ffd8130b0e1f1fca49dd8b130a621e449c7ce7 100644
+--- a/mozilla/security/jss/org/mozilla/jss/CryptoManager.java
++++ b/mozilla/security/jss/org/mozilla/jss/CryptoManager.java
+@@ -1515,30 +1515,44 @@ public final class CryptoManager implements TokenSupplier
+             CertificateUsage certificateUsage)
+         throws ObjectNotFoundException, InvalidNicknameException
+     {
+-        if (nickname==null) {
+-            throw new InvalidNicknameException("Nickname must be non-null");
+-        }
+-        // 0 certificate usage will get current usage
+-        // should call isCertValid() call above that returns certificate usage
+-        if ((certificateUsage == null) ||
+-                (certificateUsage == CertificateUsage.CheckAllUsages)){
+-            int currCertificateUsage = 0x0000;
+-            currCertificateUsage = verifyCertificateNowCUNative(nickname,
+-                checkSig);
++        try {
++            verifyCertificate(nickname, checkSig, certificateUsage);
++            return true;
++
++        } catch (ObjectNotFoundException | InvalidNicknameException e) {
++            throw e;
+ 
+-            if (currCertificateUsage == CertificateUsage.basicCertificateUsages){ 
+-                // cert is good for nothing
+-                return false;
+-            } else
+-                return true;
+-        } else {
+-            return verifyCertificateNowNative(nickname, checkSig,
+-              certificateUsage.getUsage());
++        } catch (CertificateException e) {
++            return false;
+         }
+     }
+ 
+-    private native boolean verifyCertificateNowNative(String nickname,
+-        boolean checkSig, int certificateUsage) throws ObjectNotFoundException;
++    /**
++     * Verify a certificate that exists in the given cert database,
++     * check if it's valid and that we trust the issuer. Verify time
++     * against now.
++     * @param nickname nickname of the certificate to verify.
++     * @param checkSig verify the signature of the certificate
++     * @param certificateUsage see certificate usage defined to verify certificate
++     *
++     * @exception InvalidNicknameException If the nickname is null.
++     * @exception ObjectNotFoundException If no certificate could be found
++     *      with the given nickname.
++     * @exception CertificateException If certificate is invalid.
++     */
++    public void verifyCertificate(String nickname,
++            boolean checkSig,
++            CertificateUsage certificateUsage)
++                    throws ObjectNotFoundException, InvalidNicknameException, CertificateException {
++        int usage = certificateUsage == null ? 0 : certificateUsage.getUsage();
++        verifyCertificateNowNative(nickname, checkSig, usage);
++    }
++
++    private native void verifyCertificateNowNative(
++            String nickname,
++            boolean checkSig,
++            int certificateUsage)
++                    throws ObjectNotFoundException, InvalidNicknameException, CertificateException;
+ 
+     /**
+      * note: this method calls obsolete function in NSS
+diff --git a/mozilla/security/jss/org/mozilla/jss/PK11Finder.c b/mozilla/security/jss/org/mozilla/jss/PK11Finder.c
+index 8c7f0b4c05b58527a41cac140dbb5dc30578570f..4986478ffc860e145cd31e41c2880fcc2b5e007e 100644
+--- a/mozilla/security/jss/org/mozilla/jss/PK11Finder.c
++++ b/mozilla/security/jss/org/mozilla/jss/PK11Finder.c
+@@ -1667,21 +1667,86 @@ Java_org_mozilla_jss_CryptoManager_verifyCertificateNowCUNative(JNIEnv *env,
+ /***********************************************************************
+  * CryptoManager.verifyCertificateNowNative
+  *
+- * Returns JNI_TRUE if success, JNI_FALSE otherwise
++ * Verify a certificate that exists in the given cert database,
++ * check if it's valid and that we trust the issuer. Verify time
++ * against now.
++ * @param nickname nickname of the certificate to verify.
++ * @param checkSig verify the signature of the certificate
++ * @param certificateUsage see certificate usage defined to verify certificate
++ *
++ * @exception InvalidNicknameException If the nickname is null.
++ * @exception ObjectNotFoundException If no certificate could be found
++ *      with the given nickname.
++ * @exception CertificateException If certificate is invalid.
+  */
+-JNIEXPORT jboolean JNICALL
++JNIEXPORT void JNICALL
+ Java_org_mozilla_jss_CryptoManager_verifyCertificateNowNative(JNIEnv *env,
+-        jobject self, jstring nickString, jboolean checkSig, jint required_certificateUsage)
++        jobject self, jstring nickString, jboolean checkSig, jint certificateUsage)
+ {
+-    SECStatus         rv    = SECFailure;
+     SECCertificateUsage      currUsage = 0x0000;
++    SECStatus                rv = SECFailure;
++    CERTCertificate          *cert = NULL;
++    char                     *nickname = NULL;
+ 
+-    rv = verifyCertificateNow(env, self, nickString, checkSig, required_certificateUsage, &currUsage);
++    if (nickString == NULL) {
++        JSS_throwMsg(env, INVALID_NICKNAME_EXCEPTION, "Missing certificate nickname");
++        goto finish;
++    }
+ 
+-    if( rv == SECSuccess) {
+-        return JNI_TRUE;
+-    } else {
+-        return JNI_FALSE;
++    nickname = (char *) (*env)->GetStringUTFChars(env, nickString, NULL);
++
++    if (nickname == NULL) {
++        JSS_throwMsg(env, INVALID_NICKNAME_EXCEPTION, "Missing certificate nickname");
++        goto finish;
++    }
++
++    cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), nickname);
++
++    if (cert == NULL) {
++        char *msgBuf;
++        msgBuf = PR_smprintf("Certificate not found: %s", nickname);
++        JSS_throwMsg(env, OBJECT_NOT_FOUND_EXCEPTION, msgBuf);
++        PR_Free(msgBuf);
++        goto finish;
++    }
++
++    /* 0 for certificateUsage in call to CERT_VerifyCertificateNow will
++     * retrieve the current valid usage into currUsage
++     */
++    rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert,
++        checkSig, certificateUsage, NULL, &currUsage);
++
++    if (rv != SECSuccess) {
++        JSS_throwMsgPrErr(env, CERTIFICATE_EXCEPTION, "Invalid certificate");
++        goto finish;
++    }
++
++    if ((certificateUsage == 0x0000) &&
++        (currUsage ==
++            ( certUsageUserCertImport |
++            certUsageVerifyCA |
++            certUsageProtectedObjectSigner |
++            certUsageAnyCA ))) {
++
++        /* The certificate is good for nothing.
++         * The following usages cannot be verified:
++         *   certUsageAnyCA
++         *   certUsageProtectedObjectSigner
++         *   certUsageUserCertImport
++         *   certUsageVerifyCA
++         *   (0x0b80)
++         */
++
++        JSS_throwMsgPrErr(env, CERTIFICATE_EXCEPTION, "Unusable certificate");
++        goto finish;
++    }
++
++finish:
++    if (nickname != NULL) {
++        (*env)->ReleaseStringUTFChars(env, nickString, nickname);
++    }
++    if (cert != NULL) {
++        CERT_DestroyCertificate(cert);
+     }
+ }
+ 
+diff --git a/mozilla/security/jss/org/mozilla/jss/util/jss_exceptions.h b/mozilla/security/jss/org/mozilla/jss/util/jss_exceptions.h
+index 4884928306223ff0699a22e7da33e3d13a904d39..acd329a4ecd3592ebe1d72c7bdac435d84dcae99 100644
+--- a/mozilla/security/jss/org/mozilla/jss/util/jss_exceptions.h
++++ b/mozilla/security/jss/org/mozilla/jss/util/jss_exceptions.h
+@@ -79,6 +79,8 @@ PR_BEGIN_EXTERN_C
+ 
+ #define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
+ 
++#define INVALID_NICKNAME_EXCEPTION "org/mozilla/jss/util/InvalidNicknameException"
++
+ #define INVALID_KEY_FORMAT_EXCEPTION "org/mozilla/jss/crypto/InvalidKeyFormatException"
+ 
+ #define INVALID_PARAMETER_EXCEPTION "java/security/InvalidParameterException"
+-- 
+2.5.0
+
diff --git a/SOURCES/jss-crmf-envelopedData.patch b/SOURCES/jss-crmf-envelopedData.patch
new file mode 100644
index 0000000..13c21d7
--- /dev/null
+++ b/SOURCES/jss-crmf-envelopedData.patch
@@ -0,0 +1,33 @@
+diff -up jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkix/crmf/EncryptedKey.java.roysjosh jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkix/crmf/EncryptedKey.java
+--- jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkix/crmf/EncryptedKey.java.roysjosh	2016-06-24 14:51:48.929122053 -0700
++++ jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkix/crmf/EncryptedKey.java	2016-06-24 14:52:29.487027005 -0700
+@@ -127,7 +127,8 @@ public class EncryptedKey implements ASN
+         } else {
+             Assert._assert(type == ENVELOPED_DATA);
+             Assert._assert(envelopedData != null);
+-            envelopedData.encode(implicitTag, ostream);
++            EXPLICIT explicit = new EXPLICIT( new Tag(0), envelopedData );
++            explicit.encode(tag, ostream);
+         }
+     }
+ 
+@@ -147,7 +148,9 @@ public class EncryptedKey implements ASN
+             choicet = new CHOICE.Template();
+ 
+             choicet.addElement( EncryptedValue.getTemplate() );
+-            choicet.addElement( new Tag(0), ANY.getTemplate() );
++            choicet.addElement( new EXPLICIT.Template(
++                                        new Tag(0),
++                                        ANY.getTemplate() ));
+         }
+ 
+         public boolean tagMatch(Tag tag) {
+@@ -164,7 +167,7 @@ public class EncryptedKey implements ASN
+                 return new EncryptedKey( (EncryptedValue) choice.getValue() );
+             } else {
+                 Assert._assert( choice.getTag().equals(new Tag(0)) );
+-                return new EncryptedKey( (ANY) choice.getValue() );
++                return new EncryptedKey( (ANY) ((EXPLICIT) choice.getValue()).getContent() );
+             }
+ 
+           } catch(InvalidBERException e) {
diff --git a/SOURCES/jss-lunasaUnwrap.patch b/SOURCES/jss-lunasaUnwrap.patch
new file mode 100644
index 0000000..5021bd6
--- /dev/null
+++ b/SOURCES/jss-lunasaUnwrap.patch
@@ -0,0 +1,12 @@
+diff -up jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c.cfu jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c
+--- jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c.cfu	2016-04-28 16:50:06.000000000 -0700
++++ jss-4.2.6/mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c	2016-04-28 16:50:00.000000000 -0700
+@@ -434,7 +434,7 @@ Java_org_mozilla_jss_pkcs11_PK11KeyWrapp
+         isSensitive = PR_FALSE;
+         isExtractable = PR_FALSE;
+     } else if ( isLunasa) {
+-        isSensitive = PR_FALSE;
++        isSensitive = PR_TRUE;
+         isExtractable = PR_TRUE;
+     }
+ 
diff --git a/SOURCES/jss-symkey-enhancements.patch b/SOURCES/jss-symkey-enhancements.patch
new file mode 100644
index 0000000..248ba76
--- /dev/null
+++ b/SOURCES/jss-symkey-enhancements.patch
@@ -0,0 +1,1855 @@
+diff -up ./mozilla/security/jss/build_java.pl.jmagne ./mozilla/security/jss/build_java.pl
+--- ./mozilla/security/jss/build_java.pl.jmagne	2016-04-14 13:56:16.946920239 -0700
++++ ./mozilla/security/jss/build_java.pl	2016-04-14 14:53:08.501298062 -0700
+@@ -31,7 +31,8 @@ org.mozilla.jss.pkcs11.PK11MessageDigest
+ org.mozilla.jss.pkcs11.PK11PrivKey   
+ org.mozilla.jss.pkcs11.PK11PubKey     
+ org.mozilla.jss.pkcs11.PK11SymKey      
+-org.mozilla.jss.pkcs11.PK11KeyPairGenerator 
++org.mozilla.jss.pkcs11.PK11KeyPairGenerator
++org.mozilla.jss.pkcs11.PK11SymmetricKeyDeriver
+ org.mozilla.jss.pkcs11.PK11KeyGenerator
+ org.mozilla.jss.pkcs11.PK11Token
+ org.mozilla.jss.pkcs11.PrivateKeyProxy  
+diff -up ./mozilla/security/jss/lib/jss.def.jmagne ./mozilla/security/jss/lib/jss.def
+--- ./mozilla/security/jss/lib/jss.def.jmagne	2016-04-14 16:00:06.229534228 -0700
++++ ./mozilla/security/jss/lib/jss.def	2016-04-14 16:00:32.229356314 -0700
+@@ -158,6 +158,7 @@ Java_org_mozilla_jss_pkcs11_PK11Store_de
+ Java_org_mozilla_jss_pkcs11_PK11Store_importPrivateKey;
+ Java_org_mozilla_jss_pkcs11_PK11Store_putCertsInVector;
+ Java_org_mozilla_jss_pkcs11_PK11Store_putKeysInVector;
++Java_org_mozilla_jss_pkcs11_PK11Store_putSymKeysInVector;
+ Java_org_mozilla_jss_pkcs11_SigContextProxy_releaseNativeResources;
+ Java_org_mozilla_jss_pkcs11_PK11RSAPublicKey_getModulusByteArray;
+ Java_org_mozilla_jss_pkcs11_PK11RSAPublicKey_getPublicExponentByteArray;
+@@ -336,6 +337,8 @@ Java_org_mozilla_jss_CryptoManager_verif
+ Java_org_mozilla_jss_asn1_ASN1Util_getTagDescriptionByOid;
+ Java_org_mozilla_jss_ssl_SocketBase_setSSLVersionRange;
+ Java_org_mozilla_jss_ssl_SSLSocket_setSSLVersionRangeDefault;
++Java_org_mozilla_jss_pkcs11_PK11SymmetricKeyDeriver_nativeDeriveSymKey;
++Java_org_mozilla_jss_pkcs11_PK11SymKey_setNickNameNative;
+ ;+    local:
+ ;+       *;
+ ;+};
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.c.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.c
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.c.jmagne	2016-04-14 16:02:38.108494940 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.c	2016-04-14 16:02:47.243432431 -0700
+@@ -114,6 +114,11 @@ JSS_AlgInfo JSS_AlgTable[NUM_ALGS] = {
+ /* 51 */    {SEC_OID_PKCS5_PBKDF2, SEC_OID_TAG},
+ /* 52 */    {SEC_OID_PKCS5_PBES2, SEC_OID_TAG},
+ /* 53 */    {SEC_OID_PKCS5_PBMAC1, SEC_OID_TAG},
++/* 54 */    {SEC_OID_HMAC_SHA1,SEC_OID_TAG},
++/* 55 */    {SEC_OID_HMAC_SHA224,SEC_OID_TAG},
++/* 56 */    {SEC_OID_HMAC_SHA256,SEC_OID_TAG},
++/* 57 */    {SEC_OID_HMAC_SHA384,SEC_OID_TAG},
++/* 58 */    {SEC_OID_HMAC_SHA512,SEC_OID_TAG}
+ /* REMEMBER TO UPDATE NUM_ALGS!!! */
+ };
+ 
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.h.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.h
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.h.jmagne	2016-04-14 11:30:41.871517926 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.h	2016-04-14 11:30:54.933436860 -0700
+@@ -56,7 +56,7 @@ typedef struct JSS_AlgInfoStr {
+     JSS_AlgType type;
+ } JSS_AlgInfo;
+ 
+-#define NUM_ALGS 54
++#define NUM_ALGS 59
+ 
+ extern JSS_AlgInfo JSS_AlgTable[];
+ extern CK_ULONG JSS_symkeyUsage[];
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.java.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.java
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.java.jmagne	2016-04-14 16:06:13.388021812 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/Algorithm.java	2016-04-14 16:06:27.537924813 -0700
+@@ -237,5 +237,9 @@ public class Algorithm {
+     protected static final short SEC_OID_PKCS5_PBKDF2=51;
+     protected static final short SEC_OID_PKCS5_PBES2=52;
+     protected static final short SEC_OID_PKCS5_PBMAC1=53;
+-
++    protected static final short SEC_OID_HMAC_SHA1=54;
++    protected static final short SEC_OID_HMAC_SHA224=55;
++    protected static final short SEC_OID_HMAC_SHA256=56;
++    protected static final short SEC_OID_HMAC_SHA384=57;
++    protected static final short SEC_OID_HMAC_SHA512=58;
+ }
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoStore.java.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoStore.java
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoStore.java.jmagne	2016-04-14 17:03:33.504298176 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoStore.java	2016-04-14 17:03:42.198238112 -0700
+@@ -75,6 +75,18 @@ public interface CryptoStore {
+     getPrivateKeys() throws TokenException;
+ 
+     /**
++     * Returns all symmetric keys stored on this token.
++     *
++     * @return An array of all symmetric keys stored on this token.
++     * @exception TokenException If an error occurs on the token while
++     *      gathering the keys.
++     */
++    public SymmetricKey[]
++    getSymmetricKeys() throws TokenException;
++
++
++
++    /**
+      * Deletes the given PrivateKey from the CryptoToken.
+      * This is a very dangerous call: it deletes the key from the underlying
+      * token. After calling this, the PrivateKey passed in must no longer
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoToken.java.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoToken.java
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoToken.java.jmagne	2016-04-14 16:07:39.458429756 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/CryptoToken.java	2016-04-14 16:07:52.266341595 -0700
+@@ -92,6 +92,9 @@ public interface CryptoToken {
+     getCipherContext(EncryptionAlgorithm algorithm)
+         throws java.security.NoSuchAlgorithmException, TokenException;
+ 
++    public abstract SymmetricKeyDeriver getSymmetricKeyDeriver() 
++        throws TokenException;
++
+     public abstract KeyWrapper
+     getKeyWrapper(KeyWrapAlgorithm algorithm)
+         throws java.security.NoSuchAlgorithmException, TokenException;
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/HMACAlgorithm.java.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/HMACAlgorithm.java
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/HMACAlgorithm.java.jmagne	2016-04-14 16:09:02.858855679 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/HMACAlgorithm.java	2016-04-14 16:09:18.048751121 -0700
+@@ -85,4 +85,21 @@ public class HMACAlgorithm extends Diges
+     public static final HMACAlgorithm SHA1 = new HMACAlgorithm
+         (CKM_SHA_1_HMAC, "SHA-1-HMAC",
+              OBJECT_IDENTIFIER.ALGORITHM.subBranch(26), 20);
++
++    public static final HMACAlgorithm SHA224 = new HMACAlgorithm
++        (SEC_OID_HMAC_SHA224, "SHA-224-HMAC",
++             OBJECT_IDENTIFIER.RSADSI.subBranch(8), 28);
++
++    public static final HMACAlgorithm SHA256 = new HMACAlgorithm
++        (SEC_OID_HMAC_SHA256, "SHA-256-HMAC",
++             OBJECT_IDENTIFIER.RSADSI.subBranch(9), 32);
++
++    public static final HMACAlgorithm SHA384 = new HMACAlgorithm
++        (SEC_OID_HMAC_SHA384, "SHA-384-HMAC",
++             OBJECT_IDENTIFIER.RSADSI.subBranch(10), 48);
++
++    public static final HMACAlgorithm SHA512 = new HMACAlgorithm
++        (SEC_OID_HMAC_SHA512, "SHA-512-HMAC",
++             OBJECT_IDENTIFIER.RSADSI.subBranch(11), 64);
++
+ }
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/KeyWrapper.java.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/KeyWrapper.java
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/KeyWrapper.java.jmagne	2016-04-14 16:10:43.930159965 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/KeyWrapper.java	2016-04-14 16:10:55.377081172 -0700
+@@ -133,4 +133,21 @@ public interface KeyWrapper {
+         throws TokenException, IllegalStateException,
+             InvalidAlgorithmParameterException;
+ 
++    public SymmetricKey unwrapSymmetricPerm(byte[] wrapped, SymmetricKey.Type type,
++        SymmetricKey.Usage usage, int keyLength)
++        throws TokenException, IllegalStateException,
++            InvalidAlgorithmParameterException;
++
++    /**
++     * Unwraps a key and allows it to be used for all operations.
++     * @param keyLength The expected length of the key in bytes.  This is
++     *   only used for variable-length keys (RC4) and non-padding
++     *   algorithms. Otherwise, it can be set to anything(like 0).
++     */
++    public SymmetricKey unwrapSymmetricPerm(byte[] wrapped, SymmetricKey.Type type,
++        int keyLength)
++        throws TokenException, IllegalStateException,
++            InvalidAlgorithmParameterException;
++
++
+ }
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKeyDeriver.java.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKeyDeriver.java
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKeyDeriver.java.jmagne	2016-04-14 16:36:36.080464052 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKeyDeriver.java	2016-04-14 16:36:49.784369514 -0700
+@@ -0,0 +1,79 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is the Netscape Security Services for Java.
++ *     
++ * The Initial Developer of the Original Code is
++ * Netscape Communications Corporation.
++ * Portions created by the Initial Developer are Copyright (C) 1998-2000
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++package org.mozilla.jss.crypto;
++
++import java.security.spec.AlgorithmParameterSpec;
++import java.security.InvalidAlgorithmParameterException;
++import java.security.PublicKey;
++import java.security.InvalidKeyException;
++
++public interface SymmetricKeyDeriver {
++
++   /* Use with the encrypt type mechanisms
++      Example: initDerive(
++                    symKey,  (PKCS11Constants.CKM_DES3_ECB_ENCRYPT_DATA) 4354L, derivationData, null,
++                    PKCS11Constants.CKM_DES3_ECB, PKCS11Constants.CKA_DERIVE, 16);
++   */
++
++    public abstract void initDerive(SymmetricKey baseKey, 
++        long deriveMech, byte[] param, byte[] iv, long targetMech, long operation, long keySize)
++        throws InvalidKeyException;
++
++
++
++    /* Use with key extraction and key concatanation mechanisms
++  
++    Example:
++       param: byte array that has the bit position of where to extract
++     initDerive(
++                derivedKey, PKCS11Constants.CKM_EXTRACT_KEY_FROM_KEY,param,null,
++                PKCS11Constants.CKA_ENCRYPT, PKCS11Constants.CKA_DERIVE,8);
++ 
++ 
++    initDerive(
++               baseSymKey,secondarySymKey, PKCS11Constants.CKM_CONCATENATE_BASE_AND_KEY,null,null,
++               PKCS11Constants.CKM_DES3_ECB, PKCS11Constants.CKA_DERIVE,0);
++ 
++    */ 
++
++    public abstract void initDerive(SymmetricKey baseKey, 
++        SymmetricKey secondaryKey, long deriveMech, byte[] param, byte[] iv, long targetMech, long operation, long keySize)
++        throws InvalidKeyException; 
++
++   public abstract SymmetricKey  derive()
++       throws TokenException;
++}
+diff -up ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKey.java.jmagne ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKey.java
+--- ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKey.java.jmagne	2016-04-14 16:11:50.865699222 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/crypto/SymmetricKey.java	2016-04-14 16:12:02.768617289 -0700
+@@ -71,6 +71,10 @@ public interface SymmetricKey {
+ 
+     String getFormat();
+ 
++    String getNickName();
++
++    void setNickName(String nickName);
++
+     public final static class Type {
+         // all names converted to lowercase for case insensitivity
+         private static Hashtable nameMap = new Hashtable();
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/manifest.mn.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/manifest.mn
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/manifest.mn.jmagne	2016-04-14 16:15:59.271989344 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/manifest.mn	2016-04-14 16:16:10.670910881 -0700
+@@ -64,6 +64,7 @@ CSRCS =                             \
+ 			PK11Store.c				\
+             PK11SymKey.c            \
+ 			PK11Token.c				\
++            PK11SymmetricKeyDeriver.c \
+             $(NULL)
+ 
+ 
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c.jmagne	2016-04-14 16:17:29.760366477 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.c	2016-04-14 16:17:58.742166983 -0700
+@@ -519,7 +519,7 @@ JNIEXPORT jobject JNICALL
+ Java_org_mozilla_jss_pkcs11_PK11KeyWrapper_nativeUnwrapSymWithSym
+     (JNIEnv *env, jclass clazz, jobject tokenObj, jobject unwrapperObj,
+         jbyteArray wrappedBA, jobject wrapAlgObj, jobject typeAlgObj,
+-        jint keyLen, jbyteArray ivBA, jint usageEnum)
++        jint keyLen, jbyteArray ivBA, jint usageEnum,jboolean temporary)
+ {
+     PK11SymKey *symKey=NULL, *wrappingKey=NULL;
+     CK_MECHANISM_TYPE wrappingMech, keyTypeMech;
+@@ -527,6 +527,7 @@ Java_org_mozilla_jss_pkcs11_PK11KeyWrapp
+     jobject keyObj = NULL;
+     CK_ULONG operation;
+     CK_FLAGS flags;
++    PRBool isPermanent = PR_FALSE;
+ 
+     /* get key type */
+     keyTypeMech = JSS_getPK11MechFromAlg(env, typeAlgObj);
+@@ -579,8 +580,21 @@ Java_org_mozilla_jss_pkcs11_PK11KeyWrapp
+         flags = 0;
+     }
+ 
+-    symKey = PK11_UnwrapSymKeyWithFlags(wrappingKey, wrappingMech, param,
+-        wrappedKey, keyTypeMech, operation, keyLen, flags);
++    if( temporary ) {
++        isPermanent = PR_FALSE;
++    } else {
++        isPermanent = PR_TRUE;
++    }
++
++    if( isPermanent == PR_FALSE) {
++        symKey = PK11_UnwrapSymKeyWithFlags(wrappingKey, wrappingMech, param,
++            wrappedKey, keyTypeMech, operation, keyLen, flags);
++
++    } else {
++        symKey = PK11_UnwrapSymKeyWithFlagsPerm(wrappingKey, wrappingMech, param,
++            wrappedKey, keyTypeMech, operation, keyLen, flags,isPermanent);
++    }
++
+     if( symKey == NULL ) {
+         JSS_throwMsg(env, TOKEN_EXCEPTION, "Failed to unwrap key");
+         goto finish;
+@@ -702,7 +716,7 @@ finish:
+ JNIEXPORT jobject JNICALL
+ Java_org_mozilla_jss_pkcs11_PK11KeyWrapper_nativeUnwrapSymPlaintext
+     (JNIEnv *env, jclass clazz, jobject tokenObj, jbyteArray wrappedBA,
+-        jobject typeAlgObj, jint usageEnum)
++        jobject typeAlgObj, jint usageEnum,jboolean temporary)
+ {
+     PK11SymKey *symKey=NULL;
+     CK_MECHANISM_TYPE keyTypeMech;
+@@ -711,6 +725,8 @@ Java_org_mozilla_jss_pkcs11_PK11KeyWrapp
+     PK11SlotInfo *slot = NULL;
+     CK_ULONG operation;
+     CK_FLAGS flags;
++    PRBool isPerm = PR_FALSE;
++
+ 
+     /* get key type */
+     keyTypeMech = JSS_getPK11MechFromAlg(env, typeAlgObj);
+@@ -740,9 +756,15 @@ Java_org_mozilla_jss_pkcs11_PK11KeyWrapp
+         flags = 0;
+     }
+ 
++    if( temporary ) {
++        isPerm = PR_FALSE;
++    } else {
++        isPerm = PR_TRUE;
++    }
++
+     /* pull in the key */
+     symKey = PK11_ImportSymKeyWithFlags(slot, keyTypeMech, PK11_OriginUnwrap,
+-        operation, wrappedKey, flags, PR_FALSE /*isPerm*/, NULL);
++        operation, wrappedKey, flags, isPerm, NULL);
+     if( symKey == NULL ) {
+         JSS_throwMsg(env, TOKEN_EXCEPTION, "Failed to unwrap key");
+         goto finish;
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.java.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.java
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.java.jmagne	2016-04-14 16:19:26.998559480 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11KeyWrapper.java	2016-04-14 16:19:40.941463506 -0700
+@@ -498,8 +498,25 @@ final class PK11KeyWrapper implements Ke
+         return unwrapSymmetric(wrapped, type, -1, keyLen);
+     }
+ 
++    public SymmetricKey
++    unwrapSymmetricPerm(byte[] wrapped, SymmetricKey.Type type,
++        SymmetricKey.Usage usage, int keyLen)
++        throws TokenException, IllegalStateException,
++            InvalidAlgorithmParameterException
++    {
++        return unwrapSymmetricPerm(wrapped, type, usage.getVal(), keyLen);
++    }
++
++    public SymmetricKey
++    unwrapSymmetricPerm(byte[] wrapped, SymmetricKey.Type type, int keyLen)
++        throws TokenException, IllegalStateException,
++            InvalidAlgorithmParameterException
++    {
++        return unwrapSymmetricPerm(wrapped, type, -1, keyLen);
++    }
++
+     private SymmetricKey
+-    unwrapSymmetric(byte[] wrapped, SymmetricKey.Type type,
++    unwrapSymmetricPerm(byte[] wrapped, SymmetricKey.Type type,
+         int usageEnum, int keyLen)
+         throws TokenException, IllegalStateException,
+             InvalidAlgorithmParameterException
+@@ -508,6 +525,10 @@ final class PK11KeyWrapper implements Ke
+             throw new IllegalStateException();
+         }
+ 
++        /* Since we want permanent,make the temporary arg false */
++        boolean temporary = false;
++
++
+         if( (! algorithm.isPadded()) && (type == SymmetricKey.RC4) ) {
+             if( keyLen <= 0 ) {
+                 throw new InvalidAlgorithmParameterException(
+@@ -521,12 +542,53 @@ final class PK11KeyWrapper implements Ke
+ 
+         if( algorithm == KeyWrapAlgorithm.PLAINTEXT ) {
+             return nativeUnwrapSymPlaintext(token, wrapped, algFromType(type),
+-                usageEnum );
++                usageEnum,temporary );
+         } else {
+             if( symKey != null ) {
+                 Assert._assert(pubKey==null && privKey==null);
+                 return nativeUnwrapSymWithSym(token, symKey, wrapped, algorithm,
+-                        algFromType(type), keyLen, IV, usageEnum);
++                        algFromType(type), keyLen, IV, usageEnum,temporary);
++            } else {
++                Assert._assert(privKey!=null && pubKey==null && symKey==null);
++                throw new TokenException("We do not support permnament unwrapping with private key.");
++            }
++        }
++    }
++
++
++    private SymmetricKey
++    unwrapSymmetric(byte[] wrapped, SymmetricKey.Type type,
++        int usageEnum, int keyLen)
++        throws TokenException, IllegalStateException,
++            InvalidAlgorithmParameterException
++    {
++        if( state != UNWRAP ) {
++            throw new IllegalStateException();
++        }
++
++        if( (! algorithm.isPadded()) && (type == SymmetricKey.RC4) ) {
++            if( keyLen <= 0 ) {
++                throw new InvalidAlgorithmParameterException(
++                    "RC4 keys wrapped in unpadded algorithms need key length"+
++                    " specified when unwrapping");
++            }
++        } else {
++            // Don't use the key length
++            //keyLen = 0;
++        }
++
++        /* Since we DONT want permanent,make the temporary arg true */
++        boolean temporary = true;
++
++
++        if( algorithm == KeyWrapAlgorithm.PLAINTEXT ) {
++            return nativeUnwrapSymPlaintext(token, wrapped, algFromType(type),
++                usageEnum, temporary );
++        } else {
++            if( symKey != null ) {
++                Assert._assert(pubKey==null && privKey==null);
++                return nativeUnwrapSymWithSym(token, symKey, wrapped, algorithm,
++                        algFromType(type), keyLen, IV, usageEnum,temporary);
+             } else {
+                 Assert._assert(privKey!=null && pubKey==null && symKey==null);
+                 return nativeUnwrapSymWithPriv(token, privKey, wrapped,
+@@ -586,7 +648,7 @@ final class PK11KeyWrapper implements Ke
+     private static native SymmetricKey
+     nativeUnwrapSymWithSym(PK11Token token, SymmetricKey unwrappingKey,
+         byte[] wrappedKey, KeyWrapAlgorithm alg, Algorithm type, int keyLen,
+-        byte[] IV, int usageEnum)
++        byte[] IV, int usageEnum,boolean temporary)
+             throws TokenException;
+ 
+     /**
+@@ -600,7 +662,7 @@ final class PK11KeyWrapper implements Ke
+ 
+     private static native SymmetricKey
+     nativeUnwrapSymPlaintext(PK11Token token, byte[] wrappedKey,
+-        Algorithm type, int usageEnum);
++        Algorithm type, int usageEnum,boolean temporary);
+ 
+     private void reset() {
+         state = UNINITIALIZED;
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11MessageDigest.c.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11MessageDigest.c
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11MessageDigest.c.jmagne	2016-05-06 18:10:04.531912407 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11MessageDigest.c	2016-05-06 17:36:19.913933639 -0700
+@@ -99,17 +99,19 @@ Java_org_mozilla_jss_pkcs11_PK11MessageD
+     }
+ 
+     /* copy the key, setting the CKA_SIGN attribute */
+-    newKey = PK11_CopySymKeyForSigning(origKey, mech);
++/*    newKey = PK11_CopySymKeyForSigning(origKey, mech);
+     if( newKey == NULL ) {
+         JSS_throwMsg(env, DIGEST_EXCEPTION,
+                         "Unable to set CKA_SIGN attribute on symmetric key");
+         goto finish;
+     }
+ 
++*/
++
+     param.data = NULL;
+     param.len = 0;
+ 
+-    context = PK11_CreateContextBySymKey(mech, CKA_SIGN, newKey, &param);
++    context = PK11_CreateContextBySymKey(mech, CKA_SIGN, origKey, &param);
+     if( context == NULL ) {
+         JSS_throwMsg(env, DIGEST_EXCEPTION,
+             "Unable to initialize digest context");
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.c.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.c
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.c.jmagne	2016-04-14 16:22:16.174394977 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.c	2016-04-14 16:22:26.605323176 -0700
+@@ -44,13 +44,101 @@
+ #include <cert.h>
+ #include <certdb.h>
+ #include <secasn1.h>
+-
+ #include <jssutil.h>
+ #include <Algorithm.h>
+ #include "pk11util.h"
+ #include <java_ids.h>
+ #include <jss_exceptions.h>
+ 
++typedef struct
++{
++    enum
++    {
++        PW_NONE = 0,
++        PW_FROMFILE = 1,
++        PW_PLAINTEXT = 2,
++        PW_EXTERNAL = 3
++    } source;
++    char *data;
++} secuPWData;
++
++/**********************************************************************
++ * PK11Store.putSymKeysInVector
++ */
++JNIEXPORT void JNICALL
++Java_org_mozilla_jss_pkcs11_PK11Store_putSymKeysInVector
++    (JNIEnv *env, jobject this, jobject keyVector)
++{
++    PK11SlotInfo *slot;
++    jobject object = NULL;
++    jclass vectorClass;
++    jmethodID addElement;
++
++    PK11SymKey *firstSymKey= NULL;
++    PK11SymKey *sk  = NULL;
++    PK11SymKey *nextSymKey = NULL;
++    secuPWData  pwdata;
++
++    PK11SymKey *freeSymKey = NULL;
++    PK11SymKey *nextFreeSymKey = NULL;
++
++    pwdata.source   = PW_NONE;
++    pwdata.data     = (char *) NULL;
++
++    PR_ASSERT(env!=NULL && this!=NULL && keyVector!=NULL);
++
++    if( JSS_PK11_getStoreSlotPtr(env, this, &slot) != PR_SUCCESS) {
++        ASSERT_OUTOFMEM(env);
++        goto finish;
++    }
++    PR_ASSERT(slot!=NULL);
++
++    vectorClass = (*env)->GetObjectClass(env, keyVector);
++    if(vectorClass == NULL) {
++        ASSERT_OUTOFMEM(env);
++        goto finish;
++    }
++
++    addElement = (*env)->GetMethodID(env,
++                                     vectorClass,
++                                     VECTOR_ADD_ELEMENT_NAME,
++                                     VECTOR_ADD_ELEMENT_SIG);
++    if(addElement == NULL) {
++        ASSERT_OUTOFMEM(env);
++        goto finish;
++    }
++
++    PK11_Authenticate(slot, PR_TRUE /*load certs*/, NULL /*wincx*/);
++
++    /* Obtain the symmetric key list. */
++    firstSymKey = PK11_ListFixedKeysInSlot( slot , NULL, ( void *) &pwdata );
++    sk = firstSymKey;
++
++    while(( sk != NULL ))
++    {
++        if( sk ) {
++
++            nextSymKey = sk;
++            object = JSS_PK11_wrapSymKey(env, &sk);
++
++            if(object == NULL) {
++                PR_ASSERT( (*env)->ExceptionOccurred(env) );
++                goto finish;
++            }
++
++            /***************************************************
++            * Insert the key into the vector
++            ***************************************************/
++            (*env)->CallVoidMethod(env, keyVector, addElement, object);
++        }
++
++        sk = PK11_GetNextSymKey( nextSymKey );
++    }
++
++finish:
++
++    return;
++}
+ 
+ /**********************************************************************
+  * PK11Store.putKeysInVector
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.java.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.java
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.java.jmagne	2016-04-14 16:23:26.997907471 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Store.java	2016-04-14 16:23:34.435856272 -0700
+@@ -66,8 +66,23 @@ public final class PK11Store implements
+         keys.copyInto( (Object[]) array );
+         return array;
+     }
++
++    public synchronized SymmetricKey[]
++    getSymmetricKeys() throws TokenException {
++
++        Vector keys = new Vector();
++        putSymKeysInVector(keys);
++        SymmetricKey[] array = new SymmetricKey[keys.size()];
++        keys.copyInto( (Object[]) array);
++        return array;
++    }
++
++
++
+     protected native void putKeysInVector(Vector keys) throws TokenException;
+ 
++    protected native void putSymKeysInVector(Vector symKeys) throws TokenException;
++
+ 
+     public native void deletePrivateKey(PrivateKey key)
+         throws NoSuchItemOnTokenException, TokenException;
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.c.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.c
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.c.jmagne	2016-04-14 16:24:44.565372557 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.c	2016-05-17 11:37:48.532485104 -0700
+@@ -33,7 +33,6 @@
+  * the terms of any one of the MPL, the GPL or the LGPL.
+  *
+  * ***** END LICENSE BLOCK ***** */
+-
+ #include "_jni/org_mozilla_jss_pkcs11_SymKeyProxy.h"
+ 
+ #include <nspr.h>
+@@ -62,6 +61,8 @@ JSS_PK11_wrapSymKey(JNIEnv *env, PK11Sym
+     jmethodID constructor;
+     jbyteArray ptrArray;
+     jobject Key=NULL;
++    char *nickname = NULL;
++    jstring jnickname = NULL;
+ 
+     PR_ASSERT(env!=NULL && symKey!=NULL && *symKey!=NULL);
+ 
+@@ -72,10 +73,17 @@ JSS_PK11_wrapSymKey(JNIEnv *env, PK11Sym
+         goto finish;
+     }
+ 
++    nickname = PK11_GetSymKeyNickname( *symKey );
++
++    if (nickname) {
++        jnickname = (*env)->NewStringUTF(env, nickname);
++    }
++
++ 
+     /* find the constructor */
+     constructor = (*env)->GetMethodID(env, keyClass,
+                                         PLAIN_CONSTRUCTOR,
+-                                        PK11SYMKEY_CONSTRUCTOR_SIG);
++                                        PK11SYMKEY_CONSTRUCTOR_1_SIG);
+     if(constructor == NULL) {
+         ASSERT_OUTOFMEM(env);
+         goto finish;
+@@ -87,12 +95,16 @@ JSS_PK11_wrapSymKey(JNIEnv *env, PK11Sym
+         goto finish;
+     }
+     /* call the constructor */
+-    Key = (*env)->NewObject(env, keyClass, constructor, ptrArray);
++    Key = (*env)->NewObject(env, keyClass, constructor, ptrArray,jnickname);
+ 
+ finish:
+     if(Key == NULL) {
+         PK11_FreeSymKey(*symKey);
+     }
++    if(nickname != NULL) {
++        PORT_Free(nickname);
++        nickname = NULL;
++    }
+     *symKey = NULL;
+     return Key;
+ }
+@@ -181,6 +193,49 @@ finish:
+ 
+ /***********************************************************************
+  *
++ * PK11SymKey.setNickNameNative
++ */
++JNIEXPORT void JNICALL
++Java_org_mozilla_jss_pkcs11_PK11SymKey_setNickNameNative
++    (JNIEnv *env, jobject this,jstring nickname)
++{
++    PK11SymKey *key=NULL;
++    const char *keyname = NULL;
++    SECStatus status;
++
++    /* If no nickname provided, we are done */
++    if( nickname == NULL ) {
++        JSS_throwMsgPrErr(env, TOKEN_EXCEPTION,
++            "Nickname is NULL, will not be set");        
++        goto finish;
++    }
++
++    /* get the key pointer */
++    if( JSS_PK11_getSymKeyPtr(env, this, &key) != PR_SUCCESS) {
++        goto finish;
++    }
++
++    /* convert the Java String into a native "C" string */
++    keyname = (*env)->GetStringUTFChars( env, nickname, 0 );
++
++    /* name the key */
++    status = PK11_SetSymKeyNickname( key, keyname );
++    if( status != SECSuccess ) {
++        JSS_throwMsgPrErr(env, TOKEN_EXCEPTION,
++            "Failed to name symmetric key");
++    }
++finish:
++
++    if( keyname != NULL ) {
++        /* free the native "C" string */
++        (*env)->ReleaseStringUTFChars(env, nickname, keyname);
++    }
++
++    return;
++}
++
++/***********************************************************************
++ *
+  * PK11SymKey.getKeyData
+  */
+ JNIEXPORT jbyteArray JNICALL
+@@ -279,6 +334,10 @@ Java_org_mozilla_jss_pkcs11_PK11SymKey_g
+           case CKK_AES:
+             typeFieldName = AES_KEYTYPE_FIELD;
+             break;
++          case CKK_DES2:
++             printf("hello des2! \n");
++             typeFieldName = DES3_KEYTYPE_FIELD;
++             break;
+           default:
+             PR_ASSERT(PR_FALSE);
+             typeFieldName = DES_KEYTYPE_FIELD;
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.java.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.java
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.java.jmagne	2016-04-14 16:58:33.385371633 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymKey.java	2016-05-17 11:41:36.323841045 -0700
+@@ -44,9 +44,17 @@ public final class PK11SymKey implements
+     protected PK11SymKey(byte[] pointer) {
+         Assert._assert(pointer!=null);
+         keyProxy  = new SymKeyProxy(pointer);
++        nickName = null;
++    }
++
++    protected PK11SymKey(byte[] pointer,String nickName) {
++        Assert._assert(pointer!=null);
++        keyProxy  = new SymKeyProxy(pointer);
++        this.nickName = nickName;
+     }
+ 
+     private SymKeyProxy keyProxy;
++    private String nickName;
+ 
+     public SymmetricKey.Type getType() {
+         KeyType kt = getKeyType();
+@@ -108,6 +116,20 @@ public final class PK11SymKey implements
+     public String getFormat() {
+         return "RAW";
+     }
++
++    public String getNickName() {
++        return nickName;
++    }
++
++    public void setNickName(String nickName) {
++        this.nickName = nickName;
++
++        if( nickName != null) {
++            setNickNameNative(nickName);
++        }
++    }
++
++    public native void setNickNameNative(String nickName);
+ }
+ 
+ class SymKeyProxy extends KeyProxy {
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.c.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.c
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.c.jmagne	2016-04-14 16:26:18.611723763 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.c	2016-05-17 14:13:35.456574082 -0700
+@@ -0,0 +1,364 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is the Netscape Security Services for Java.
++ *
++ * The Initial Developer of the Original Code is
++ * Netscape Communications Corporation.
++ * Portions created by the Initial Developer are Copyright (C) 1998-2000
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++#include "_jni/org_mozilla_jss_pkcs11_PK11SymmetricKeyDeriver.h"
++#include <plarena.h>
++#include <secmodt.h>
++#include <pk11func.h>
++#include <pk11pqg.h>
++#include <secerr.h>
++#include <nspr.h>
++#include <key.h>
++#include <secasn1.h>
++#include <base64.h>
++#include <cert.h>
++#include <cryptohi.h>
++
++#include <jssutil.h>
++#include <jss_exceptions.h>
++#include <jss_bigint.h>
++#include <Algorithm.h>
++#include <jni.h>
++#include <secitem.h>
++#include "java_ids.h"
++
++#include "pk11util.h"
++#include <plstr.h>
++
++/***********************************************************************
++ * Expose the NSS functionality at low level, one should know what to do
++ * at the Java level. 
++ */
++
++JNIEXPORT jobject JNICALL Java_org_mozilla_jss_pkcs11_PK11SymmetricKeyDeriver_nativeDeriveSymKey
++  (JNIEnv * env, jobject this,jobject tokenObj, 
++  jobject baseKeyObj, jobject secondaryKeyObj, 
++  jlong deriveMechanism, jbyteArray param, jbyteArray iv, jlong targetMechanism, jlong operation, jlong keySize)
++{
++    jobject keyObj = NULL;
++    PK11SlotInfo *slot=NULL;
++    PK11SlotInfo *bestSlot = NULL;
++    PK11SlotInfo *slotForKey = NULL;
++    PK11SlotInfo *slotForSecondaryKey = NULL;
++    PK11SlotInfo *finalSlot = NULL;
++    PK11SlotInfo *finalSecondarySlot = NULL;
++    PK11SlotInfo *finalBaseKeySlot = NULL;
++
++    PK11SymKey *baseKey = NULL;
++    PK11SymKey *bestBaseKey = NULL;
++    PK11SymKey *finalBaseKey = NULL;
++    PK11SymKey *newKey = NULL;
++
++    PK11SymKey *secondaryKey = NULL;
++    PK11SymKey *bestSecondaryKey = NULL;
++    PK11SymKey *finalSecondaryKey = NULL;
++    PK11SymKey *derivedKey = NULL;
++    jbyte *paramValue = NULL;
++    int paramLength = 0;
++    jbyte *ivValue = NULL;
++    int ivLength = 0;
++
++
++    CK_OBJECT_HANDLE keyhandle = 0;
++
++    CK_AES_CBC_ENCRYPT_DATA_PARAMS aes;
++    CK_DES_CBC_ENCRYPT_DATA_PARAMS des;
++    CK_KEY_DERIVATION_STRING_DATA string;
++
++    SECItem paramsItem = { siBuffer, NULL, 0 };
++
++    PR_ASSERT(env!=NULL && this!=NULL);
++
++    if( baseKeyObj == 0) {
++        PR_fprintf(PR_STDOUT,"baseKeyObj can not be null!\n");
++        goto loser;
++    }
++
++    if( param != NULL) {
++        paramValue = (*env)->GetByteArrayElements(env,param, NULL);
++        paramLength = (*env)->GetArrayLength(env,param);
++    }
++
++    if( iv != NULL) {
++        ivValue = (*env)->GetByteArrayElements(env,iv, NULL);
++        ivLength = (*env)->GetArrayLength(env,iv);
++    }
++
++    /* Set up the params data for the PK11_Derive family */
++
++    switch ( deriveMechanism ) {
++        case CKM_DES_ECB_ENCRYPT_DATA:
++        case CKM_DES3_ECB_ENCRYPT_DATA:
++        case CKM_AES_ECB_ENCRYPT_DATA:
++        case CKM_CAMELLIA_ECB_ENCRYPT_DATA:
++        case CKM_SEED_ECB_ENCRYPT_DATA:
++        /* Use CK_KEY_DERIVATION_STRING_DATA */ 
++
++            string.pData = (unsigned char *) paramValue;
++            string.ulLen = paramLength;
++            paramsItem.data = (void *) &string;
++            paramsItem.len = sizeof(string);
++
++        break;
++        case CKM_DES_CBC_ENCRYPT_DATA:
++        case CKM_DES3_CBC_ENCRYPT_DATA:
++        /* Use CK_DES_CBC_ENCRYPT_DATA_PARAMS */
++    
++            if( ivValue == NULL) {
++               PR_fprintf(PR_STDOUT, "Need iv param for CKM_DES_CBC_ENCRYPT_DATA or CKM_DES3_CBC_ENCRYPT_DATA. \n");
++               goto loser;
++            }
++
++             if( ivLength != 8) {
++               PR_fprintf(PR_STDOUT, "Need iv param for CKM_DES_CBC_ENCRYPT_DATA  structure to be 8 bytes!. \n");
++               goto loser;
++            }
++
++            des.pData = (unsigned char *) paramValue;
++            des.length = paramLength;
++            PORT_Memcpy(des.iv,ivValue,ivLength);
++            paramsItem.data = (void *) &des;
++            paramsItem.len = sizeof(des);
++    
++        break;
++
++        case CKM_AES_CBC_ENCRYPT_DATA:
++        case CKM_CAMELLIA_CBC_ENCRYPT_DATA:
++        case CKM_SEED_CBC_ENCRYPT_DATA:
++        /* Use CK_AES_CBC_ENCRYPT_DATA_PARAMS */
++            
++            if ( ivValue == NULL ) {
++                PR_fprintf(PR_STDOUT, "Need iv param for CBC encrypt derive for AES, or CAMELLIA or SEED. \n");
++                goto loser;
++            }
++
++            if( ivLength != 16) {
++                PR_fprintf(PR_STDOUT, "Need iv param for CK_AES_CBC_ENCRYPT_DATA_PARAMS structure to be 16 bytes!. \n");
++                goto loser;
++            }
++
++            aes.pData = (unsigned char *) paramValue;
++            aes.length = paramLength;
++            PORT_Memcpy(aes.iv,ivValue,ivLength);
++            paramsItem.data = (void *) &aes;
++            paramsItem.len = sizeof(aes);
++        break;
++        default:
++            paramsItem.data = (unsigned char *) paramValue;
++            paramsItem.len = paramLength;
++        break;
++    }
++
++    /* Get slot */
++    if( JSS_PK11_getTokenSlotPtr(env, tokenObj, &slot) != PR_SUCCESS) {
++        goto loser;
++    }
++
++    /* Get base key */
++
++    if( JSS_PK11_getSymKeyPtr(env, baseKeyObj, &baseKey) != PR_SUCCESS) {
++        PR_fprintf(PR_STDOUT, "PK11SymmetricKeyDeriver.nativeDeriveSymKey: Unable to extract symmetric base key!");
++        goto loser;
++    }
++
++    /* Ask NSS what the best slot for the given mechanism */
++
++    bestSlot = PK11_GetBestSlot(deriveMechanism, NULL);
++
++    if( bestSlot == NULL) {
++        PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey: Can't find suitable slot for sym key derivation! \n");
++        goto loser;
++    }
++
++    slotForKey = PK11_GetSlotFromKey(baseKey);
++
++    int keyOnRequestedSlot = 0;
++    int baseKeyMoved= 0;
++
++    if(slotForKey != slot) {
++        keyOnRequestedSlot = 0;
++    }  else {
++        keyOnRequestedSlot = 1;
++        finalBaseKeySlot = slot;
++    } 
++
++    if ( PK11_DoesMechanism( slot, deriveMechanism)) {
++        if ( keyOnRequestedSlot ) {
++            finalBaseKey = baseKey;
++        } else {
++            bestBaseKey = PK11_MoveSymKey( slot, CKA_ENCRYPT, 0, PR_FALSE, baseKey );
++            if(bestBaseKey == NULL) {
++                PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey:  Can't move Base Key to requested slot!\n");
++                goto loser;
++            }
++            baseKeyMoved = 1;
++            finalBaseKey = bestBaseKey;
++            finalBaseKeySlot = slot;
++        }
++
++    } else {
++            bestBaseKey = PK11_MoveSymKey( bestSlot, CKA_ENCRYPT, 0, PR_FALSE, baseKey );
++            if(bestBaseKey == NULL) {
++                PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey:  Can't move Base Key to best slot!\n");
++                goto loser;
++            }
++            baseKeyMoved = 1;
++            finalBaseKey = bestBaseKey;
++            finalBaseKeySlot = bestSlot;
++    }
++
++    /* Assume we want to do a concatenation family here */
++
++    if( secondaryKeyObj != NULL) {
++        if( JSS_PK11_getSymKeyPtr(env, secondaryKeyObj, &secondaryKey) != PR_SUCCESS) {
++            PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey:  Can't find secondary sym key!\n");
++            goto loser;
++        }
++
++        /* Make sure the secondary key is in the proper slot to do concatenation */
++
++        slotForSecondaryKey = PK11_GetSlotFromKey( secondaryKey );
++
++        if( finalBaseKeySlot != slotForSecondaryKey ) {
++
++            finalSecondaryKey = PK11_MoveSymKey (finalBaseKeySlot, CKA_ENCRYPT, 0, PR_FALSE, secondaryKey);
++
++            if( finalSecondaryKey == NULL) {
++                PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey, Problem moving secondary key to proper slot.\n");
++                goto loser;
++            }
++        } else {
++            finalSecondaryKey = secondaryKey;
++        }
++
++        if( paramValue == NULL) {
++            keyhandle = PK11_GetSymKeyHandle(finalSecondaryKey);
++
++            if( keyhandle == 0) {
++                PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey, can't get handle for secondary sym key.\n");
++                goto loser;
++            }
++
++            paramsItem.data=(unsigned char *) &keyhandle;
++            paramsItem.len=sizeof(keyhandle);
++
++        } else {
++            PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey: incorrect input parameter provided!\n");
++            goto loser;
++        }
++    }
++
++    derivedKey = PK11_Derive(finalBaseKey, deriveMechanism, &paramsItem, targetMechanism,
++                                                            operation, keySize);
++    if(derivedKey == NULL) {
++        PR_fprintf(PR_STDOUT,
++                    "ERROR: Can't derive symmetric key, error: %d \n",PR_GetError());
++        goto loser;
++    }
++
++    if ( (finalSlot =  PK11_GetSlotFromKey(derivedKey )) != slot) {
++        newKey =  PK11_MoveSymKey ( slot, CKA_ENCRYPT, 0, PR_FALSE, derivedKey);
++
++        if ( newKey == NULL ) {
++            PR_fprintf(PR_STDOUT,"PK11SymmetricKeyDeriver.nativeDeriveSymKey: error moving key to original slot, return anyway. \n");
++            newKey = derivedKey;
++            derivedKey = NULL;
++        }
++       
++    }  else {
++        newKey = derivedKey;
++        derivedKey = NULL;
++    }
++
++    keyObj = JSS_PK11_wrapSymKey(env, &newKey);
++
++loser:
++
++    if ( bestBaseKey != NULL ) {
++       PK11_FreeSymKey ( bestBaseKey );
++       bestBaseKey = NULL;
++    }
++
++    if ( bestSecondaryKey != NULL ) {
++       PK11_FreeSymKey ( bestSecondaryKey );
++       bestSecondaryKey = NULL;
++    }
++
++    if ( derivedKey != NULL) {
++      PK11_FreeSymKey ( derivedKey );
++      derivedKey = NULL;
++    }
++
++    if (bestSlot != NULL ) {
++       PK11_FreeSlot(bestSlot);
++       bestSlot = NULL;
++    }
++
++    if ( slotForKey != NULL ) {
++       PK11_FreeSlot( slotForKey );
++       slotForKey = NULL;
++    }
++
++    if ( finalSlot != NULL ) {
++       PK11_FreeSlot( finalSlot );
++       finalSlot = NULL;
++    }
++
++    if ( finalSecondarySlot != NULL ) {
++       PK11_FreeSlot( finalSecondarySlot );
++       finalSecondarySlot = NULL;
++    }
++
++    if ( slotForSecondaryKey != NULL ) {
++       PK11_FreeSlot( slotForSecondaryKey );
++       slotForSecondaryKey = NULL;
++    }
++
++    if(paramValue) {
++        (*env)->ReleaseByteArrayElements(env, param, (jbyte*)paramValue,
++                                                              JNI_ABORT);
++    }
++    if(ivValue) {
++        (*env)->ReleaseByteArrayElements(env, iv, (jbyte*)ivValue,
++                                                        JNI_ABORT);
++    }
++
++    if( keyObj == NULL) {
++        JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, "Unable to derive symmetric key! "
++                 "failure!");
++    }
++
++    return keyObj; 
++}
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.java.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.java
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.java.jmagne	2016-04-14 16:28:29.179823017 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11SymmetricKeyDeriver.java	2016-04-14 16:28:36.186774680 -0700
+@@ -0,0 +1,158 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is the Netscape Security Services for Java.
++ *
++ * The Initial Developer of the Original Code is
++ * Netscape Communications Corporation.
++ * Portions created by the Initial Developer are Copyright (C) 1998-2000
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++package org.mozilla.jss.pkcs11;
++
++import org.mozilla.jss.crypto.*;
++import org.mozilla.jss.util.Assert;
++import sun.security.pkcs11.wrapper.*;
++import java.security.InvalidKeyException;
++
++
++/*This operation is pkcs11 based only */
++
++public class PK11SymmetricKeyDeriver implements SymmetricKeyDeriver {
++
++    private PK11Token token = null;
++    private SymmetricKey baseKey = null;
++    private SymmetricKey secondaryKey = null;
++    private long deriveMechanism = 0;
++    private long targetMechanism = 0;
++    private long operation = 0;
++    private long keySize = 0;
++    private byte[] param = null;
++    private byte[] iv = null;
++
++    public PK11SymmetricKeyDeriver(PK11Token token)
++    {
++        this.token = token;
++    }
++
++    /* Use with the encrypt type mechanisms 
++
++    Example: initDerive(
++                    symKey, (PKCS11Constants.CKM_DES3_ECB_ENCRYPT_DATA) 4354L, derivationData, null,
++                    PKCS11Constants.CKM_DES3_ECB, PKCS11Constants.CKA_DERIVE, 16);
++
++
++   */
++    public void initDerive(SymmetricKey baseKey, long deriveMech, byte[] param, byte[] iv, 
++                              long targetMech, long operation, long keySize) throws InvalidKeyException
++    {
++        reset();
++
++        if(baseKey == null) {
++            throw new InvalidKeyException("Key is null");
++        }
++
++        this.baseKey = baseKey;
++        this.deriveMechanism = deriveMech;
++        this.targetMechanism = targetMech;
++        this.operation = operation;
++
++        if ( param != null) {
++            this.param = new byte[param.length];
++            System.arraycopy(param,0,this.param,0,param.length);
++        }
++
++        if ( iv != null) {
++            this.iv = new byte[iv.length];
++            System.arraycopy(iv,0,this.iv,0,iv.length);
++        }
++
++        this.keySize = keySize;
++
++    }
++
++    /* Use with key extraction and key concatanation mechanisms
++       
++    Example Extraction:
++       param: byte array that has the bit position of where to extract
++     initDerive(
++                derivedKey, PKCS11Constants.CKM_EXTRACT_KEY_FROM_KEY,param,null,
++                PKCS11Constants.CKA_ENCRYPT, PKCS11Constants.CKA_DERIVE,8);
++
++    Example Concat:
++
++    initDerive(
++               baseSymKey,secondarySymKey, PKCS11Constants.CKM_CONCATENATE_BASE_AND_KEY,null,null,
++               PKCS11Constants.CKM_DES3_ECB, PKCS11Constants.CKA_DERIVE,0);
++
++    */ 
++
++    public void initDerive(SymmetricKey baseKey, SymmetricKey secondaryKey, long deriveMech, 
++        byte[] param, byte[] iv, long targetMech, long operation, long keySize) throws InvalidKeyException
++    {
++        reset();
++
++        if ( baseKey == null || secondaryKey == null) {
++            throw new InvalidKeyException("Key is null");
++        }
++
++        initDerive(baseKey, deriveMech, param,iv,targetMech,operation,keySize);
++        this.secondaryKey = secondaryKey;
++
++    }
++
++
++    public SymmetricKey derive()
++         throws TokenException
++    {
++        SymmetricKey result = deriveSymKey(this.baseKey,this.secondaryKey,this.deriveMechanism, this.param, this.iv, this.targetMechanism, this.operation,this.keySize);
++        return result;
++    }
++
++    private SymmetricKey
++    deriveSymKey(SymmetricKey baseKey, SymmetricKey secondaryKey, long deriveMechanism, byte[] param, byte[] iv, long targetMechanism, long operation, long keySize)
++        throws TokenException, IllegalStateException
++    {
++        return nativeDeriveSymKey(token, baseKey, secondaryKey,deriveMechanism, param, iv, targetMechanism, operation, keySize);
++    }
++
++    public native SymmetricKey nativeDeriveSymKey(PK11Token token, SymmetricKey baseKey, SymmetricKey secondaryKey, long deriveMechanism, byte[] param, byte[] iv,
++        long targetMechanism, long operation, long keySize);
++
++    private void reset() {
++        baseKey = null;
++        secondaryKey = null;
++        deriveMechanism = 0;
++        targetMechanism = 0;
++        operation = 0;
++        keySize = 0;
++        param = null;
++        iv = null;
++   }
++}
+diff -up ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java.jmagne ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java
+--- ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java.jmagne	2016-04-14 16:30:46.098878459 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/pkcs11/PK11Token.java	2016-04-14 17:27:30.918367372 -0700
+@@ -131,6 +131,11 @@ public final class PK11Token implements
+         return PK11KeyGenerator.clone(key, this);
+     }
+ 
++    public PK11SymmetricKeyDeriver getSymmetricKeyDeriver()
++    {
++         return new PK11SymmetricKeyDeriver(this);
++    }
++
+     public KeyWrapper
+     getKeyWrapper(KeyWrapAlgorithm algorithm)
+         throws NoSuchAlgorithmException, TokenException
+diff -up ./mozilla/security/jss/org/mozilla/jss/tests/SymKeyDeriving.java.jmagne ./mozilla/security/jss/org/mozilla/jss/tests/SymKeyDeriving.java
+--- ./mozilla/security/jss/org/mozilla/jss/tests/SymKeyDeriving.java.jmagne	2016-04-14 16:32:58.529964860 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/tests/SymKeyDeriving.java	2016-05-17 11:43:51.858862556 -0700
+@@ -0,0 +1,516 @@
++/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
++ *
++ * The contents of this file are subject to the Mozilla Public License Version
++ * 1.1 (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * Software distributed under the License is distributed on an "AS IS" basis,
++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
++ * for the specific language governing rights and limitations under the
++ * License.
++ *
++ * The Original Code is the Netscape Security Services for Java.
++ *
++ * The Initial Developer of the Original Code is
++ * Netscape Communications Corporation.
++ * Portions created by the Initial Developer are Copyright (C) 1998-2000
++ * the Initial Developer. All Rights Reserved.
++ *
++ * Contributor(s):
++ *
++ * Alternatively, the contents of this file may be used under the terms of
++ * either the GNU General Public License Version 2 or later (the "GPL"), or
++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
++ * in which case the provisions of the GPL or the LGPL are applicable instead
++ * of those above. If you wish to allow use of your version of this file only
++ * under the terms of either the GPL or the LGPL, and not to allow others to
++ * use your version of this file under the terms of the MPL, indicate your
++ * decision by deleting the provisions above and replace them with the notice
++ * and other provisions required by the GPL or the LGPL. If you do not delete
++ * the provisions above, a recipient may use your version of this file under
++ * the terms of any one of the MPL, the GPL or the LGPL.
++ *
++ * ***** END LICENSE BLOCK ***** */
++
++package org.mozilla.jss.tests;
++
++import org.mozilla.jss.crypto.*;
++import org.mozilla.jss.CryptoManager;
++import org.mozilla.jss.util.Assert;
++import org.mozilla.jss.pkcs11.*;
++import sun.security.pkcs11.wrapper.PKCS11Constants;
++import java.nio.ByteBuffer;
++import java.util.Arrays;
++import java.util.Vector;
++import java.util.Enumeration;
++
++/**
++ * Sym Key deriving tests..
++ *
++ */
++
++public class SymKeyDeriving {
++
++      private static final byte[] iv8 = new byte [] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 };
++      private static final byte[] iv16 = new byte [] { 0x1, 0x2, 0x3, 0x4, 
++                    0x5, 0x6, 0x7, 0x8,  
++                    0x9,0xa, 0xb, 0xc,0xd,0xe, 0xf,0x10 };
++
++      private static final byte[] derivationData1 = new byte[] { 0x11, 0x11, 0x13,
++          0x14, 0x15, 0x16, 0x17, 0x18 };
++
++      private static final byte[] derivationData2 = new byte [] { 0x9, 0xa, 0xb, 0xc, 0xd,
++          0xe, 0xf, 0x10 };
++
++      private static final byte[] derivationData16 = new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,0x7, 0x8,
++          0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10 };
++
++
++    public static void main(String args[]) {
++
++      SymmetricKey macKeyDev = null;
++      try {
++
++        CryptoManager.InitializationValues vals =
++              new CryptoManager.InitializationValues("./"
++              );
++        CryptoManager.initialize(vals);
++        CryptoManager cm = CryptoManager.getInstance();
++        CryptoToken token = cm.getInternalCryptoToken();
++        CryptoToken keyToken = cm.getInternalKeyStorageToken();
++        System.out.println("interal token name: " + keyToken.getName());
++        KeyGenerator keyKg = keyToken.getKeyGenerator(KeyGenAlgorithm.DES3);
++        SymmetricKey baseKey = keyKg.generate();
++
++
++        KeyGenerator keyKgDes = keyToken.getKeyGenerator(KeyGenAlgorithm.DES);
++        SymmetricKey baseKeyDes = keyKgDes.generate();
++        System.out.println("strength: " + baseKeyDes.getStrength());
++
++
++        KeyGenerator keyKgAES = keyToken.getKeyGenerator(KeyGenAlgorithm.AES);
++        keyKgAES.initialize(128);
++        SymmetricKey baseKeyAES = keyKgAES.generate();
++
++
++
++        System.out.println("baseKey bytes: ");
++        byte[] baseBytes = baseKey.getEncoded();
++        displayByteArray(baseBytes,true); 
++
++
++        /*****************************************************************************************************/
++
++        System.out.println("\n Mechanism CKM_EXTRACT_KEY_FROM_KEY test 16 bytes. \n");
++
++
++        SymmetricKeyDeriver deriver = token.getSymmetricKeyDeriver();
++        System.out.println("deriver: " + deriver);
++        System.out.println("CKM_EXTRACT_KEY_FROM_KEY : " + PKCS11Constants.CKM_EXTRACT_KEY_FROM_KEY);
++
++        long bitPosition = 0;
++
++        byte[] param = longToBytes(bitPosition);
++
++        deriver.initDerive(
++                           baseKey, PKCS11Constants.CKM_EXTRACT_KEY_FROM_KEY,param,null, 
++                           PKCS11Constants.CKA_ENCRYPT, PKCS11Constants.CKA_DERIVE,(long) 16);
++
++
++        SymmetricKey extracted16 = deriver.derive();
++
++        System.out.println("Derived key: " + extracted16);
++
++        if(extracted16 == null) {
++            System.out.println("Failed to derive 16 byte key with mechanism: CKM_EXTRACT_KEY_FROM_KEY \n");
++        }
++
++        System.out.println("derivedKey 16 bytes: ");
++        byte[] derivedBytes = extracted16.getEncoded();
++        displayByteArray(derivedBytes,true);
++
++
++        /*****************************************************************************************************/
++
++        System.out.println("\n Mechanism CKM_EXTRACT_KEY_FROM_KEY test 8 bytes. \n");
++
++
++        SymmetricKeyDeriver extract8 = token.getSymmetricKeyDeriver();
++        extract8.initDerive(
++                           extracted16, PKCS11Constants.CKM_EXTRACT_KEY_FROM_KEY,param,null,
++                           PKCS11Constants.CKA_ENCRYPT, PKCS11Constants.CKA_DERIVE,(long) 8);
++
++
++       SymmetricKey extracted8 = extract8.derive();
++       System.out.println("Derived key: " + extracted8);
++
++        if(extracted8 == null) {
++            System.out.println("Failed to derive key extracted 8 bytes with mechanism: CKM_EXTRACT_KEY_FROM_KEY \n");
++        }
++
++        byte[] extracted8Bytes = extracted8.getEncoded();
++        System.out.println("derived extracted 8 bytes of key: ");
++        displayByteArray(extracted8Bytes,true);
++
++
++        /*****************************************************************************************************/
++
++
++         System.out.println("\n Mechanism CKM_CONCATENATE_BASE_AND_KEY test 16 + 8 = 24 byte key. \n");
++
++        SymmetricKeyDeriver concat = keyToken.getSymmetricKeyDeriver();
++        concat.initDerive(
++                           extracted16,extracted8, PKCS11Constants.CKM_CONCATENATE_BASE_AND_KEY,null,null,
++                           PKCS11Constants.CKM_DES3_ECB, PKCS11Constants.CKA_DERIVE,(long) 0);
++
++        SymmetricKey concated24 =  concat.derive();
++
++        if( concated24 == null) {
++            System.out.println("Failed to derive key concated 8 bytes to 16 bytes key: CKM_CONCATENATE_BASE_AND_KEY \n");
++        }
++
++        byte[] concated24Bytes = concated24.getEncoded();
++        System.out.println("derived concated 16 + 8 = 24 byte key: ");
++        displayByteArray(concated24Bytes,true);
++
++        /*****************************************************************************************************/
++
++        // Now lets try  more complex derivation
++
++       // tmp2 = PK11_Derive( master , CKM_DES_ECB_ENCRYPT_DATA , &param , CKM_CONCATENATE_BASE_AND_KEY , CKA_DERIVE , 0);
++
++       System.out.println("\n Mechanism CKM_DES_ECB_ENCRYPT_DATA test. \n");
++
++       SymmetricKeyDeriver encrypt = token.getSymmetricKeyDeriver();
++
++       encrypt.initDerive(
++                           baseKeyDes, /* PKCS11Constants.CKM_DES_ECB_ENCRYPT_DATA */ 4352L,derivationData1 ,null,
++                           PKCS11Constants.CKM_DES_ECB, PKCS11Constants.CKA_DERIVE,(long) 8);
++
++       SymmetricKey encrypted8 = encrypt.derive();
++
++       if( encrypted8 == null) {
++            System.out.println("Failed to derive  8 bytes from encrypted derivation data.");
++        }
++
++        byte[] encrypted8Bytes = encrypted8.getEncoded();
++        System.out.println("derived encrypted 8 bytes: " + encrypted8Bytes.length);
++        displayByteArray(encrypted8Bytes,true);
++
++        Cipher cipher = null;
++        cipher =  keyToken.getCipherContext(EncryptionAlgorithm.DES_ECB);
++
++        cipher.initEncrypt(baseKeyDes);
++
++        byte[] ciphertext = cipher.doFinal(derivationData1);
++        displayByteArray(ciphertext,true);
++
++        if ( ciphertext.length != encrypted8Bytes.length ) {
++            System.out.println("FAILED: encrypted data length not equal to derived key length.");
++        } else {
++            for ( int i = 0; i < ciphertext.length ; i ++) {
++                ciphertext[i]&=0xfe;
++                encrypted8Bytes[i]&=0xfe;
++            }
++            if ( Arrays.equals(ciphertext, encrypted8Bytes)) {
++                System.out.println("PASSED: derived key the same as encrypted data.");
++            } else {
++
++                System.out.println("FAILED: derived key not the same as encrypted data.");
++            }
++        }
++
++
++        /*****************************************************************************************************/
++
++        // Try ecnrypted des3 derivation
++
++       System.out.println("\n Mechanism CKM_DES3_ECB_ENCRYPT_DATA test. \n");
++
++       SymmetricKeyDeriver encryptDes3 = token.getSymmetricKeyDeriver();
++
++       encryptDes3.initDerive(
++                           baseKey, /* PKCS11Constants.CKM_DES3_ECB_ENCRYPT_DATA */ 4354L  ,derivationData16 ,null,
++                           PKCS11Constants.CKM_DES3_ECB, PKCS11Constants.CKA_DERIVE,(long) 16);
++
++
++       SymmetricKey encrypted16 = encryptDes3.derive();
++
++       if ( encrypted16 == null) {
++           System.out.println("Failed to derive 16 bytes from encrypted derivation data.");
++       }
++
++       byte[] encrypted16Bytes = encrypted16.getEncoded();
++
++       System.out.println("derived encrypted 16 bytes: " + encrypted16Bytes.length);
++       displayByteArray(encrypted16Bytes,true);
++
++
++       cipher =  keyToken.getCipherContext(EncryptionAlgorithm.DES3_ECB);
++       cipher.initEncrypt(baseKey);
++       ciphertext = cipher.doFinal(derivationData16);
++       displayByteArray(ciphertext,true);
++
++       if ( ciphertext.length != encrypted16Bytes.length ) {
++           System.out.println("FAILED: encrypted data length not equal to derived key length.");
++       } else {
++           for ( int i = 0; i < ciphertext.length ; i ++) {
++               ciphertext[i]&=0xfe;
++               encrypted16Bytes[i]&=0xfe;
++           }
++           if ( Arrays.equals(ciphertext, encrypted16Bytes)) {
++               System.out.println("PASSED: derived key the same as encrypted data.");
++           } else {
++               System.out.println("FAILED: derived key not the same as encrypted data.");
++           }
++       }
++
++
++       /*****************************************************************************************************/
++
++       System.out.println("\n Mechanism CKM_DES_CBC_ENCRYPT_DATA test. \n");
++
++       SymmetricKeyDeriver encryptDesCBC = token.getSymmetricKeyDeriver();
++
++       encryptDesCBC.initDerive(
++                           baseKeyDes, /* PKCS11Constants.CKM_DES_CBC_ENCRYPT_DATA */ 4353L  ,derivationData1 ,iv8,
++                           PKCS11Constants.CKM_DES_CBC, PKCS11Constants.CKA_DERIVE,(long) 8);
++
++
++       SymmetricKey encryptedDesCBC = encryptDesCBC.derive();
++
++       if ( encryptedDesCBC == null) {
++           System.out.println("Failed to derive 8 bytes from encrypted derivation data.");
++       }
++
++       byte[] encryptedDesCBCBytes = encryptedDesCBC.getEncoded();
++
++       System.out.println("derived encrypted 8 bytes: " + encryptedDesCBCBytes.length);
++       displayByteArray(encryptedDesCBCBytes,true);
++
++
++       cipher =  keyToken.getCipherContext(EncryptionAlgorithm.DES_CBC);
++       cipher.initEncrypt(baseKeyDes,new IVParameterSpec(iv8));
++       ciphertext = cipher.doFinal(derivationData1);
++       displayByteArray(ciphertext,true);
++
++        if ( ciphertext.length != encryptedDesCBCBytes.length ) {
++            System.out.println("FAILED: encrypted data length not equal to derived key length.");
++        } else {
++            for ( int i = 0; i < ciphertext.length ; i ++) {
++                ciphertext[i]&=0xfe;
++                encryptedDesCBCBytes[i]&=0xfe;
++            }
++            if ( Arrays.equals(ciphertext, encryptedDesCBCBytes)) {
++                System.out.println("PASSED: derived key the same as encrypted data.");
++            } else {
++
++                System.out.println("FAILED: derived key not the same as encrypted data.");
++            }
++        }
++
++        /*****************************************************************************************************/
++
++       System.out.println("\n Mechanism CKM_DES3_CBC_ENCRYPT_DATA test. \n");
++        
++       SymmetricKeyDeriver encryptDes3CBC = token.getSymmetricKeyDeriver();
++
++       encryptDes3CBC.initDerive(
++                           baseKey, /* PKCS11Constants.CKM_DES3_CBC_ENCRYPT_DATA */ 4355L  ,derivationData16 ,iv8,
++                           PKCS11Constants.CKM_DES3_CBC, PKCS11Constants.CKA_DERIVE,(long) 16);
++        
++
++       SymmetricKey encryptedDes3CBC = encryptDes3CBC.derive();
++        
++       if ( encryptedDes3CBC == null) {
++           System.out.println("Failed to derive 16 bytes from encrypted derivation data.");
++       }
++        
++       byte[] encryptedDes3CBCBytes = encryptedDes3CBC.getEncoded();
++
++       System.out.println("derived encrypted 16 bytes: " + encryptedDes3CBCBytes.length);
++       displayByteArray(encryptedDes3CBCBytes,true);
++
++
++       cipher =  keyToken.getCipherContext(EncryptionAlgorithm.DES3_CBC);
++       cipher.initEncrypt(baseKey,new IVParameterSpec(iv8));
++       ciphertext = cipher.doFinal(derivationData16);
++       displayByteArray(ciphertext,true);
++
++        if ( ciphertext.length != encryptedDes3CBCBytes.length ) {
++            System.out.println("FAILED: encrypted data length not equal to derived key length.");
++        } else {
++            for ( int i = 0; i < ciphertext.length ; i ++) {
++                ciphertext[i]&=0xfe;
++                encryptedDes3CBCBytes[i]&=0xfe;
++            }
++            if ( Arrays.equals(ciphertext, encryptedDes3CBCBytes)) {
++                System.out.println("PASSED: derived key the same as encrypted data.");
++            } else {
++
++                System.out.println("FAILED: derived key not the same as encrypted data.");
++            }
++        }
++
++        /*****************************************************************************************************/
++
++       System.out.println("\n Mechanism CKM_AES_ECB_ENCRYPT_DATA test. \n");
++
++       SymmetricKeyDeriver encryptAESECB = token.getSymmetricKeyDeriver();
++
++       //System.in.read();
++       encryptAESECB.initDerive(
++                           baseKeyAES, /* PKCS11Constants.CKM_AES_ECB_ENCRYPT_DATA */ 4356L  ,derivationData16 ,null,
++                           PKCS11Constants.CKM_AES_ECB, PKCS11Constants.CKA_DERIVE,(long) 16);
++
++
++       SymmetricKey encryptedAESECB = encryptAESECB.derive();
++
++       if ( encryptedAESECB == null) {
++           System.out.println("Failed to derive 16 bytes from encrypted derivation data.");
++       }
++
++       byte[] encryptedAESECBBytes = encryptedAESECB.getEncoded();
++
++       System.out.println("derived encrypted 16 bytes: " + encryptedAESECBBytes.length);
++       displayByteArray(encryptedAESECBBytes,true);
++
++
++       cipher =  keyToken.getCipherContext(EncryptionAlgorithm.AES_128_ECB);
++       cipher.initEncrypt(baseKeyAES);
++       ciphertext = cipher.doFinal(derivationData16);
++       displayByteArray(ciphertext,true);
++
++        if ( ciphertext.length != encryptedAESECBBytes.length ) {
++            System.out.println("FAILED: encrypted data length not equal to derived key length.");
++        } else {
++            for ( int i = 0; i < ciphertext.length ; i ++) {
++                ciphertext[i]&=0xfe;
++                encryptedAESECBBytes[i]&=0xfe;
++            }
++            if ( Arrays.equals(ciphertext, encryptedAESECBBytes)) {
++                System.out.println("PASSED: derived key the same as encrypted data.");
++            } else {
++
++                System.out.println("FAILED: derived key not the same as encrypted data.");
++            }
++        }
++
++
++       /*****************************************************************************************************/
++
++       System.out.println("\n Mechanism CKM_AES_CBC_ENCRYPT_DATA test. \n");
++
++       SymmetricKeyDeriver encryptAESCBC= token.getSymmetricKeyDeriver();
++
++       //System.in.read();
++       encryptAESCBC.initDerive(
++                           baseKeyAES, /* PKCS11Constants.CKM_AES_CBC_ENCRYPT_DATA */ 4357L  ,derivationData16 ,iv16,
++                           PKCS11Constants.CKM_AES_CBC, PKCS11Constants.CKA_DERIVE,(long) 16);
++
++
++       SymmetricKey encryptedAESCBC = encryptAESCBC.derive();
++
++       if ( encryptedAESCBC == null) {
++           System.out.println("Failed to derive 16 bytes from encrypted derivation data.");
++       }
++
++       byte[] encryptedAESCBCBytes = encryptedAESCBC.getEncoded();
++
++       System.out.println("derived encrypted 16 bytes: " + encryptedAESCBCBytes.length);
++       displayByteArray(encryptedAESCBCBytes,true);
++
++
++       cipher =  keyToken.getCipherContext(EncryptionAlgorithm.AES_128_CBC);
++       cipher.initEncrypt(baseKeyAES,new IVParameterSpec(iv16));
++       ciphertext = cipher.doFinal(derivationData16);
++       displayByteArray(ciphertext,true);
++
++        if ( ciphertext.length != encryptedAESCBCBytes.length ) {
++            System.out.println("FAILED: encrypted data length not equal to derived key length.");
++        } else {
++            for ( int i = 0; i < ciphertext.length ; i ++) {
++                ciphertext[i]&=0xfe;
++                encryptedAESCBCBytes[i]&=0xfe;
++            }
++            if ( Arrays.equals(ciphertext, encryptedAESCBCBytes)) {
++                System.out.println("PASSED: derived key the same as encrypted data.");
++            } else {
++
++                System.out.println("FAILED: derived key not the same as encrypted data.");
++            }
++        }
++
++        // get vector of symkeys
++
++        Enumeration<CryptoToken> ect = null; 
++        ect = (Enumeration<CryptoToken>) cm.getAllTokens(); 
++        CryptoToken ct = null; //ct = cm.getTokenByName("ePass Token"); 
++        while (ect.hasMoreElements()) 
++        { 
++          ct = ect.nextElement(); 
++          System.out.println("CryptoToken.name= " + ct.getName()); 
++        } 
++
++        SymmetricKey[] keys = keyToken.getCryptoStore().getSymmetricKeys();
++
++        SymmetricKey macKey = getSymKeyByName(keys, "defKeySet-macKey");
++
++        System.out.println("macKey: " + macKey);
++
++      } catch(Exception e) {
++        e.printStackTrace();
++      }
++    }
++
++    public static void
++    displayByteArray(byte[] ba, boolean has_check_sum) {
++        char mask = 0xff;
++
++        if ( has_check_sum == true )
++            mask = 0xfe;
++
++        for(int i=0; i < ba.length; i++) {
++ 
++            System.out.print( Integer.toHexString(ba[i]&mask) + " " );
++            if( (i % 26) == 25 ) {
++                System.out.println("");
++            }
++        }
++        System.out.println("");
++    }
++
++    public static  byte[] longToBytes(long x) {
++        ByteBuffer buffer = ByteBuffer.allocate(8);
++        buffer.putLong(x);
++        return buffer.array();
++    }
++
++    public static byte[] concatByteArrays(byte[] a, byte[] b) {
++        byte[] result = new byte[a.length + b.length]; 
++        System.arraycopy(a, 0, result, 0, a.length); 
++        System.arraycopy(b, 0, result, a.length, b.length); 
++        return result;
++    }
++
++    public static SymmetricKey getSymKeyByName( SymmetricKey[] keys, String name) {
++        if ( keys == null || name == null ) {
++            return null;
++        }
++
++        int len = keys.length;
++        for(int i = 0 ; i < len ; i++ ) {
++            SymmetricKey cur = keys[i];
++            if ( cur != null ) {
++                if( name.equals(cur.getNickName())) {
++                    System.out.println("Found key: " + name + "\n");
++                    return cur; 
++                }
++            }
++        }
++
++        return null;
++    }
++}
+diff -up ./mozilla/security/jss/org/mozilla/jss/util/java_ids.h.jmagne ./mozilla/security/jss/org/mozilla/jss/util/java_ids.h
+--- ./mozilla/security/jss/org/mozilla/jss/util/java_ids.h.jmagne	2016-04-14 16:34:36.729287416 -0700
++++ ./mozilla/security/jss/org/mozilla/jss/util/java_ids.h	2016-04-14 16:34:45.608226163 -0700
+@@ -243,6 +243,7 @@ PR_BEGIN_EXTERN_C
+  */
+ #define PK11SYMKEY_CLASS_NAME "org/mozilla/jss/pkcs11/PK11SymKey"
+ #define PK11SYMKEY_CONSTRUCTOR_SIG "([B)V"
++#define PK11SYMKEY_CONSTRUCTOR_1_SIG "([BLjava/lang/String;)V" 
+ 
+ /*
+  * PK11Token
diff --git a/SPECS/jss.spec b/SPECS/jss.spec
index 3fa15a9..cc130dc 100644
--- a/SPECS/jss.spec
+++ b/SPECS/jss.spec
@@ -1,6 +1,6 @@
 Name:           jss
 Version:        4.2.6
-Release:        37%{?dist}
+Release:        42%{?dist}
 Summary:        Java Security Services (JSS)
 
 Group:          System Environment/Libraries
@@ -16,11 +16,11 @@ Source2:        http://pki.fedoraproject.org/pki/sources/%{name}/%{name}-%{versi
 Source3:        http://pki.fedoraproject.org/pki/sources/%{name}/%{name}-%{version}-%{release}/lgpl.txt
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
-BuildRequires:  nss-devel >= 3.12.3.99
-BuildRequires:  nspr-devel >= 4.6.99
+BuildRequires:  nss-devel >= 3.21.0
+BuildRequires:  nspr-devel >= 4.11.0
 BuildRequires:  java-devel
 Requires:       java
-Requires:       nss >= 3.12.3.99
+Requires:       nss >= 3.21.0
 
 Patch1:         jss-key_pair_usage_with_op_flags.patch
 Patch2:         jss-javadocs-param.patch
@@ -50,6 +50,11 @@ Patch25:        jss-RC4-strengh-verify.patch
 Patch26:        jss-support-TLS1_1-TLS1_2.patch
 Patch27:        jss-WindowsCompileFix.patch
 Patch28:        jss-WindowsLoadLibrary.patch
+Patch29:        jss-Fixed-build-failures.patch
+Patch30:        jss-VerifyCertificate-enhancement.patch
+Patch31:        jss-lunasaUnwrap.patch
+Patch32:        jss-symkey-enhancements.patch
+Patch33:        jss-crmf-envelopedData.patch
 
 %description
 Java Security Services (JSS) is a java native interface which provides a bridge
@@ -94,6 +99,11 @@ This package contains the API documentation for JSS.
 %patch26 -p1
 %patch27 -p1
 %patch28 -p1
+%patch29 -p1
+%patch30 -p1
+%patch31 -p1
+%patch32 -p1
+%patch33 -p1
 
 %build
 [ -z "$JAVA_HOME" ] && export JAVA_HOME=%{_jvmdir}/java
@@ -198,6 +208,23 @@ rm -rf $RPM_BUILD_ROOT
 
 
 %changelog
+* Tue Aug 9 2016 Christina Fu <cfu@redhat.com> - 4.2.6-42
+- Sync up patches from both Fedora and RHEL; adding one patch
+  (cfu, edewata, mharmsen) from RHEL:
+- Bugzilla Bug #1289799 - JSS build failure on F23 and Rawhide (edewata)
+
+* Fri Jun 24 2016 Christina Fu <cfu@redhat.com> - 4.2.6-41
+- Bugzilla 1221295 jss fails to decode EncryptedKey >> EnvelopedData
+  (cfu for roysjosh@gmail.com)
+
+* Thu May 19 2016 Christina Fu <cfu@redhat.com> - 4.2.6-40
+- Bugzilla 1074208 - pass up exact JSS certificate validation errors from NSS
+  (edewata)
+- Bugzilla 1331596 - Key archival fails when KRA is configured with lunasa.
+  (cfu)
+- PKI ticket 801 - Merge pki-symkey into jss (phase 1)
+  (jmagne)
+
 * Wed Jul 8 2015 Christina Fu <cfu@redhat.com> - 4.2.6-37
 - Bugzilla Bug #1238450 - UnsatisfiedLinkError on Windows