You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2017/06/30 14:17:56 UTC

[2/2] cxf git commit: [CXF-7434] JweJson and other related improvements

[CXF-7434] JweJson and other related improvements


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/33eb378e
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/33eb378e
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/33eb378e

Branch: refs/heads/master
Commit: 33eb378e47cee7d9c2ce0f7cb04cf0d5bcce4ad7
Parents: e4328f8
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Fri Jun 30 15:17:38 2017 +0100
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Fri Jun 30 15:17:38 2017 +0100

----------------------------------------------------------------------
 .../cxf/jaxrs/json/basic/JsonMapObject.java     |   4 +
 .../jaxrs/AbstractJweJsonWriterProvider.java    | 102 ++++++-
 .../jaxrs/AbstractJwsJsonWriterProvider.java    |  29 +-
 .../jose/jaxrs/JweJsonWriterInterceptor.java    |  38 +--
 .../jose/jaxrs/JwsJsonWriterInterceptor.java    |  39 ++-
 .../JwsMultipartSignatureInFilter.java          |   2 +-
 .../cxf/rs/security/jose/common/JoseUtils.java  |  12 +
 .../jose/common/KeyManagementUtils.java         |  13 +
 .../cxf/rs/security/jose/jwa/KeyAlgorithm.java  |   3 +
 .../jose/jwe/DirectKeyDecryptionAlgorithm.java  |   2 +-
 .../jose/jwe/DirectKeyEncryptionAlgorithm.java  |   5 +-
 .../rs/security/jose/jwe/JweJsonConsumer.java   |   3 +-
 .../jose/jwe/JweJsonEncryptionEntry.java        |   2 +-
 .../rs/security/jose/jwe/JweJsonProducer.java   |   9 +-
 .../cxf/rs/security/jose/jwe/JweUtils.java      | 277 ++++++++++---------
 .../cxf/rs/security/jose/jws/JwsUtils.java      | 115 ++------
 .../security/jose/jwe/JweJsonConsumerTest.java  |   8 +-
 .../cxf/rs/security/jose/jws/JwsUtilsTest.java  |   3 +-
 .../token/provider/jwt/JWTTokenProvider.java    |   2 +-
 .../token/provider/JWTTokenProviderTest.java    |   6 +-
 .../jaxrs/JAXRSClientServerBookTest.java        |   2 +-
 .../systest/jaxrs/security/jose/BookStore.java  |  50 +++-
 .../security/jose/jwejws/JAXRSJweJsonTest.java  |  59 ++--
 .../security/jose/jwejws/JAXRSJweJwsTest.java   |  29 ++
 .../security/jose/jwejws/JAXRSJwsJsonTest.java  |  17 +-
 .../jaxrs/security/certs/jwkPrivateSet.txt      |  11 +
 .../jaxrs/security/jose/jwejws/server.xml       |  12 +
 .../security/jose/jwejws/serverJweJson.xml      |  25 +-
 .../jaxrs/security/jwe.direct.properties        |  21 ++
 .../systest/jaxrs/security/jwejson1.properties  |  22 ++
 .../systest/jaxrs/security/jwejson2.properties  |  22 ++
 .../jaxrs/security/secret.jwk.hmac2.properties  |  19 --
 32 files changed, 607 insertions(+), 356 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java
----------------------------------------------------------------------
diff --git a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java
index 184b525..e1bf0bb 100644
--- a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java
+++ b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObject.java
@@ -121,4 +121,8 @@ public class JsonMapObject implements Serializable {
     public Map<String, Object> getUpdateCount() {
         return updateCount == null ? null : Collections.<String, Object>unmodifiableMap(updateCount);
     }
+    
+    public Object removeProperty(String name) {
+        return values.remove(name);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonWriterProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonWriterProvider.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonWriterProvider.java
index d131c8d..8e41ac4 100644
--- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonWriterProvider.java
+++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJweJsonWriterProvider.java
@@ -21,10 +21,14 @@ package org.apache.cxf.rs.security.jose.jaxrs;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Properties;
+import java.util.Set;
 import java.util.logging.Logger;
 
 import org.apache.cxf.common.logging.LogUtils;
@@ -35,9 +39,18 @@ import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.rs.security.jose.common.JoseConstants;
+import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
+import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.ContentEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweEncryption;
 import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweException;
+import org.apache.cxf.rs.security.jose.jwe.JweHeaders;
 import org.apache.cxf.rs.security.jose.jwe.JweUtils;
-import org.apache.cxf.rs.security.jose.jws.JwsException;
+import org.apache.cxf.rs.security.jose.jwe.KeyEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
+import org.apache.cxf.rs.security.jose.jwk.KeyOperation;
 import org.apache.cxf.rs.security.jose.jws.JwsJsonProducer;
 
 public class AbstractJweJsonWriterProvider {
@@ -52,17 +65,18 @@ public class AbstractJweJsonWriterProvider {
         this.encProviders = providers;
     }
 
-    protected List<JweEncryptionProvider> getInitializedEncryptionProviders() {
-        if (encProviders != null) {
-            return encProviders;
-        }
+    protected List<String> getPropertyLocations() {
         Message m = JAXRSUtils.getCurrentMessage();
         Object propLocsProp =
             MessageUtils.getContextualProperty(m, JoseConstants.RSSEC_ENCRYPTION_OUT_PROPS,
                                                JoseConstants.RSSEC_ENCRYPTION_PROPS);
         if (propLocsProp == null) {
-            LOG.warning("JWE JSON init properties resource is not identified");
-            throw new JwsException(JwsException.Error.NO_INIT_PROPERTIES);
+            if (encProviders == null) {
+                LOG.warning("JWE JSON init properties resource is not identified");
+                throw new JweException(JweException.Error.NO_INIT_PROPERTIES);
+            } else {
+                return Collections.emptyList();
+            }
         }
         List<String> propLocs = null;
         if (propLocsProp instanceof String) {
@@ -71,9 +85,79 @@ public class AbstractJweJsonWriterProvider {
         } else {
             propLocs = CastUtils.cast((List<?>)propLocsProp);
         }
+        return propLocs;
+    }
+    
+    protected List<JweEncryptionProvider> getInitializedEncryptionProviders(List<String> propLocs,
+                                              JweHeaders sharedProtectedHeaders,
+                                              List<JweHeaders> perRecipientUnprotectedHeaders) {
+        if (encProviders != null) {
+            return encProviders;
+        }
+        // The task is to have a single ContentEncryptionProvider instance, 
+        // configured to generate CEK only once, paired with all the loaded
+        // KeyEncryptionProviders to have JweEncryptionProviders initialized
+        
+        Message m = JAXRSUtils.getCurrentMessage();
+        // Load all the properties
+        List<Properties> propsList = new ArrayList<Properties>(propLocs.size());
+        for (int i = 0; i < propLocs.size(); i++) {
+            propsList.add(JweUtils.loadJweProperties(m, propLocs.get(i)));
+        }
+        
+        
+        ContentAlgorithm ctAlgo = null;
+        // This set is to find out how many key encryption algorithms are used
+        // If only one then save it in the shared protected headers as opposed to
+        // per-recipient specific not protected ones
+        Set<KeyAlgorithm> keyAlgos = new HashSet<KeyAlgorithm>();
+        
+        List<KeyEncryptionProvider> keyProviders = new LinkedList<KeyEncryptionProvider>();
+        for (int i = 0; i < propLocs.size(); i++) {
+            Properties props = propsList.get(i);
+            ContentAlgorithm currentCtAlgo = JweUtils.getContentEncryptionAlgorithm(m, props, ContentAlgorithm.A128GCM);
+            if (ctAlgo == null) {
+                ctAlgo = currentCtAlgo;
+            } else if (currentCtAlgo != null && !ctAlgo.equals(currentCtAlgo)) {
+                // ctAlgo must be the same for all the recipients
+                throw new JweException(JweException.Error.INVALID_CONTENT_ALGORITHM);
+            }
+            
+            JweHeaders perRecipientUnprotectedHeader = perRecipientUnprotectedHeaders.get(i);
+            KeyEncryptionProvider keyEncryptionProvider = 
+                JweUtils.loadKeyEncryptionProvider(props, m, perRecipientUnprotectedHeader);
+            if (keyEncryptionProvider.getAlgorithm() == KeyAlgorithm.DIRECT && propLocs.size() > 1) {
+                throw new JweException(JweException.Error.INVALID_JSON_JWE);
+            }
+            keyProviders.add(keyEncryptionProvider);
+            
+            keyAlgos.add(perRecipientUnprotectedHeader.getKeyEncryptionAlgorithm());
+        }
+        if (ctAlgo == null) {
+            throw new JweException(JweException.Error.INVALID_CONTENT_ALGORITHM);
+        }
+        sharedProtectedHeaders.setContentEncryptionAlgorithm(ctAlgo);
+        
         List<JweEncryptionProvider> theEncProviders = new LinkedList<JweEncryptionProvider>();
-        for (String propLoc : propLocs) {
-            theEncProviders.addAll(JweUtils.loadJweEncryptionProviders(propLoc, m));
+        if (keyProviders.size() == 1 && keyProviders.get(0).getAlgorithm() == KeyAlgorithm.DIRECT) {
+            JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, propsList.get(0), KeyOperation.ENCRYPT);
+            if (jwk != null) {
+                ContentEncryptionProvider ctProvider = JweUtils.getContentEncryptionProvider(jwk, ctAlgo);
+                JweEncryptionProvider encProvider = new JweEncryption(keyProviders.get(0), ctProvider);
+                theEncProviders.add(encProvider);
+            }
+        } else {
+            ContentEncryptionProvider ctProvider = JweUtils.getContentEncryptionProvider(ctAlgo, true);
+            for (int i = 0; i < keyProviders.size(); i++) {
+                JweEncryptionProvider encProvider = new JweEncryption(keyProviders.get(0), ctProvider);
+                theEncProviders.add(encProvider);
+            }
+        }
+        if (keyAlgos.size() == 1) {
+            sharedProtectedHeaders.setKeyEncryptionAlgorithm(keyAlgos.iterator().next());
+            for (int i = 0; i < perRecipientUnprotectedHeaders.size(); i++) {
+                perRecipientUnprotectedHeaders.get(i).removeProperty(JoseConstants.JWE_HEADER_KEY_ENC_ALGORITHM);
+            }
         }
         return theEncProviders;
     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonWriterProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonWriterProvider.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonWriterProvider.java
index 31db16d..d2f10c3 100644
--- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonWriterProvider.java
+++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/AbstractJwsJsonWriterProvider.java
@@ -25,6 +25,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Properties;
 import java.util.logging.Logger;
 
 import org.apache.cxf.common.logging.LogUtils;
@@ -36,6 +37,7 @@ import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.rs.security.jose.common.JoseConstants;
 import org.apache.cxf.rs.security.jose.jws.JwsException;
+import org.apache.cxf.rs.security.jose.jws.JwsHeaders;
 import org.apache.cxf.rs.security.jose.jws.JwsJsonProducer;
 import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
 import org.apache.cxf.rs.security.jose.jws.JwsUtils;
@@ -52,17 +54,18 @@ public class AbstractJwsJsonWriterProvider {
         this.sigProviders = signatureProviders;
     }
 
-    protected List<JwsSignatureProvider> getInitializedSigProviders() {
-        if (sigProviders != null) {
-            return sigProviders;
-        }
+    protected List<String> getPropertyLocations() {
         Message m = JAXRSUtils.getCurrentMessage();
         Object propLocsProp =
             MessageUtils.getContextualProperty(m, JoseConstants.RSSEC_SIGNATURE_OUT_PROPS,
                                                JoseConstants.RSSEC_SIGNATURE_PROPS);
         if (propLocsProp == null) {
-            LOG.warning("JWS JSON init properties resource is not identified");
-            throw new JwsException(JwsException.Error.NO_INIT_PROPERTIES);
+            if (sigProviders == null) {
+                LOG.warning("JWS JSON init properties resource is not identified");
+                throw new JwsException(JwsException.Error.NO_INIT_PROPERTIES);
+            } else {
+                return Collections.emptyList();
+            }
         }
         List<String> propLocs = null;
         if (propLocsProp instanceof String) {
@@ -71,9 +74,19 @@ public class AbstractJwsJsonWriterProvider {
         } else {
             propLocs = CastUtils.cast((List<?>)propLocsProp);
         }
+        return propLocs;
+    }
+    
+    protected List<JwsSignatureProvider> getInitializedSigProviders(
+        List<String> propLocs, List<JwsHeaders> protectedHeaders) {
+        if (sigProviders != null) {
+            return sigProviders;
+        }
+        Message m = JAXRSUtils.getCurrentMessage();
         List<JwsSignatureProvider> theSigProviders = new LinkedList<JwsSignatureProvider>();
-        for (String propLoc : propLocs) {
-            theSigProviders.addAll(JwsUtils.loadSignatureProviders(propLoc, m));
+        for (int i = 0; i < propLocs.size(); i++) {
+            Properties props = JwsUtils.loadJwsProperties(m, propLocs.get(i));
+            theSigProviders.add(JwsUtils.loadSignatureProvider(props, protectedHeaders.get(i)));
         }
         return theSigProviders;
     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java
index 9d0926f..9405a2c 100644
--- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java
+++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonWriterInterceptor.java
@@ -36,8 +36,6 @@ import org.apache.cxf.helpers.IOUtils;
 import org.apache.cxf.io.CachedOutputStream;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.rs.security.jose.common.JoseConstants;
-import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
-import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
 import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
 import org.apache.cxf.rs.security.jose.jwe.JweHeaders;
 import org.apache.cxf.rs.security.jose.jwe.JweJsonProducer;
@@ -55,7 +53,15 @@ public class JweJsonWriterInterceptor extends AbstractJweJsonWriterProvider impl
             return;
         }
         OutputStream actualOs = ctx.getOutputStream();
-        List<JweEncryptionProvider> providers = getInitializedEncryptionProviders();
+        JweHeaders sharedProtectedHeaders = new JweHeaders();
+        List<String> propLocs = getPropertyLocations();
+        List<JweHeaders> perRecipientUnprotectedHeaders = new ArrayList<JweHeaders>(propLocs.size());
+        for (int i = 0; i < propLocs.size(); i++) {
+            perRecipientUnprotectedHeaders.add(new JweHeaders());
+        }
+        List<JweEncryptionProvider> providers = getInitializedEncryptionProviders(propLocs,
+                                                                                  sharedProtectedHeaders,
+                                                                                  perRecipientUnprotectedHeaders);
 
         String ctString = null;
         MediaType contentMediaType = ctx.getMediaType();
@@ -66,30 +72,10 @@ public class JweJsonWriterInterceptor extends AbstractJweJsonWriterProvider impl
                 ctString = JAXRSUtils.mediaTypeToString(contentMediaType);
             }
         }
-        JweHeaders protectedHeaders = new JweHeaders(ContentAlgorithm.A128GCM);
         if (ctString != null) {
-            protectedHeaders.setContentType(ctString);
-        }
-        protectHttpHeadersIfNeeded(ctx, protectedHeaders);
-        List<KeyAlgorithm> keyAlgos = new ArrayList<>();
-        for (JweEncryptionProvider p : providers) {
-            if (!keyAlgos.contains(p.getKeyAlgorithm())) {
-                keyAlgos.add(p.getKeyAlgorithm());
-            }
-        }
-        List<JweHeaders> perRecipientUnprotectedHeaders = null;
-        if (keyAlgos.size() == 1) {
-            // Can be optionally set in shared unprotected headers
-            // or per-recipient headers
-            protectedHeaders.setKeyEncryptionAlgorithm(keyAlgos.get(0));
-        } else {
-            perRecipientUnprotectedHeaders = new ArrayList<>();
-            for (KeyAlgorithm keyAlgo : keyAlgos) {
-                JweHeaders headers = new JweHeaders();
-                headers.setKeyEncryptionAlgorithm(keyAlgo);
-                perRecipientUnprotectedHeaders.add(headers);
-            }
+            sharedProtectedHeaders.setContentType(ctString);
         }
+        protectHttpHeadersIfNeeded(ctx, sharedProtectedHeaders);
         if (useJweOutputStream) {
             //TODO
         } else {
@@ -99,7 +85,7 @@ public class JweJsonWriterInterceptor extends AbstractJweJsonWriterProvider impl
 
 
 
-            JweJsonProducer producer = new JweJsonProducer(protectedHeaders, cos.getBytes());
+            JweJsonProducer producer = new JweJsonProducer(sharedProtectedHeaders, cos.getBytes());
             String jweContent = producer.encryptWith(providers, perRecipientUnprotectedHeaders);
 
             setJoseMediaType(ctx);

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java
index 6aca136..0ac3000 100644
--- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java
+++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java
@@ -59,15 +59,23 @@ public class JwsJsonWriterInterceptor extends AbstractJwsJsonWriterProvider impl
             ctx.proceed();
             return;
         }
-        List<JwsSignatureProvider> sigProviders = getInitializedSigProviders();
+        List<String> propLocs = getPropertyLocations();
+        List<JwsHeaders> protectedHeaders = new ArrayList<JwsHeaders>(propLocs.size());
+        for (int i = 0; i < propLocs.size(); i++) {
+            protectedHeaders.add(new JwsHeaders());
+        }
+        List<JwsSignatureProvider> sigProviders = getInitializedSigProviders(propLocs, protectedHeaders);
         OutputStream actualOs = ctx.getOutputStream();
         if (useJwsOutputStream) {
-            List<String> protectedHeaders = new ArrayList<>(sigProviders.size());
+            List<String> encodedProtectedHeaders = new ArrayList<>(sigProviders.size());
             List<JwsSignature> signatures = new ArrayList<>(sigProviders.size());
-            for (JwsSignatureProvider signer : sigProviders) {
-                JwsHeaders protectedHeader = prepareProtectedHeader(ctx, signer);
+            int size = sigProviders.size();
+            for (int i = 0; i < size; i++) {
+                JwsSignatureProvider signer = sigProviders.get(i);
+                JwsHeaders protectedHeader = protectedHeaders.get(i);
+                prepareProtectedHeader(protectedHeader, ctx, signer, size == 1);
                 String encoded = Base64UrlUtility.encode(writer.toJson(protectedHeader));
-                protectedHeaders.add(encoded);
+                encodedProtectedHeaders.add(encoded);
                 JwsSignature signature = signer.createJwsSignature(protectedHeader);
                 byte[] start = StringUtils.toBytesUTF8(encoded + ".");
                 signature.update(start, 0, start.length);
@@ -75,7 +83,7 @@ public class JwsJsonWriterInterceptor extends AbstractJwsJsonWriterProvider impl
             }
             ctx.setMediaType(JAXRSUtils.toMediaType(JoseConstants.MEDIA_TYPE_JOSE_JSON));
             actualOs.write(StringUtils.toBytesUTF8("{\"payload\":\""));
-            JwsJsonOutputStream jwsStream = new JwsJsonOutputStream(actualOs, protectedHeaders, signatures);
+            JwsJsonOutputStream jwsStream = new JwsJsonOutputStream(actualOs, encodedProtectedHeaders, signatures);
 
             Base64UrlOutputStream base64Stream = null;
             if (encodePayload) {
@@ -94,8 +102,11 @@ public class JwsJsonWriterInterceptor extends AbstractJwsJsonWriterProvider impl
             ctx.setOutputStream(cos);
             ctx.proceed();
             JwsJsonProducer p = new JwsJsonProducer(new String(cos.getBytes(), StandardCharsets.UTF_8));
-            for (JwsSignatureProvider signer : sigProviders) {
-                JwsHeaders protectedHeader = prepareProtectedHeader(ctx, signer);
+            int size = sigProviders.size();
+            for (int i = 0; i < size; i++) {
+                JwsSignatureProvider signer = sigProviders.get(i);
+                JwsHeaders protectedHeader = protectedHeaders.get(i);
+                prepareProtectedHeader(protectedHeader, ctx, signer, size == 1);
                 p.signWith(signer, protectedHeader, null);
             }
             ctx.setMediaType(JAXRSUtils.toMediaType(JoseConstants.MEDIA_TYPE_JOSE_JSON));
@@ -104,16 +115,18 @@ public class JwsJsonWriterInterceptor extends AbstractJwsJsonWriterProvider impl
 
     }
 
-    private JwsHeaders prepareProtectedHeader(WriterInterceptorContext ctx,
-                                              JwsSignatureProvider signer) {
-        JwsHeaders headers = new JwsHeaders();
+    private void prepareProtectedHeader(JwsHeaders headers,
+                                        WriterInterceptorContext ctx,
+                                        JwsSignatureProvider signer,
+                                        boolean protectHttp) {
         headers.setSignatureAlgorithm(signer.getAlgorithm());
         setContentTypeIfNeeded(headers, ctx);
         if (!encodePayload) {
             headers.setPayloadEncodingStatus(false);
         }
-        protectHttpHeadersIfNeeded(ctx, headers);
-        return headers;
+        if (protectHttp) {
+            protectHttpHeadersIfNeeded(ctx, headers);
+        }
     }
 
     public void setContentTypeRequired(boolean contentTypeRequired) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartSignatureInFilter.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartSignatureInFilter.java b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartSignatureInFilter.java
index e0a306d..2234850 100644
--- a/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartSignatureInFilter.java
+++ b/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartSignatureInFilter.java
@@ -103,7 +103,7 @@ public class JwsMultipartSignatureInFilter implements MultipartInputFilter {
                                                    JoseConstants.RSSEC_SIGNATURE_IN_PROPS,
                                                    JoseConstants.RSSEC_SIGNATURE_PROPS);
             
-            theVerifier = JwsUtils.loadSignatureVerifier(message, props, headers, false);
+            theVerifier = JwsUtils.loadSignatureVerifier(message, props, headers);
         } else {
             theVerifier = verifier;
         }

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
index 428c775..470ede1 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseUtils.java
@@ -31,6 +31,7 @@ import java.util.logging.Logger;
 import org.apache.cxf.Bus;
 import org.apache.cxf.common.classloader.ClassLoaderUtils;
 import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.PropertyUtils;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
 import org.apache.cxf.message.Message;
@@ -204,6 +205,17 @@ public final class JoseUtils {
         return props;
     }
 
+    public static boolean checkBooleanProperty(JoseHeaders headers, Properties props, Message m,
+                                                String propertyName) {
+        if (headers == null) {
+            return false;
+        }
+        if (props.containsKey(propertyName)) {
+            return PropertyUtils.isTrue(props.get(propertyName));
+        }
+        return MessageUtils.getContextualBoolean(m, propertyName, false);
+    }
+    
     //
     // <End> Copied from JAX-RS RT FRONTEND ResourceUtils
     //

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
index 63c0b08..2b020df 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
@@ -505,4 +505,17 @@ public final class KeyManagementUtils {
 
         return null;
     }
+    
+    public static void setSha1DigestHeader(JoseHeaders headers, Message m, Properties props) {
+        String digest = loadDigestAndEncodeX509Certificate(m, props, MessageDigestUtils.ALGO_SHA_1);
+        if (digest != null) {
+            headers.setX509Thumbprint(digest);
+        }
+    }
+    public static void setSha256DigestHeader(JoseHeaders headers, Message m, Properties props) {
+        String digest = loadDigestAndEncodeX509Certificate(m, props, MessageDigestUtils.ALGO_SHA_256);
+        if (digest != null) {
+            headers.setX509ThumbprintSHA256(digest);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/KeyAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/KeyAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/KeyAlgorithm.java
index a403da0..460696d 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/KeyAlgorithm.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/KeyAlgorithm.java
@@ -71,6 +71,9 @@ public enum KeyAlgorithm {
         if (algo == null) {
             return null;
         }
+        if (KeyAlgorithm.DIRECT.getJwaName().equals(algo)) {
+            return KeyAlgorithm.DIRECT;
+        }
         return KeyAlgorithm.valueOf(algo.replace('-', '_')
                                     .replace('+', '_'));
 

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyDecryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyDecryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyDecryptionAlgorithm.java
index 3f5c955..92bc469 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyDecryptionAlgorithm.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyDecryptionAlgorithm.java
@@ -44,7 +44,7 @@ public class DirectKeyDecryptionAlgorithm implements KeyDecryptionProvider {
     }
     @Override
     public KeyAlgorithm getAlgorithm() {
-        return null;
+        return KeyAlgorithm.DIRECT;
     }
     protected void validateKeyEncryptionKey(JweDecryptionInput jweDecryptionInput) {
         byte[] encryptedCEK = jweDecryptionInput.getEncryptedCEK();

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyEncryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyEncryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyEncryptionAlgorithm.java
index 2f038a9..584390a 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyEncryptionAlgorithm.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyEncryptionAlgorithm.java
@@ -30,13 +30,14 @@ public class DirectKeyEncryptionAlgorithm implements KeyEncryptionProvider {
         return new byte[0];
     }
     protected void checkKeyEncryptionAlgorithm(JweHeaders headers) {
-        if (headers.getKeyEncryptionAlgorithm() != null) {
+        KeyAlgorithm keyAlgo = headers.getKeyEncryptionAlgorithm();
+        if (keyAlgo != null && !KeyAlgorithm.DIRECT.equals(keyAlgo)) {
             LOG.warning("Key encryption algorithm header is set");
             throw new JweException(JweException.Error.INVALID_KEY_ALGORITHM);
         }
     }
     @Override
     public KeyAlgorithm getAlgorithm() {
-        return null;
+        return KeyAlgorithm.DIRECT;
     }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java
index 4b71f8d..c457a2c 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java
@@ -93,7 +93,8 @@ public class JweJsonConsumer {
         for (Map.Entry<JweJsonEncryptionEntry, JweHeaders> entry : recipientsMap.entrySet()) {
             KeyAlgorithm keyAlgo = entry.getValue().getKeyEncryptionAlgorithm();
             if (keyAlgo != null && keyAlgo.equals(jwe.getKeyAlgorithm())
-                || keyAlgo == null && jwe.getKeyAlgorithm() == null) {
+                || keyAlgo == null 
+                    && (jwe.getKeyAlgorithm() == null || KeyAlgorithm.DIRECT.equals(jwe.getKeyAlgorithm()))) {
                 if (recipientProps != null
                     && !entry.getValue().asMap().entrySet().containsAll(recipientProps.entrySet())) {
                     continue;

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
index f13502e..55f9897 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
@@ -47,7 +47,7 @@ public class JweJsonEncryptionEntry implements JsonObject {
     public String toJson() {
         JsonMapObjectReaderWriter jsonWriter = new JsonMapObjectReaderWriter();
         Map<String, Object> recipientsEntry = new LinkedHashMap<String, Object>();
-        if (unprotectedHeader != null) {
+        if (unprotectedHeader != null && !unprotectedHeader.asMap().isEmpty()) {
             recipientsEntry.put("header", this.unprotectedHeader);
         }
         if (encodedEncryptedKey != null) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducer.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducer.java
index 48f4145..0f5ae53 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducer.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducer.java
@@ -31,6 +31,7 @@ import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.util.Base64UrlUtility;
 import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
 import org.apache.cxf.rs.security.jose.common.JoseConstants;
+import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
 
 public class JweJsonProducer {
     protected static final Logger LOG = LogUtils.getL7dLogger(JweJsonProducer.class);
@@ -106,7 +107,7 @@ public class JweJsonProducer {
             JweHeaders perRecipientUnprotected =
                 recipientUnprotected == null ? null : recipientUnprotected.get(i);
             JweHeaders jsonHeaders = null;
-            if (perRecipientUnprotected != null) {
+            if (perRecipientUnprotected != null && !perRecipientUnprotected.asMap().isEmpty()) {
                 checkCriticalHeaders(perRecipientUnprotected);
                 if (!Collections.disjoint(unionHeaders.asMap().keySet(),
                                           perRecipientUnprotected.asMap().keySet())) {
@@ -140,7 +141,9 @@ public class JweJsonProducer {
             }
 
             byte[] encryptedCek = state.getContentEncryptionKey();
-            if (encryptedCek.length == 0 && encryptor.getKeyAlgorithm() != null) {
+            if (encryptedCek.length == 0 
+                && encryptor.getKeyAlgorithm() != null
+                && !KeyAlgorithm.DIRECT.equals(encryptor.getKeyAlgorithm())) {
                 LOG.warning("Unexpected key encryption algorithm");
                 throw new JweException(JweException.Error.INVALID_JSON_JWE);
             }
@@ -157,7 +160,7 @@ public class JweJsonProducer {
         }
         if (entries.size() == 1 && canBeFlat) {
             JweHeaders unprotectedEntryHeader = entries.get(0).getUnprotectedHeader();
-            if (unprotectedEntryHeader != null) {
+            if (unprotectedEntryHeader != null && !unprotectedEntryHeader.asMap().isEmpty()) {
                 jweJsonMap.put("header", unprotectedEntryHeader);
             }
             String encryptedKey = entries.get(0).getEncodedEncryptedKey();

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
index ca9192c..9fa4ec6 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
@@ -32,7 +32,6 @@ import java.security.interfaces.RSAPublicKey;
 import java.security.spec.ECFieldFp;
 import java.security.spec.ECPoint;
 import java.security.spec.EllipticCurve;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -45,7 +44,6 @@ import javax.crypto.SecretKey;
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.message.Message;
-import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.phase.PhaseInterceptorChain;
 import org.apache.cxf.rs.security.jose.common.JoseConstants;
 import org.apache.cxf.rs.security.jose.common.JoseHeaders;
@@ -303,8 +301,23 @@ public final class JweUtils {
         return ContentAlgorithm.getAlgorithm(algo);
     }
     public static JweEncryption getDirectKeyJweEncryption(JsonWebKey key) {
-        return getDirectKeyJweEncryption(JwkUtils.toSecretKey(key),
-                                         getContentAlgo(key.getAlgorithm()));
+        if (AlgorithmUtils.isEcdhEsDirect(key.getAlgorithm())) {
+            return getEcDirectKeyJweEncryption(key, ContentAlgorithm.A128GCM);
+        } else {
+            return getDirectKeyJweEncryption(JwkUtils.toSecretKey(key), getContentAlgo(key.getAlgorithm()));
+        }
+    }
+    public static JweEncryption getEcDirectKeyJweEncryption(JsonWebKey key, ContentAlgorithm ctAlgo) {
+        if (AlgorithmUtils.isEcdhEsDirect(key.getAlgorithm())) {
+            String curve = key.getStringProperty(JsonWebKey.EC_CURVE);
+            if (curve == null) {
+                curve = JsonWebKey.EC_CURVE_P256;
+            }
+            ECPublicKey ecKey = JwkUtils.toECPublicKey(key);
+            return new EcdhDirectKeyJweEncryption(ecKey, curve, ctAlgo);
+        } else {
+            throw new JweException(JweException.Error.INVALID_KEY_ALGORITHM);
+        }
     }
     public static JweEncryption getDirectKeyJweEncryption(SecretKey key, ContentAlgorithm algo) {
         return getDirectKeyJweEncryption(key.getEncoded(), algo);
@@ -318,7 +331,11 @@ public final class JweUtils {
         }
     }
     public static JweDecryption getDirectKeyJweDecryption(JsonWebKey key) {
-        return getDirectKeyJweDecryption(JwkUtils.toSecretKey(key), getContentAlgo(key.getAlgorithm()));
+        if (AlgorithmUtils.isEcdhEsDirect(key.getAlgorithm())) {
+            return getEcDirectKeyJweDecryption(key, ContentAlgorithm.A128GCM);
+        } else {
+            return getDirectKeyJweDecryption(JwkUtils.toSecretKey(key), getContentAlgo(key.getAlgorithm()));
+        }
     }
     public static JweDecryption getDirectKeyJweDecryption(SecretKey key, ContentAlgorithm algorithm) {
         return getDirectKeyJweDecryption(key.getEncoded(), algorithm);
@@ -331,6 +348,18 @@ public final class JweUtils {
                                  getContentDecryptionProvider(algorithm));
         }
     }
+    public static JweDecryption getEcDirectKeyJweDecryption(JsonWebKey key, ContentAlgorithm ctAlgo) {
+        if (AlgorithmUtils.isEcdhEsDirect(key.getAlgorithm())) {
+            String curve = key.getStringProperty(JsonWebKey.EC_CURVE);
+            if (curve == null) {
+                curve = JsonWebKey.EC_CURVE_P256;
+            }
+            ECPrivateKey ecKey = JwkUtils.toECPrivateKey(key);
+            return new EcdhDirectKeyJweDecryption(ecKey, ctAlgo);
+        } else {
+            throw new JweException(JweException.Error.INVALID_KEY_ALGORITHM);
+        }
+    }
     public static JweEncryptionProvider loadEncryptionProvider(boolean required) {
         return loadEncryptionProvider(null, required);
     }
@@ -340,97 +369,108 @@ public final class JweUtils {
         if (props == null) {
             return null;
         }
-        return loadEncryptionProvider(props, headers, required);
+        return loadEncryptionProvider(props, headers);
     }
 
-    public static JweEncryptionProvider loadEncryptionProvider(Properties props, JweHeaders headers, boolean required) {
+    public static JweEncryptionProvider loadEncryptionProvider(Properties props, JweHeaders headers) {
         Message m = PhaseInterceptorChain.getCurrentMessage();
-
-        boolean includeCert =
-            headers != null && MessageUtils.getContextualBoolean(
-                m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT, false);
-        boolean includeCertSha1 = headers != null && MessageUtils.getContextualBoolean(
-                m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA1, false);
-        boolean includeCertSha256 = !includeCertSha1 && headers != null && MessageUtils.getContextualBoolean(
-                m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA256, false);
-
-        KeyEncryptionProvider keyEncryptionProvider = null;
-        KeyAlgorithm keyAlgo = getKeyEncryptionAlgorithm(m, props, null, null);
+        return loadEncryptionProvider(props, m, headers);
+    }
+    
+    public static JweEncryptionProvider loadEncryptionProvider(Properties props, Message m, JweHeaders headers) {
+    
+        KeyEncryptionProvider keyEncryptionProvider = loadKeyEncryptionProvider(props, m, headers);
         ContentAlgorithm contentAlgo = getContentEncryptionAlgorithm(m, props, null, ContentAlgorithm.A128GCM);
         if (m != null) {
             m.put(JoseConstants.RSSEC_ENCRYPTION_CONTENT_ALGORITHM, contentAlgo.getJwaName());
         }
         ContentEncryptionProvider ctEncryptionProvider = null;
-        if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
+        if (KeyAlgorithm.DIRECT == keyEncryptionProvider.getAlgorithm()) {
             JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.ENCRYPT);
-            if (KeyAlgorithm.DIRECT == keyAlgo) {
+            if (jwk != null) {
                 contentAlgo = getContentEncryptionAlgorithm(m, props,
-                                            ContentAlgorithm.getAlgorithm(jwk.getAlgorithm()),
-                                            ContentAlgorithm.A128GCM);
+                    jwk.getAlgorithm() != null ? ContentAlgorithm.getAlgorithm(jwk.getAlgorithm()) : null,
+                    contentAlgo);
                 ctEncryptionProvider = getContentEncryptionProvider(jwk, contentAlgo);
-            } else {
-                keyAlgo = getKeyEncryptionAlgorithm(m, props,
-                                                    KeyAlgorithm.getAlgorithm(jwk.getAlgorithm()),
-                                                    getDefaultKeyAlgorithm(jwk));
-                keyEncryptionProvider = getKeyEncryptionProvider(jwk, keyAlgo);
-
-                boolean includePublicKey = headers != null && MessageUtils.getContextualBoolean(
-                    m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_PUBLIC_KEY, false);
-                boolean includeKeyId = headers != null && MessageUtils.getContextualBoolean(
-                    m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_KEY_ID, false);
+            }         
+        }
+        String compression = props.getProperty(JoseConstants.RSSEC_ENCRYPTION_ZIP_ALGORITHM);
+        return createJweEncryptionProvider(keyEncryptionProvider,
+                                    ctEncryptionProvider,
+                                    contentAlgo,
+                                    compression,
+                                    headers);
+    }
+    
+    public static KeyEncryptionProvider loadKeyEncryptionProvider(Properties props, Message m, JweHeaders headers) {
+        
+        KeyEncryptionProvider keyEncryptionProvider = null;
+        KeyAlgorithm keyAlgo = getKeyEncryptionAlgorithm(m, props, null, null);
+        if (KeyAlgorithm.DIRECT == keyAlgo) {
+            keyEncryptionProvider = new DirectKeyEncryptionAlgorithm();    
+        } else {
+            boolean includeCert = 
+                JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT);
+            boolean includeCertSha1 = 
+                JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA1);
+            boolean includeCertSha256 =  
+                JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA256);
+            boolean includeKeyId = 
+                JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_KEY_ID);
 
-                if (includeCert) {
-                    JwkUtils.includeCertChain(jwk, headers, keyAlgo.getJwaName());
-                }
-                if (includeCertSha1) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                        props, MessageDigestUtils.ALGO_SHA_1);
-                    if (digest != null) {
-                        headers.setX509Thumbprint(digest);
+            if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
+                JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.ENCRYPT);
+                if (jwk != null) {
+                    keyAlgo = getKeyEncryptionAlgorithm(m, props,
+                                                        KeyAlgorithm.getAlgorithm(jwk.getAlgorithm()),
+                                                        getDefaultKeyAlgorithm(jwk));
+                    keyEncryptionProvider = getKeyEncryptionProvider(jwk, keyAlgo);
+    
+                    boolean includePublicKey = 
+                        JoseUtils.checkBooleanProperty(headers, props, m, 
+                                                       JoseConstants.RSSEC_ENCRYPTION_INCLUDE_PUBLIC_KEY);
+                    if (includeCert) {
+                        JwkUtils.includeCertChain(jwk, headers, keyAlgo.getJwaName());
                     }
-                } else if (includeCertSha256) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                        props, MessageDigestUtils.ALGO_SHA_256);
-                    if (digest != null) {
-                        headers.setX509ThumbprintSHA256(digest);
+                    if (includeCertSha1) {
+                        KeyManagementUtils.setSha1DigestHeader(headers, m, props);
+                    } else if (includeCertSha256) {
+                        KeyManagementUtils.setSha256DigestHeader(headers, m, props);
+                    }
+                    if (includePublicKey) {
+                        JwkUtils.includePublicKey(jwk, headers, keyAlgo.getJwaName());
+                    }
+                    if (includeKeyId && jwk.getKeyId() != null) {
+                        headers.setKeyId(jwk.getKeyId());
                     }
                 }
-                if (includePublicKey) {
-                    JwkUtils.includePublicKey(jwk, headers, keyAlgo.getJwaName());
-                }
-                if (includeKeyId && jwk.getKeyId() != null && headers != null) {
-                    headers.setKeyId(jwk.getKeyId());
+            } else {
+                keyEncryptionProvider = getPublicKeyEncryptionProvider(
+                    KeyManagementUtils.loadPublicKey(m, props),
+                    props,
+                    keyAlgo);
+                if (includeCert) {
+                    headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props));
                 }
-            }
-        } else {
-            keyEncryptionProvider = getPublicKeyEncryptionProvider(
-                KeyManagementUtils.loadPublicKey(m, props),
-                props,
-                keyAlgo);
-            if (includeCert) {
-                headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props));
-            }
-            if (includeCertSha1) {
-                String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                    props, MessageDigestUtils.ALGO_SHA_1);
-                if (digest != null) {
-                    headers.setX509Thumbprint(digest);
+                if (includeCertSha1) {
+                    KeyManagementUtils.setSha1DigestHeader(headers, m, props);
+                } else if (includeCertSha256) {
+                    KeyManagementUtils.setSha256DigestHeader(headers, m, props);
                 }
-            } else if (includeCertSha256) {
-                String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                    props, MessageDigestUtils.ALGO_SHA_256);
-                if (digest != null) {
-                    headers.setX509ThumbprintSHA256(digest);
+                if (includeKeyId && props.containsKey(JoseConstants.RSSEC_KEY_STORE_ALIAS)) {
+                    headers.setKeyId(props.getProperty(JoseConstants.RSSEC_KEY_STORE_ALIAS));
                 }
             }
         }
-
-        String compression = props.getProperty(JoseConstants.RSSEC_ENCRYPTION_ZIP_ALGORITHM);
-        return createJweEncryptionProvider(keyEncryptionProvider,
-                                    ctEncryptionProvider,
-                                    contentAlgo.getJwaName(),
-                                    compression);
+        if (keyEncryptionProvider == null) {
+            throw new JweException(JweException.Error.INVALID_KEY_ALGORITHM);
+        }
+        headers.setKeyEncryptionAlgorithm(keyEncryptionProvider.getAlgorithm());
+        return keyEncryptionProvider;
+        
     }
+    
+    
     public static JweDecryptionProvider loadDecryptionProvider(boolean required) {
         return loadDecryptionProvider(null, required);
     }
@@ -440,12 +480,11 @@ public final class JweUtils {
             return null;
         }
 
-        return loadDecryptionProvider(props, inHeaders, required);
+        return loadDecryptionProvider(props, inHeaders);
     }
 
     public static JweDecryptionProvider loadDecryptionProvider(Properties props,
-                                                               JweHeaders inHeaders,
-                                                               boolean required) {
+                                                               JweHeaders inHeaders) {
 
         Message m = PhaseInterceptorChain.getCurrentMessage();
         KeyDecryptionProvider keyDecryptionProvider = null;
@@ -524,50 +563,7 @@ public final class JweUtils {
         return createJweDecryptionProvider(keyDecryptionProvider, ctDecryptionKey,
                                            contentAlgo);
     }
-    public static List<JweEncryptionProvider> loadJweEncryptionProviders(String propLoc, Message m) {
-        Properties props = loadJweProperties(m, propLoc);
-        JweEncryptionProvider theEncProvider = loadEncryptionProvider(props, null, false);
-        if (theEncProvider != null) {
-            return Collections.singletonList(theEncProvider);
-        }
-        List<JweEncryptionProvider> theEncProviders = null;
-        if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
-            List<JsonWebKey> jwks = JwkUtils.loadJsonWebKeys(m, props, KeyOperation.ENCRYPT);
-            if (jwks != null) {
-                theEncProviders = new ArrayList<>(jwks.size());
-                for (JsonWebKey jwk : jwks) {
-                    theEncProviders.add(getDirectKeyJweEncryption(jwk));
-                }
-            }
-        }
-        if (theEncProviders == null) {
-            LOG.warning("Providers are not available");
-            throw new JweException(JweException.Error.NO_ENCRYPTOR);
-        }
-        return theEncProviders;
-    }
-    public static List<JweDecryptionProvider> loadJweDecryptionProviders(String propLoc, Message m) {
-        Properties props = loadJweProperties(m, propLoc);
-        JweDecryptionProvider theDecProvider = loadDecryptionProvider(props, null, false);
-        if (theDecProvider != null) {
-            return Collections.singletonList(theDecProvider);
-        }
-        List<JweDecryptionProvider> theDecProviders = null;
-        if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
-            List<JsonWebKey> jwks = JwkUtils.loadJsonWebKeys(m, props, KeyOperation.DECRYPT);
-            if (jwks != null) {
-                theDecProviders = new ArrayList<>(jwks.size());
-                for (JsonWebKey jwk : jwks) {
-                    theDecProviders.add(getDirectKeyJweDecryption(jwk));
-                }
-            }
-        }
-        if (theDecProviders == null) {
-            LOG.warning("Providers are not available");
-            throw new JweException(JweException.Error.NO_ENCRYPTOR);
-        }
-        return theDecProviders;
-    }
+    
     public static JweEncryptionProvider createJweEncryptionProvider(PublicKey key,
                                                                     KeyAlgorithm keyAlgo,
                                                                     ContentAlgorithm contentEncryptionAlgo) {
@@ -621,17 +617,23 @@ public final class JweUtils {
                                                                     String compression) {
         JweHeaders headers =
             prepareJweHeaders(keyEncryptionProvider != null ? keyEncryptionProvider.getAlgorithm().getJwaName() : null,
-                contentEncryptionAlgo.getJwaName(), compression);
+                contentEncryptionAlgo.getJwaName(), compression, null);
         return createJweEncryptionProvider(keyEncryptionProvider, headers);
     }
+    
     public static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider,
                                                                     JweHeaders headers) {
+        return createJweEncryptionProvider(keyEncryptionProvider, headers, false);
+    }
+    public static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider,
+                                                                    JweHeaders headers,
+                                                                    boolean generateCekOnce) {
         ContentAlgorithm contentEncryptionAlgo = headers.getContentEncryptionAlgorithm();
         if (AlgorithmUtils.isAesCbcHmac(contentEncryptionAlgo.getJwaName())) {
-            return new AesCbcHmacJweEncryption(contentEncryptionAlgo, keyEncryptionProvider);
+            return new AesCbcHmacJweEncryption(contentEncryptionAlgo, keyEncryptionProvider, generateCekOnce);
         } else {
             return new JweEncryption(keyEncryptionProvider,
-                                     getContentEncryptionProvider(contentEncryptionAlgo));
+                                     getContentEncryptionProvider(contentEncryptionAlgo, generateCekOnce));
         }
     }
     public static JweDecryptionProvider createJweDecryptionProvider(PrivateKey key,
@@ -798,8 +800,9 @@ public final class JweUtils {
     }
     private static JweHeaders prepareJweHeaders(String keyEncryptionAlgo,
                                                 String contentEncryptionAlgo,
-                                                String compression) {
-        JweHeaders headers = new JweHeaders();
+                                                String compression,
+                                                JweHeaders headers) {
+        headers = headers != null ? headers : new JweHeaders();
         if (keyEncryptionAlgo != null) {
             headers.setKeyEncryptionAlgorithm(KeyAlgorithm.getAlgorithm(keyEncryptionAlgo));
         }
@@ -809,21 +812,23 @@ public final class JweUtils {
         }
         return headers;
     }
+    
     private static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider,
                                                                      ContentEncryptionProvider ctEncryptionProvider,
-                                                                     String contentEncryptionAlgo,
-                                                                     String compression) {
+                                                                     ContentAlgorithm contentEncryptionAlgo,
+                                                                     String compression,
+                                                                     JweHeaders headers) {
         if (keyEncryptionProvider == null && ctEncryptionProvider == null) {
             LOG.warning("Key or content encryptor is not available");
             throw new JweException(JweException.Error.NO_ENCRYPTOR);
         }
-        JweHeaders headers =
+        headers =
             prepareJweHeaders(keyEncryptionProvider != null ? keyEncryptionProvider.getAlgorithm().getJwaName() : null,
-                contentEncryptionAlgo, compression);
-        if (keyEncryptionProvider != null) {
+                contentEncryptionAlgo.getJwaName(), compression, headers);
+        if (ctEncryptionProvider == null) {
             return createJweEncryptionProvider(keyEncryptionProvider, headers);
         } else {
-            return new JweEncryption(new DirectKeyEncryptionAlgorithm(), ctEncryptionProvider);
+            return new JweEncryption(keyEncryptionProvider, ctEncryptionProvider);
         }
     }
     private static JweDecryptionProvider createJweDecryptionProvider(KeyDecryptionProvider keyDecryptionProvider,
@@ -875,6 +880,9 @@ public final class JweUtils {
         }
         return algo;
     }
+    public static ContentAlgorithm getContentEncryptionAlgorithm(Properties props) {
+        return getContentEncryptionAlgorithm(PhaseInterceptorChain.getCurrentMessage(), props, null); 
+    }
     public static ContentAlgorithm getContentEncryptionAlgorithm(Properties props,
                                                                  ContentAlgorithm defaultAlgo) {
         return getContentEncryptionAlgorithm(PhaseInterceptorChain.getCurrentMessage(), props, defaultAlgo);
@@ -943,7 +951,8 @@ public final class JweUtils {
             return new JsonWebKeys(jwk);
         }
     }
-    private static Properties loadJweProperties(Message m, String propLoc) {
+    
+    public static Properties loadJweProperties(Message m, String propLoc) {
         try {
             return JoseUtils.loadProperties(propLoc, m.getExchange().getBus());
         } catch (Exception ex) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
index cd5a008..b3a5c42 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
@@ -28,7 +28,6 @@ import java.security.interfaces.RSAKey;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -268,51 +267,8 @@ public final class JwsUtils {
         Properties props = loadSignatureInProperties(required);
         return loadSignatureVerifier(props, headers);
     }
-    public static List<JwsSignatureProvider> loadSignatureProviders(String propLoc, Message m) {
-        Properties props = loadJwsProperties(m, propLoc);
-        JwsSignatureProvider theSigProvider = loadSignatureProvider(m, props, null, true);
-        if (theSigProvider != null) {
-            return Collections.singletonList(theSigProvider);
-        }
-        List<JwsSignatureProvider> theSigProviders = null;
-        if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
-            List<JsonWebKey> jwks = JwkUtils.loadJsonWebKeys(m, props, KeyOperation.SIGN);
-            if (jwks != null) {
-                theSigProviders = new ArrayList<>(jwks.size());
-                for (JsonWebKey jwk : jwks) {
-                    theSigProviders.add(JwsUtils.getSignatureProvider(jwk));
-                }
-            }
-        }
-        if (theSigProviders == null) {
-            LOG.warning("Providers are not available");
-            throw new JwsException(JwsException.Error.NO_PROVIDER);
-        }
-        return theSigProviders;
-    }
-
-    public static List<JwsSignatureVerifier> loadSignatureVerifiers(String propLoc, Message m) {
-        Properties props = loadJwsProperties(m, propLoc);
-        JwsSignatureVerifier theVerifier = loadSignatureVerifier(m, props, null, true);
-        if (theVerifier != null) {
-            return Collections.singletonList(theVerifier);
-        }
-        List<JwsSignatureVerifier> theVerifiers = null;
-        if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
-            List<JsonWebKey> jwks = JwkUtils.loadJsonWebKeys(m, props, KeyOperation.VERIFY);
-            if (jwks != null) {
-                theVerifiers = new ArrayList<>(jwks.size());
-                for (JsonWebKey jwk : jwks) {
-                    theVerifiers.add(JwsUtils.getSignatureVerifier(jwk));
-                }
-            }
-        }
-        if (theVerifiers == null) {
-            LOG.warning("Verifiers are not available");
-            throw new JwsException(JwsException.Error.NO_VERIFIER);
-        }
-        return theVerifiers;
-    }
+    
+    
     public static boolean validateCriticalHeaders(JwsHeaders headers) {
         //TODO: validate JWS specific constraints
         return JoseUtils.validateCriticalHeaders(headers);
@@ -322,30 +278,25 @@ public final class JwsUtils {
         return loadSignatureProvider(PhaseInterceptorChain.getCurrentMessage(),
                                      props, headers);
     }
-    public static JwsSignatureProvider loadSignatureProvider(Message m,
-                                                              Properties props,
-                                                              JwsHeaders headers) {
-        return loadSignatureProvider(m, props, headers, false);
-    }
+    
     public static JwsSignatureProvider loadSignatureProvider(String propertiesLoc, Bus bus) {
         Properties props = loadSignatureProperties(propertiesLoc, bus);
         return loadSignatureProvider(props, null);
     }
 
-    private static JwsSignatureProvider loadSignatureProvider(Message m,
+    public static JwsSignatureProvider loadSignatureProvider(Message m,
                                                              Properties props,
-                                                             JwsHeaders headers,
-                                                             boolean ignoreNullProvider) {
+                                                             JwsHeaders headers) {
         JwsSignatureProvider theSigProvider = null;
 
-        boolean includeCert = headers != null && MessageUtils.getContextualBoolean(
-                m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT, false);
-        boolean includeCertSha1 = headers != null && MessageUtils.getContextualBoolean(
-                m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA1, false);
-        boolean includeCertSha256 = !includeCertSha1 && headers != null && MessageUtils.getContextualBoolean(
-                                  m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA256, false);
-        boolean includeKeyId = headers != null && MessageUtils.getContextualBoolean(
-                m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_KEY_ID, false);
+        boolean includeCert = 
+            JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT);
+        boolean includeCertSha1 = 
+            JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA1);
+        boolean includeCertSha256 =  
+            JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_CERT_SHA256);
+        boolean includeKeyId =
+            JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_KEY_ID);
 
         if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
             JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.SIGN);
@@ -356,24 +307,17 @@ public final class JwsUtils {
                                                              getDefaultKeyAlgorithm(jwk));
                 theSigProvider = JwsUtils.getSignatureProvider(jwk, signatureAlgo);
 
-                boolean includePublicKey = headers != null && MessageUtils.getContextualBoolean(
-                    m, JoseConstants.RSSEC_SIGNATURE_INCLUDE_PUBLIC_KEY, false);
+                boolean includePublicKey = 
+                    JoseUtils.checkBooleanProperty(headers, props, m, 
+                                                   JoseConstants.RSSEC_SIGNATURE_INCLUDE_PUBLIC_KEY);
 
                 if (includeCert) {
                     JwkUtils.includeCertChain(jwk, headers, signatureAlgo.getJwaName());
                 }
                 if (includeCertSha1) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                        props, MessageDigestUtils.ALGO_SHA_1);
-                    if (digest != null) {
-                        headers.setX509Thumbprint(digest);
-                    }
+                    KeyManagementUtils.setSha1DigestHeader(headers, m, props);
                 } else if (includeCertSha256) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                        props, MessageDigestUtils.ALGO_SHA_256);
-                    if (digest != null) {
-                        headers.setX509ThumbprintSHA256(digest);
-                    }
+                    KeyManagementUtils.setSha256DigestHeader(headers, m, props);
                 }
                 if (includePublicKey) {
                     JwkUtils.includePublicKey(jwk, headers, signatureAlgo.getJwaName());
@@ -397,24 +341,16 @@ public final class JwsUtils {
                     headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props));
                 }
                 if (includeCertSha1) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                        props, MessageDigestUtils.ALGO_SHA_1);
-                    if (digest != null) {
-                        headers.setX509Thumbprint(digest);
-                    }
+                    KeyManagementUtils.setSha1DigestHeader(headers, m, props);
                 } else if (includeCertSha256) {
-                    String digest = KeyManagementUtils.loadDigestAndEncodeX509Certificate(m, 
-                                        props, MessageDigestUtils.ALGO_SHA_256);
-                    if (digest != null) {
-                        headers.setX509ThumbprintSHA256(digest);
-                    }
+                    KeyManagementUtils.setSha256DigestHeader(headers, m, props);
                 }  
                 if (includeKeyId && props.containsKey(JoseConstants.RSSEC_KEY_STORE_ALIAS)) {
                     headers.setKeyId(props.getProperty(JoseConstants.RSSEC_KEY_STORE_ALIAS));
                 }
             }
         }
-        if (theSigProvider == null && !ignoreNullProvider) {
+        if (theSigProvider == null) {
             LOG.warning("Provider is not available");
             throw new JwsException(JwsException.Error.NO_PROVIDER);
         }
@@ -423,12 +359,11 @@ public final class JwsUtils {
     public static JwsSignatureVerifier loadSignatureVerifier(Properties props,
                                                              JwsHeaders inHeaders) {
         return loadSignatureVerifier(PhaseInterceptorChain.getCurrentMessage(),
-                                     props, inHeaders, false);
+                                     props, inHeaders);
     }
     public static JwsSignatureVerifier loadSignatureVerifier(Message m,
                                                               Properties props,
-                                                              JwsHeaders inHeaders,
-                                                              boolean ignoreNullVerifier) {
+                                                              JwsHeaders inHeaders) {
         JwsSignatureVerifier theVerifier = null;
         String inHeaderKid = null;
         if (inHeaders != null) {
@@ -489,13 +424,13 @@ public final class JwsUtils {
                 }
             }
         }
-        if (theVerifier == null && !ignoreNullVerifier) {
+        if (theVerifier == null) {
             LOG.warning("Verifier is not available");
             throw new JwsException(JwsException.Error.NO_VERIFIER);
         }
         return theVerifier;
     }
-    private static Properties loadJwsProperties(Message m, String propLoc) {
+    public static Properties loadJwsProperties(Message m, String propLoc) {
         try {
             return JoseUtils.loadProperties(propLoc, m.getExchange().getBus());
         } catch (Exception ex) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java
index 4475375..0a3089e 100644
--- a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java
@@ -161,9 +161,9 @@ public class JweJsonConsumerTest extends Assert {
         jweProviders.add(jwe1);
         jweProviders.add(jwe2);
 
-        List<JweHeaders> perRecipientHeades = new LinkedList<JweHeaders>();
-        perRecipientHeades.add(new JweHeaders("key1"));
-        perRecipientHeades.add(new JweHeaders("key2"));
+        List<JweHeaders> perRecipientHeaders = new LinkedList<JweHeaders>();
+        perRecipientHeaders.add(new JweHeaders("key1"));
+        perRecipientHeaders.add(new JweHeaders("key2"));
 
         JweJsonProducer p = new JweJsonProducer(protectedHeaders,
                                                 sharedUnprotectedHeaders,
@@ -171,7 +171,7 @@ public class JweJsonConsumerTest extends Assert {
                                                 StringUtils.toBytesUTF8(JweJsonProducerTest.EXTRA_AAD_SOURCE),
                                                 false);
 
-        String jweJson = p.encryptWith(jweProviders, perRecipientHeades);
+        String jweJson = p.encryptWith(jweProviders, perRecipientHeaders);
         doTestMultipleRecipients(jweJson);
     }
     private void doTestMultipleRecipients(String jweJson) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java
index 6f28ef4..d293ace 100644
--- a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsUtilsTest.java
@@ -60,8 +60,7 @@ public class JwsUtilsTest extends Assert {
         p.put(JoseConstants.RSSEC_KEY_STORE_ALIAS, "alice");
         JwsSignatureVerifier jws = JwsUtils.loadSignatureVerifier(createMessage(),
                                                                   p,
-                                                                  new JwsHeaders(),
-                                                                  false);
+                                                                  new JwsHeaders());
         assertNotNull(jws);
     }
     @Test

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
index d1bb134..7cab14d 100644
--- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/token/provider/jwt/JWTTokenProvider.java
@@ -332,7 +332,7 @@ public class JWTTokenProvider implements TokenProvider {
         encProperties.put(JoseConstants.RSSEC_KEY_STORE, keystore);
 
         JweEncryptionProvider encProvider =
-            JweUtils.loadEncryptionProvider(encProperties, jweHeaders, false);
+            JweUtils.loadEncryptionProvider(encProperties, jweHeaders);
         // token.getJwsHeaders().setSignatureAlgorithm(sigProvider.getAlgorithm());
 
         return encProvider.encrypt(StringUtils.toBytesUTF8(token), null);

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
index cf09345..7c662d4 100644
--- a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
+++ b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/token/provider/JWTTokenProviderTest.java
@@ -236,7 +236,7 @@ public class JWTTokenProviderTest extends org.junit.Assert {
             decProperties.put(JoseConstants.RSSEC_KEY_PSWD, "skpass");
 
             JweDecryptionProvider decProvider =
-                JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders(), false);
+                JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders());
 
             JweDecryptionOutput decOutput = decProvider.decrypt(token);
             String decToken = decOutput.getContentText();
@@ -290,7 +290,7 @@ public class JWTTokenProviderTest extends org.junit.Assert {
                                   ContentAlgorithm.A128CBC_HS256.name());
 
                 JweDecryptionProvider decProvider =
-                    JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders(), false);
+                    JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders());
 
                 JweDecryptionOutput decOutput = decProvider.decrypt(token);
                 String decToken = decOutput.getContentText();
@@ -337,7 +337,7 @@ public class JWTTokenProviderTest extends org.junit.Assert {
             decProperties.put(JoseConstants.RSSEC_KEY_PSWD, "skpass");
 
             JweDecryptionProvider decProvider =
-                JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders(), false);
+                JweUtils.loadDecryptionProvider(decProperties, jwtConsumer.getHeaders());
 
             JweDecryptionOutput decOutput = decProvider.decrypt(token);
             String decToken = decOutput.getContentText();

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
index b86d923..b0ec144 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
@@ -123,7 +123,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
     }
 
     @Test
-    public void testBlockAndTrowException() throws Exception {
+    public void testBlockAndThrowException() throws Exception {
         String address = "http://localhost:" + PORT + "/bookstore/blockAndThrowException";
         WebClient wc = WebClient.create(address);
         Response r = wc.get();

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java
----------------------------------------------------------------------
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java
index 0e039cd..f91733d 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/BookStore.java
@@ -20,7 +20,9 @@
 package org.apache.cxf.systest.jaxrs.security.jose;
 
 
+import java.util.Collections;
 import java.util.List;
+import java.util.Properties;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.InternalServerErrorException;
@@ -29,6 +31,15 @@ import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 
 import org.apache.cxf.jaxrs.ext.multipart.Multipart;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionOutput;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweJsonConsumer;
+import org.apache.cxf.rs.security.jose.jwe.JweUtils;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
 import org.apache.cxf.systest.jaxrs.security.Book;
 
 @Path("/bookstore")
@@ -44,7 +55,7 @@ public class BookStore {
     public String echoText(String text) {
         return text;
     }
-
+    
     @POST
     @Path("/books")
     @Produces("application/json")
@@ -86,6 +97,43 @@ public class BookStore {
         return books;
     }
 
+    @POST
+    @Path("/books")
+    @Produces({"text/plain"})
+    @Consumes("application/jose+json")
+    public String echoTextJweJsonIn(String jweJson) {
+        
+        JweJsonConsumer consumer = new JweJsonConsumer(jweJson);
+        
+        // Recipient 1
+        final String recipient1PropLoc = "org/apache/cxf/systest/jaxrs/security/jwejson1.properties";
+        final String recipient1Kid = "AesWrapKey";
+        String recipient1DecryptedText = getRecipientText(consumer, recipient1PropLoc, recipient1Kid);
+        
+        // Recipient 2
+        final String recipient2PropLoc = "org/apache/cxf/systest/jaxrs/security/jwejson2.properties";
+        final String recipient2Kid = "AesWrapKey2";
+        String recipient2DecryptedText = getRecipientText(consumer, recipient2PropLoc, recipient2Kid);
+        return recipient1DecryptedText + recipient2DecryptedText;
+    }
+
+    private String getRecipientText(JweJsonConsumer consumer, String recipientPropLoc, String recipientKid) { 
+        Message message = JAXRSUtils.getCurrentMessage();
+        
+        
+        Properties recipientProps = JweUtils.loadJweProperties(message, recipientPropLoc);
+        JsonWebKey recipientKey = JwkUtils.loadJwkSet(message, recipientProps, null).getKey(recipientKid);
+        
+        ContentAlgorithm contentEncryptionAlgorithm = JweUtils.getContentEncryptionAlgorithm(recipientProps);
+        
+        JweDecryptionProvider jweRecipient = 
+            JweUtils.createJweDecryptionProvider(recipientKey, contentEncryptionAlgorithm);
+        
+        JweDecryptionOutput jweRecipientOutput = 
+            consumer.decryptWith(jweRecipient,
+                                 Collections.singletonMap("kid", recipientKid));
+        return jweRecipientOutput.getContentText();
+    }
 }
 
 

http://git-wip-us.apache.org/repos/asf/cxf/blob/33eb378e/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJsonTest.java
----------------------------------------------------------------------
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJsonTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJsonTest.java
index 6b63f30..332b8c5 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJsonTest.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JAXRSJweJsonTest.java
@@ -21,10 +21,9 @@ package org.apache.cxf.systest.jaxrs.security.jose.jwejws;
 
 import java.net.URL;
 import java.security.Security;
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.cxf.Bus;
 import org.apache.cxf.bus.spring.SpringBusFactory;
@@ -59,24 +58,22 @@ public class JAXRSJweJsonTest extends AbstractBusClientServerTestBase {
     }
 
     @Test
-    public void testJweJsonPlainTextHmac() throws Exception {
-        String address = "https://localhost:" + PORT + "/jwejsonhmac";
+    public void testJweJsonSingleRecipientKeyWrapAndAesCbcHmac() throws Exception {
+        String address = "https://localhost:" + PORT + "/jwejsonkeywrap";
         BookStore bs = createBookStore(address,
-                                       "org/apache/cxf/systest/jaxrs/security/secret.jwk.properties",
-                                       null);
+                                       "org/apache/cxf/systest/jaxrs/security/secret.jwk.properties");
         String text = bs.echoText("book");
         assertEquals("book", text);
     }
-
-    private BookStore createBookStore(String address, Object properties,
-                                      List<?> extraProviders) throws Exception {
-        return createBookStore(address,
-                               Collections.singletonMap(JoseConstants.RSSEC_ENCRYPTION_PROPS, properties),
-                               extraProviders);
+    @Test
+    public void testJweJsonSingleRecipientAesGcmDirect() throws Exception {
+        String address = "https://localhost:" + PORT + "/jwejsondirect";
+        BookStore bs = createBookStore(address,
+                                       "org/apache/cxf/systest/jaxrs/security/jwe.direct.properties");
+        String text = bs.echoText("book");
+        assertEquals("book", text);
     }
-    private BookStore createBookStore(String address,
-                                      Map<String, Object> mapProperties,
-                                      List<?> extraProviders) throws Exception {
+    private BookStore createBookStore(String address, String propLoc) throws Exception {
         JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
         SpringBusFactory bf = new SpringBusFactory();
         URL busFile = JAXRSJweJsonTest.class.getResource("client.xml");
@@ -88,11 +85,35 @@ public class JAXRSJweJsonTest extends AbstractBusClientServerTestBase {
         JweJsonWriterInterceptor writer = new JweJsonWriterInterceptor();
         providers.add(writer);
         providers.add(new JweJsonClientResponseFilter());
-        if (extraProviders != null) {
-            providers.addAll(extraProviders);
-        }
         bean.setProviders(providers);
-        bean.getProperties(true).putAll(mapProperties);
+        bean.getProperties(true).put(JoseConstants.RSSEC_ENCRYPTION_PROPS,
+                                     propLoc);
+        return bean.create(BookStore.class);
+    }
+    
+    @Test
+    public void testJweJsontTwoRecipientsKeyWrapAndAesGcm() throws Exception {
+        String address = "https://localhost:" + PORT + "/jwejsonTwoRecipients";
+        BookStore bs = createBookStoreTwoRecipients(address);
+        String text = bs.echoTextJweJsonIn("book");
+        assertEquals("bookbook", text);
+    }
+
+    private BookStore createBookStoreTwoRecipients(String address) throws Exception {
+        JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = JAXRSJweJsonTest.class.getResource("client.xml");
+        Bus springBus = bf.createBus(busFile.toString());
+        bean.setBus(springBus);
+        bean.setServiceClass(BookStore.class);
+        bean.setAddress(address);
+        bean.setProvider(new JweJsonWriterInterceptor());
+        
+        List<String> properties = new ArrayList<>();
+        properties.add("org/apache/cxf/systest/jaxrs/security/jwejson1.properties");
+        properties.add("org/apache/cxf/systest/jaxrs/security/jwejson2.properties");
+        bean.getProperties(true).put(JoseConstants.RSSEC_ENCRYPTION_PROPS,
+                                 properties);
         return bean.create(BookStore.class);
     }