Return-Path: X-Original-To: apmail-cxf-commits-archive@www.apache.org Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 8B72B17EF4 for ; Wed, 21 Oct 2015 13:27:43 +0000 (UTC) Received: (qmail 76012 invoked by uid 500); 21 Oct 2015 13:27:43 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 75845 invoked by uid 500); 21 Oct 2015 13:27:43 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 74407 invoked by uid 99); 21 Oct 2015 13:27:42 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 21 Oct 2015 13:27:42 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 2F0E6E38EB; Wed, 21 Oct 2015 13:27:42 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: coheigea@apache.org To: commits@cxf.apache.org Date: Wed, 21 Oct 2015 13:27:54 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [14/18] cxf git commit: Renaming jose module http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweOutputStream.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweOutputStream.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweOutputStream.java new file mode 100644 index 0000000..1a0447d --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweOutputStream.java @@ -0,0 +1,148 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.logging.Logger; + +import javax.crypto.Cipher; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.common.util.Base64UrlUtility; + +public class JweOutputStream extends FilterOutputStream { + protected static final Logger LOG = LogUtils.getL7dLogger(JweOutputStream.class); + private Cipher encryptingCipher; + private int blockSize; + private AuthenticationTagProducer authTagProducer; + private byte[] lastRawDataChunk; + private byte[] lastEncryptedDataChunk; + private boolean flushed; + public JweOutputStream(OutputStream out, + Cipher encryptingCipher, + AuthenticationTagProducer authTagProducer) { + super(out); + this.encryptingCipher = encryptingCipher; + this.blockSize = encryptingCipher.getBlockSize(); + this.authTagProducer = authTagProducer; + } + + @Override + public void write(int value) throws IOException { + byte[] bytes = ByteBuffer.allocate(Integer.SIZE / 8).putInt(value).array(); + write(bytes, 0, bytes.length); + } + + @Override + public void write(byte b[], int off, int len) throws IOException { + if (lastRawDataChunk != null) { + int remaining = blockSize - lastRawDataChunk.length; + int lenToCopy = remaining < len ? remaining : len; + lastRawDataChunk = newArray(lastRawDataChunk, 0, lastRawDataChunk.length, b, off, lenToCopy); + off = off + lenToCopy; + len -= lenToCopy; + if (lastRawDataChunk.length < blockSize) { + return; + } else { + encryptAndWrite(lastRawDataChunk, 0, lastRawDataChunk.length); + lastRawDataChunk = null; + } + } + int offset = 0; + int chunkSize = blockSize > len ? blockSize : blockSize * (len / blockSize); + for (; offset + chunkSize <= len; offset += chunkSize, off += chunkSize) { + encryptAndWrite(b, off, chunkSize); + } + if (offset < len) { + lastRawDataChunk = newArray(b, off, len - offset); + } + + } + + private void encryptAndWrite(byte[] chunk, int off, int len) throws IOException { + byte[] encrypted = encryptingCipher.update(chunk, off, len); + if (authTagProducer != null) { + authTagProducer.update(encrypted, 0, encrypted.length); + } + encodeAndWrite(encrypted, 0, encrypted.length, false); + } + private void encodeAndWrite(byte[] encryptedChunk, int off, int len, boolean finalWrite) throws IOException { + byte[] theChunk = lastEncryptedDataChunk; + int lenToEncode = len; + if (theChunk != null) { + theChunk = newArray(theChunk, 0, theChunk.length, encryptedChunk, off, len); + lenToEncode = theChunk.length; + off = 0; + } else { + theChunk = encryptedChunk; + } + int rem = finalWrite ? 0 : lenToEncode % 3; + Base64UrlUtility.encodeAndStream(theChunk, off, lenToEncode - rem, out); + out.flush(); + if (rem > 0) { + lastEncryptedDataChunk = newArray(theChunk, lenToEncode - rem, rem); + } else { + lastEncryptedDataChunk = null; + } + } + + public void finalFlush() throws IOException { + if (flushed) { + return; + } + try { + byte[] finalBytes = lastRawDataChunk == null + ? encryptingCipher.doFinal() + : encryptingCipher.doFinal(lastRawDataChunk, 0, lastRawDataChunk.length); + final int authTagLengthBits = 128; + if (authTagProducer != null) { + authTagProducer.update(finalBytes, 0, finalBytes.length); + encodeAndWrite(finalBytes, 0, finalBytes.length, true); + } else { + encodeAndWrite(finalBytes, 0, finalBytes.length - authTagLengthBits / 8, true); + } + out.write(new byte[]{'.'}); + + if (authTagProducer == null) { + encodeAndWrite(finalBytes, finalBytes.length - authTagLengthBits / 8, authTagLengthBits / 8, true); + } else { + byte[] authTag = authTagProducer.getTag(); + encodeAndWrite(authTag, 0, authTagLengthBits / 8, true); + } + } catch (Exception ex) { + LOG.warning("Content encryption failure"); + throw new JweException(JweException.Error.CONTENT_ENCRYPTION_FAILURE, ex); + } + flushed = true; + } + private byte[] newArray(byte[] src, int srcPos, int srcLen) { + byte[] buf = new byte[srcLen]; + System.arraycopy(src, srcPos, buf, 0, srcLen); + return buf; + } + private byte[] newArray(byte[] src, int srcPos, int srcLen, byte[] src2, int srcPos2, int srcLen2) { + byte[] buf = new byte[srcLen + srcLen2]; + System.arraycopy(src, srcPos, buf, 0, srcLen); + System.arraycopy(src2, srcPos2, buf, srcLen, srcLen2); + return buf; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/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 new file mode 100644 index 0000000..5e6aece --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java @@ -0,0 +1,671 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import java.nio.ByteBuffer; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Properties; +import java.util.logging.Logger; + +import javax.crypto.KeyAgreement; +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; +import org.apache.cxf.rs.security.jose.common.JoseUtils; +import org.apache.cxf.rs.security.jose.common.KeyManagementUtils; +import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils; +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.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.jwk.KeyType; +import org.apache.cxf.rt.security.crypto.MessageDigestUtils; + +public final class JweUtils { + private static final Logger LOG = LogUtils.getL7dLogger(JweUtils.class); + + private JweUtils() { + + } + public static String encrypt(PublicKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo, + byte[] content) { + return encrypt(key, keyAlgo, contentAlgo, content, null); + } + public static String encrypt(PublicKey key, KeyAlgorithm keyAlgo, + ContentAlgorithm contentAlgo, byte[] content, String ct) { + KeyEncryptionProvider keyEncryptionProvider = getPublicKeyEncryptionProvider(key, keyAlgo); + return encrypt(keyEncryptionProvider, contentAlgo, content, ct); + } + public static String encrypt(SecretKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo, + byte[] content) { + return encrypt(key, keyAlgo, contentAlgo, content, null); + } + public static String encrypt(SecretKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo, + byte[] content, String ct) { + if (keyAlgo != null) { + KeyEncryptionProvider keyEncryptionProvider = getSecretKeyEncryptionAlgorithm(key, keyAlgo); + return encrypt(keyEncryptionProvider, contentAlgo, content, ct); + } else { + return encryptDirect(key, contentAlgo, content, ct); + } + } + public static String encrypt(JsonWebKey key, ContentAlgorithm contentAlgo, byte[] content, String ct) { + KeyEncryptionProvider keyEncryptionProvider = getKeyEncryptionProvider(key); + return encrypt(keyEncryptionProvider, contentAlgo, content, ct); + } + public static String encryptDirect(SecretKey key, ContentAlgorithm contentAlgo, byte[] content) { + return encryptDirect(key, contentAlgo, content, null); + } + public static String encryptDirect(SecretKey key, ContentAlgorithm contentAlgo, byte[] content, String ct) { + JweEncryptionProvider jwe = getDirectKeyJweEncryption(key, contentAlgo); + return jwe.encrypt(content, toJweHeaders(ct)); + } + public static String encryptDirect(JsonWebKey key, byte[] content, String ct) { + JweEncryptionProvider jwe = getDirectKeyJweEncryption(key); + return jwe.encrypt(content, toJweHeaders(ct)); + } + public static byte[] decrypt(PrivateKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo, String content) { + KeyDecryptionProvider keyDecryptionProvider = getPrivateKeyDecryptionProvider(key, keyAlgo); + return decrypt(keyDecryptionProvider, contentAlgo, content); + } + public static byte[] decrypt(SecretKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo, String content) { + if (keyAlgo != null) { + KeyDecryptionProvider keyDecryptionProvider = getSecretKeyDecryptionProvider(key, keyAlgo); + return decrypt(keyDecryptionProvider, contentAlgo, content); + } else { + return decryptDirect(key, contentAlgo, content); + } + } + public static byte[] decrypt(JsonWebKey key, ContentAlgorithm contentAlgo, String content) { + KeyDecryptionProvider keyDecryptionProvider = getKeyDecryptionProvider(key); + return decrypt(keyDecryptionProvider, contentAlgo, content); + } + public static byte[] decryptDirect(SecretKey key, ContentAlgorithm contentAlgo, String content) { + JweDecryptionProvider jwe = getDirectKeyJweDecryption(key, contentAlgo); + return jwe.decrypt(content).getContent(); + } + public static byte[] decryptDirect(JsonWebKey key, String content) { + JweDecryptionProvider jwe = getDirectKeyJweDecryption(key); + return jwe.decrypt(content).getContent(); + } + public static KeyEncryptionProvider getKeyEncryptionProvider(JsonWebKey jwk) { + return getKeyEncryptionProvider(jwk, null); + } + public static KeyEncryptionProvider getKeyEncryptionProvider(JsonWebKey jwk, KeyAlgorithm defaultAlgorithm) { + KeyAlgorithm keyAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm + : KeyAlgorithm.getAlgorithm(jwk.getAlgorithm()); + KeyEncryptionProvider keyEncryptionProvider = null; + KeyType keyType = jwk.getKeyType(); + if (KeyType.RSA == keyType) { + keyEncryptionProvider = getPublicKeyEncryptionProvider(JwkUtils.toRSAPublicKey(jwk, true), + keyAlgo); + } else if (KeyType.OCTET == keyType) { + keyEncryptionProvider = getSecretKeyEncryptionAlgorithm(JwkUtils.toSecretKey(jwk), + keyAlgo); + } else { + keyEncryptionProvider = new EcdhAesWrapKeyEncryptionAlgorithm(JwkUtils.toECPublicKey(jwk), + jwk.getStringProperty(JsonWebKey.EC_CURVE), + keyAlgo); + } + return keyEncryptionProvider; + } + public static KeyEncryptionProvider getPublicKeyEncryptionProvider(PublicKey key, KeyAlgorithm algo) { + if (key instanceof RSAPublicKey) { + return new RSAKeyEncryptionAlgorithm((RSAPublicKey)key, algo); + } else if (key instanceof ECPublicKey) { + return new EcdhAesWrapKeyEncryptionAlgorithm((ECPublicKey)key, algo); + } + + return null; + } + public static KeyEncryptionProvider getSecretKeyEncryptionAlgorithm(SecretKey key, KeyAlgorithm algo) { + if (AlgorithmUtils.isAesKeyWrap(algo.getJwaName())) { + return new AesWrapKeyEncryptionAlgorithm(key, algo); + } else if (AlgorithmUtils.isAesGcmKeyWrap(algo.getJwaName())) { + return new AesGcmWrapKeyEncryptionAlgorithm(key, algo); + } + return null; + } + public static KeyDecryptionProvider getKeyDecryptionProvider(JsonWebKey jwk) { + return getKeyDecryptionProvider(jwk, null); + } + + public static KeyDecryptionProvider getKeyDecryptionProvider(JsonWebKey jwk, KeyAlgorithm defaultAlgorithm) { + KeyAlgorithm keyAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm + : KeyAlgorithm.getAlgorithm(jwk.getAlgorithm()); + KeyDecryptionProvider keyDecryptionProvider = null; + KeyType keyType = jwk.getKeyType(); + if (KeyType.RSA == keyType) { + keyDecryptionProvider = getPrivateKeyDecryptionProvider(JwkUtils.toRSAPrivateKey(jwk), + keyAlgo); + } else if (KeyType.OCTET == keyType) { + keyDecryptionProvider = getSecretKeyDecryptionProvider(JwkUtils.toSecretKey(jwk), + keyAlgo); + } else { + keyDecryptionProvider = getPrivateKeyDecryptionProvider(JwkUtils.toECPrivateKey(jwk), + keyAlgo); + } + return keyDecryptionProvider; + } + public static KeyDecryptionProvider getPrivateKeyDecryptionProvider(PrivateKey key, KeyAlgorithm algo) { + if (key instanceof RSAPrivateKey) { + return new RSAKeyDecryptionAlgorithm((RSAPrivateKey)key, algo); + } else if (key instanceof ECPrivateKey) { + return new EcdhAesWrapKeyDecryptionAlgorithm((ECPrivateKey)key, algo); + } + + return null; + } + public static KeyDecryptionProvider getSecretKeyDecryptionProvider(SecretKey key, KeyAlgorithm algo) { + if (AlgorithmUtils.isAesKeyWrap(algo.getJwaName())) { + return new AesWrapKeyDecryptionAlgorithm(key, algo); + } else if (AlgorithmUtils.isAesGcmKeyWrap(algo.getJwaName())) { + return new AesGcmWrapKeyDecryptionAlgorithm(key, algo); + } + return null; + } + public static ContentEncryptionProvider getContentEncryptionAlgorithm(JsonWebKey jwk) { + return getContentEncryptionAlgorithm(jwk, null); + } + public static ContentEncryptionProvider getContentEncryptionAlgorithm(JsonWebKey jwk, String defaultAlgorithm) { + String ctEncryptionAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm : jwk.getAlgorithm(); + ContentEncryptionProvider contentEncryptionProvider = null; + KeyType keyType = jwk.getKeyType(); + if (KeyType.OCTET == keyType) { + return getContentEncryptionAlgorithm(JwkUtils.toSecretKey(jwk), + getContentAlgo(ctEncryptionAlgo)); + } + return contentEncryptionProvider; + } + public static ContentEncryptionProvider getContentEncryptionAlgorithm(SecretKey key, + ContentAlgorithm algorithm) { + if (AlgorithmUtils.isAesGcm(algorithm.getJwaName())) { + return new AesGcmContentEncryptionAlgorithm(key, null, algorithm); + } + return null; + } + public static ContentEncryptionProvider getContentEncryptionAlgorithm(String algorithm) { + if (AlgorithmUtils.isAesGcm(algorithm)) { + return new AesGcmContentEncryptionAlgorithm(getContentAlgo(algorithm)); + } + return null; + } + public static ContentDecryptionProvider getContentDecryptionProvider(ContentAlgorithm algorithm) { + if (AlgorithmUtils.isAesGcm(algorithm.getJwaName())) { + return new AesGcmContentDecryptionAlgorithm(algorithm); + } + return null; + } + public static SecretKey getContentDecryptionSecretKey(JsonWebKey jwk) { + return getContentDecryptionSecretKey(jwk, null); + } + public static SecretKey getContentDecryptionSecretKey(JsonWebKey jwk, String defaultAlgorithm) { + String ctEncryptionAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm : jwk.getAlgorithm(); + KeyType keyType = jwk.getKeyType(); + if (KeyType.OCTET == keyType && AlgorithmUtils.isAesGcm(ctEncryptionAlgo)) { + return JwkUtils.toSecretKey(jwk); + } + return null; + } + private static ContentAlgorithm getContentAlgo(String algo) { + return ContentAlgorithm.getAlgorithm(algo); + } + public static JweEncryption getDirectKeyJweEncryption(JsonWebKey key) { + return getDirectKeyJweEncryption(JwkUtils.toSecretKey(key), + getContentAlgo(key.getAlgorithm())); + } + public static JweEncryption getDirectKeyJweEncryption(SecretKey key, ContentAlgorithm algo) { + if (AlgorithmUtils.isAesCbcHmac(algo.getJwaName())) { + return new AesCbcHmacJweEncryption(algo, key.getEncoded(), + null, new DirectKeyEncryptionAlgorithm()); + } else { + return new JweEncryption(new DirectKeyEncryptionAlgorithm(), + getContentEncryptionAlgorithm(key, algo)); + } + } + public static JweDecryption getDirectKeyJweDecryption(JsonWebKey key) { + return getDirectKeyJweDecryption(JwkUtils.toSecretKey(key), getContentAlgo(key.getAlgorithm())); + } + public static JweDecryption getDirectKeyJweDecryption(SecretKey key, ContentAlgorithm algorithm) { + if (AlgorithmUtils.isAesCbcHmac(algorithm.getJwaName())) { + return new AesCbcHmacJweDecryption(new DirectKeyDecryptionAlgorithm(key), algorithm); + } else { + return new JweDecryption(new DirectKeyDecryptionAlgorithm(key), + getContentDecryptionProvider(algorithm)); + } + } + public static JweEncryptionProvider loadEncryptionProvider(boolean required) { + return loadEncryptionProvider(null, required); + } + @SuppressWarnings("deprecation") + public static JweEncryptionProvider loadEncryptionProvider(JweHeaders headers, boolean required) { + Message m = PhaseInterceptorChain.getCurrentMessage(); + Properties props = KeyManagementUtils.loadStoreProperties(m, required, + JoseConstants.RSSEC_ENCRYPTION_OUT_PROPS, + JoseConstants.RSSEC_ENCRYPTION_PROPS); + if (props == null) { + return null; + } + + boolean reportPublicKey = + headers != null && MessageUtils.isTrue( + MessageUtils.getContextualProperty(m, JoseConstants.RSSEC_ENCRYPTION_REPORT_KEY_PROP, + JoseConstants.RSSEC_REPORT_KEY_PROP)); + boolean reportPublicKeyId = + headers != null && MessageUtils.isTrue( + MessageUtils.getContextualProperty(m, JoseConstants.RSSEC_ENCRYPTION_REPORT_KEY_ID_PROP, + JoseConstants.RSSEC_REPORT_KEY_ID_PROP)); + + KeyEncryptionProvider keyEncryptionProvider = null; + String keyEncryptionAlgo = getKeyEncryptionAlgo(m, props, null, null); + KeyAlgorithm keyAlgo = KeyAlgorithm.getAlgorithm(keyEncryptionAlgo); + String contentEncryptionAlgo = getContentEncryptionAlgo(m, props, null); + ContentEncryptionProvider ctEncryptionProvider = null; + if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) { + JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.ENCRYPT); + if ("direct".equals(keyEncryptionAlgo)) { + contentEncryptionAlgo = getContentEncryptionAlgo(m, props, jwk.getAlgorithm()); + ctEncryptionProvider = getContentEncryptionAlgorithm(jwk, contentEncryptionAlgo); + } else { + keyEncryptionAlgo = getKeyEncryptionAlgo(m, props, jwk.getAlgorithm(), + getDefaultKeyAlgo(jwk)); + keyEncryptionProvider = getKeyEncryptionProvider(jwk, keyAlgo); + if (reportPublicKey || reportPublicKeyId) { + JwkUtils.setPublicKeyInfo(jwk, headers, keyEncryptionAlgo, + reportPublicKey, reportPublicKeyId); + } + } + } else { + keyEncryptionProvider = getPublicKeyEncryptionProvider( + KeyManagementUtils.loadPublicKey(m, props), + keyAlgo); + if (reportPublicKey) { + headers.setX509Chain(KeyManagementUtils.loadAndEncodeX509CertificateOrChain(m, props)); + } + + } + + String compression = props.getProperty(JoseConstants.RSSEC_ENCRYPTION_ZIP_ALGORITHM); + if (compression == null) { + compression = props.getProperty(JoseConstants.DEPR_RSSEC_ENCRYPTION_ZIP_ALGORITHM); + } + return createJweEncryptionProvider(keyEncryptionProvider, + ctEncryptionProvider, + contentEncryptionAlgo, + compression); + } + public static JweDecryptionProvider loadDecryptionProvider(boolean required) { + return loadDecryptionProvider(null, required); + } + public static JweDecryptionProvider loadDecryptionProvider(JweHeaders inHeaders, boolean required) { + Message m = PhaseInterceptorChain.getCurrentMessage(); + Properties props = KeyManagementUtils.loadStoreProperties(m, required, + JoseConstants.RSSEC_ENCRYPTION_IN_PROPS, + JoseConstants.RSSEC_ENCRYPTION_PROPS); + if (props == null) { + return null; + } + + KeyDecryptionProvider keyDecryptionProvider = null; + String contentEncryptionAlgo = getContentEncryptionAlgo(m, props, null); + SecretKey ctDecryptionKey = null; + String keyEncryptionAlgo = getKeyEncryptionAlgo(m, props, null, null); + if (inHeaders != null && inHeaders.getHeader(JoseConstants.HEADER_X509_CHAIN) != null) { + //TODO: validate incoming public keys or certificates + //TODO: optionally validate inHeaders.getAlgorithm against a property in props + // Supporting loading a private key via a certificate for now + List chain = KeyManagementUtils.toX509CertificateChain(inHeaders.getX509Chain()); + KeyManagementUtils.validateCertificateChain(props, chain); + PrivateKey privateKey = + KeyManagementUtils.loadPrivateKey(m, props, chain, KeyOperation.DECRYPT); + contentEncryptionAlgo = inHeaders.getContentEncryptionAlgorithm().getJwaName(); + keyDecryptionProvider = getPrivateKeyDecryptionProvider(privateKey, + inHeaders.getKeyEncryptionAlgorithm()); + } else { + if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) { + JsonWebKey jwk = JwkUtils.loadJsonWebKey(m, props, KeyOperation.DECRYPT); + if ("direct".equals(keyEncryptionAlgo)) { + contentEncryptionAlgo = getContentEncryptionAlgo(m, props, jwk.getAlgorithm()); + ctDecryptionKey = getContentDecryptionSecretKey(jwk, contentEncryptionAlgo); + } else { + keyEncryptionAlgo = getKeyEncryptionAlgo(m, props, jwk.getAlgorithm(), + getDefaultKeyAlgo(jwk)); + keyDecryptionProvider = getKeyDecryptionProvider(jwk, + KeyAlgorithm.getAlgorithm(keyEncryptionAlgo)); + } + } else { + keyDecryptionProvider = getPrivateKeyDecryptionProvider( + KeyManagementUtils.loadPrivateKey(m, props, KeyOperation.DECRYPT), + KeyAlgorithm.getAlgorithm(keyEncryptionAlgo)); + } + } + return createJweDecryptionProvider(keyDecryptionProvider, ctDecryptionKey, + getContentAlgo(contentEncryptionAlgo)); + } + public static JweEncryptionProvider createJweEncryptionProvider(PublicKey key, + KeyAlgorithm keyAlgo, + ContentAlgorithm contentEncryptionAlgo, + String compression) { + KeyEncryptionProvider keyEncryptionProvider = getPublicKeyEncryptionProvider(key, keyAlgo); + return createJweEncryptionProvider(keyEncryptionProvider, contentEncryptionAlgo, compression); + } + public static JweEncryptionProvider createJweEncryptionProvider(PublicKey key, JweHeaders headers) { + KeyEncryptionProvider keyEncryptionProvider = getPublicKeyEncryptionProvider(key, + headers.getKeyEncryptionAlgorithm()); + return createJweEncryptionProvider(keyEncryptionProvider, headers); + } + public static JweEncryptionProvider createJweEncryptionProvider(SecretKey key, + KeyAlgorithm keyAlgo, + ContentAlgorithm contentEncryptionAlgo, + String compression) { + KeyEncryptionProvider keyEncryptionProvider = getSecretKeyEncryptionAlgorithm(key, keyAlgo); + return createJweEncryptionProvider(keyEncryptionProvider, contentEncryptionAlgo, compression); + } + public static JweEncryptionProvider createJweEncryptionProvider(SecretKey key, JweHeaders headers) { + KeyEncryptionProvider keyEncryptionProvider = getSecretKeyEncryptionAlgorithm(key, + headers.getKeyEncryptionAlgorithm()); + return createJweEncryptionProvider(keyEncryptionProvider, headers); + } + public static JweEncryptionProvider createJweEncryptionProvider(JsonWebKey key, + ContentAlgorithm contentEncryptionAlgo, + String compression) { + KeyEncryptionProvider keyEncryptionProvider = getKeyEncryptionProvider(key); + return createJweEncryptionProvider(keyEncryptionProvider, contentEncryptionAlgo, compression); + } + public static JweEncryptionProvider createJweEncryptionProvider(JsonWebKey key, JweHeaders headers) { + KeyEncryptionProvider keyEncryptionProvider = getKeyEncryptionProvider(key); + return createJweEncryptionProvider(keyEncryptionProvider, headers); + } + public static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider, + ContentAlgorithm contentEncryptionAlgo, + String compression) { + JweHeaders headers = + prepareJweHeaders(keyEncryptionProvider != null ? keyEncryptionProvider.getAlgorithm().getJwaName() : null, + contentEncryptionAlgo.getJwaName(), compression); + return createJweEncryptionProvider(keyEncryptionProvider, headers); + } + public static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider, + JweHeaders headers) { + String contentEncryptionAlgo = headers.getContentEncryptionAlgorithm().getJwaName(); + if (AlgorithmUtils.isAesCbcHmac(contentEncryptionAlgo)) { + return new AesCbcHmacJweEncryption(getContentAlgo(contentEncryptionAlgo), keyEncryptionProvider); + } else { + return new JweEncryption(keyEncryptionProvider, + getContentEncryptionAlgorithm(contentEncryptionAlgo)); + } + } + public static JweDecryptionProvider createJweDecryptionProvider(PrivateKey key, + KeyAlgorithm keyAlgo, + ContentAlgorithm contentDecryptionAlgo) { + return createJweDecryptionProvider(getPrivateKeyDecryptionProvider(key, keyAlgo), contentDecryptionAlgo); + } + public static JweDecryptionProvider createJweDecryptionProvider(SecretKey key, + KeyAlgorithm keyAlgo, + ContentAlgorithm contentDecryptionAlgo) { + return createJweDecryptionProvider(getSecretKeyDecryptionProvider(key, keyAlgo), contentDecryptionAlgo); + } + public static JweDecryptionProvider createJweDecryptionProvider(JsonWebKey key, + ContentAlgorithm contentDecryptionAlgo) { + return createJweDecryptionProvider(getKeyDecryptionProvider(key), contentDecryptionAlgo); + } + public static JweDecryptionProvider createJweDecryptionProvider(KeyDecryptionProvider keyDecryptionProvider, + ContentAlgorithm contentDecryptionAlgo) { + if (AlgorithmUtils.isAesCbcHmac(contentDecryptionAlgo.getJwaName())) { + return new AesCbcHmacJweDecryption(keyDecryptionProvider, contentDecryptionAlgo); + } else { + return new JweDecryption(keyDecryptionProvider, + getContentDecryptionProvider(contentDecryptionAlgo)); + } + } + public static boolean validateCriticalHeaders(JoseHeaders headers) { + //TODO: Validate JWE specific constraints + return JoseUtils.validateCriticalHeaders(headers); + } + public static byte[] getECDHKey(JsonWebKey privateKey, + JsonWebKey peerPublicKey, + byte[] partyUInfo, + byte[] partyVInfo, + String algoName, + int algoKeyBitLen) { + return getECDHKey(JwkUtils.toECPrivateKey(privateKey), + JwkUtils.toECPublicKey(peerPublicKey), + partyUInfo, partyVInfo, algoName, algoKeyBitLen); + } + public static byte[] getECDHKey(ECPrivateKey privateKey, + ECPublicKey peerPublicKey, + byte[] partyUInfo, + byte[] partyVInfo, + String algoName, + int algoKeyBitLen) { + byte[] keyZ = generateKeyZ(privateKey, peerPublicKey); + return calculateDerivedKey(keyZ, algoName, partyUInfo, partyVInfo, algoKeyBitLen); + } + public static byte[] getAdditionalAuthenticationData(String headersJson, byte[] aad) { + byte[] headersAAD = JweHeaders.toCipherAdditionalAuthData(headersJson); + if (aad != null) { + // JWE JSON can provide the extra aad + byte[] newAAD = Arrays.copyOf(headersAAD, headersAAD.length + 1 + aad.length); + newAAD[headersAAD.length] = '.'; + System.arraycopy(aad, 0, newAAD, headersAAD.length + 1, aad.length); + return newAAD; + } else { + return headersAAD; + } + } + private static byte[] calculateDerivedKey(byte[] keyZ, + String algoName, + byte[] apuBytes, + byte[] apvBytes, + int algoKeyBitLen) { + final byte[] emptyPartyInfo = new byte[4]; + + if (apuBytes != null && apvBytes != null && Arrays.equals(apuBytes, apvBytes)) { + LOG.warning("Derived key calculation problem: apu equals to apv"); + throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE); + } + byte[] algorithmId = concatenateDatalenAndData(StringUtils.toBytesASCII(algoName)); + byte[] partyUInfo = apuBytes == null ? emptyPartyInfo : concatenateDatalenAndData(apuBytes); + byte[] partyVInfo = apvBytes == null ? emptyPartyInfo : concatenateDatalenAndData(apvBytes); + byte[] suppPubInfo = datalenToBytes(algoKeyBitLen); + + byte[] otherInfo = new byte[algorithmId.length + + partyUInfo.length + + partyVInfo.length + + suppPubInfo.length]; + System.arraycopy(algorithmId, 0, otherInfo, 0, algorithmId.length); + System.arraycopy(partyUInfo, 0, otherInfo, algorithmId.length, partyUInfo.length); + System.arraycopy(partyVInfo, 0, otherInfo, algorithmId.length + partyUInfo.length, partyVInfo.length); + System.arraycopy(suppPubInfo, 0, otherInfo, algorithmId.length + partyUInfo.length + partyVInfo.length, + suppPubInfo.length); + + + byte[] concatKDF = new byte[36 + otherInfo.length]; + concatKDF[3] = 1; + System.arraycopy(keyZ, 0, concatKDF, 4, keyZ.length); + System.arraycopy(otherInfo, 0, concatKDF, 36, otherInfo.length); + try { + byte[] round1Hash = MessageDigestUtils.createDigest(concatKDF, MessageDigestUtils.ALGO_SHA_256); + return Arrays.copyOf(round1Hash, algoKeyBitLen / 8); + } catch (Exception ex) { + LOG.warning("Derived key calculation problem: round hash1 error"); + throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE); + } + } + private static byte[] generateKeyZ(ECPrivateKey privateKey, ECPublicKey publicKey) { + try { + KeyAgreement ka = KeyAgreement.getInstance("ECDH"); + ka.init(privateKey); + ka.doPhase(publicKey, true); + return ka.generateSecret(); + } catch (Exception ex) { + LOG.warning("Derived key calculation problem"); + throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE); + } + } + private static byte[] concatenateDatalenAndData(byte[] bytesASCII) { + final byte[] datalen = datalenToBytes(bytesASCII.length); + byte[] all = new byte[4 + bytesASCII.length]; + System.arraycopy(datalen, 0, all, 0, 4); + System.arraycopy(bytesASCII, 0, all, 4, bytesASCII.length); + return all; + } + private static byte[] datalenToBytes(int len) { + ByteBuffer buf = ByteBuffer.allocate(4); + return buf.putInt(len).array(); + } + private static JweHeaders prepareJweHeaders(String keyEncryptionAlgo, + String contentEncryptionAlgo, + String compression) { + JweHeaders headers = new JweHeaders(); + if (keyEncryptionAlgo != null) { + headers.setKeyEncryptionAlgorithm(KeyAlgorithm.getAlgorithm(keyEncryptionAlgo)); + } + headers.setContentEncryptionAlgorithm(ContentAlgorithm.getAlgorithm(contentEncryptionAlgo)); + if (compression != null) { + headers.setZipAlgorithm(compression); + } + return headers; + } + private static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider, + ContentEncryptionProvider ctEncryptionProvider, + String contentEncryptionAlgo, + String compression) { + if (keyEncryptionProvider == null && ctEncryptionProvider == null) { + LOG.warning("Key or content encryptor is not available"); + throw new JweException(JweException.Error.NO_ENCRYPTOR); + } + JweHeaders headers = + prepareJweHeaders(keyEncryptionProvider != null ? keyEncryptionProvider.getAlgorithm().getJwaName() : null, + contentEncryptionAlgo, compression); + if (keyEncryptionProvider != null) { + return createJweEncryptionProvider(keyEncryptionProvider, headers); + } else { + return new JweEncryption(new DirectKeyEncryptionAlgorithm(), ctEncryptionProvider); + } + } + private static JweDecryptionProvider createJweDecryptionProvider(KeyDecryptionProvider keyDecryptionProvider, + SecretKey ctDecryptionKey, + ContentAlgorithm contentDecryptionAlgo) { + if (keyDecryptionProvider == null && ctDecryptionKey == null) { + LOG.warning("Key or content encryptor is not available"); + throw new JweException(JweException.Error.NO_ENCRYPTOR); + } + if (keyDecryptionProvider != null) { + return createJweDecryptionProvider(keyDecryptionProvider, contentDecryptionAlgo); + } else { + return getDirectKeyJweDecryption(ctDecryptionKey, contentDecryptionAlgo); + } + } + @SuppressWarnings("deprecation") + private static String getKeyEncryptionAlgo(Message m, Properties props, + String algo, String defaultAlgo) { + if (algo == null) { + if (defaultAlgo == null) { + defaultAlgo = AlgorithmUtils.RSA_OAEP_ALGO; + } + + // Check for deprecated identifier first + String encAlgo = props.getProperty(JoseConstants.DEPR_RSSEC_ENCRYPTION_KEY_ALGORITHM); + if (encAlgo == null) { + encAlgo = (String)m.getContextualProperty(JoseConstants.DEPR_RSSEC_ENCRYPTION_KEY_ALGORITHM); + } + if (encAlgo != null) { + return encAlgo; + } + + // Otherwise check newer identifier + return KeyManagementUtils.getKeyAlgorithm(m, props, + JoseConstants.RSSEC_ENCRYPTION_KEY_ALGORITHM, defaultAlgo); + } + return algo; + } + private static String getDefaultKeyAlgo(JsonWebKey jwk) { + KeyType keyType = jwk.getKeyType(); + if (KeyType.OCTET == keyType) { + return AlgorithmUtils.A128GCMKW_ALGO; + } else { + return AlgorithmUtils.RSA_OAEP_ALGO; + } + } + @SuppressWarnings("deprecation") + private static String getContentEncryptionAlgo(Message m, Properties props, String algo) { + if (algo == null) { + // Check for deprecated identifier first + String encAlgo = props.getProperty(JoseConstants.DEPR_RSSEC_ENCRYPTION_CONTENT_ALGORITHM); + if (encAlgo == null) { + encAlgo = (String)m.getContextualProperty(JoseConstants.DEPR_RSSEC_ENCRYPTION_CONTENT_ALGORITHM); + } + if (encAlgo != null) { + return encAlgo; + } + + // Otherwise check newer identifier + return KeyManagementUtils.getKeyAlgorithm(m, props, + JoseConstants.RSSEC_ENCRYPTION_CONTENT_ALGORITHM, + AlgorithmUtils.A128GCM_ALGO); + } + return algo; + } + private static String encrypt(KeyEncryptionProvider keyEncryptionProvider, + ContentAlgorithm contentAlgo, byte[] content, String ct) { + JweEncryptionProvider jwe = createJweEncryptionProvider(keyEncryptionProvider, contentAlgo, null); + return jwe.encrypt(content, toJweHeaders(ct)); + } + private static byte[] decrypt(KeyDecryptionProvider keyDecryptionProvider, ContentAlgorithm contentAlgo, + String content) { + JweDecryptionProvider jwe = createJweDecryptionProvider(keyDecryptionProvider, contentAlgo); + return jwe.decrypt(content).getContent(); + } + private static JweHeaders toJweHeaders(String ct) { + return new JweHeaders(Collections.singletonMap(JoseConstants.HEADER_CONTENT_TYPE, ct)); + } + public static void validateJweCertificateChain(List certs) { + Message m = PhaseInterceptorChain.getCurrentMessage(); + Properties props = KeyManagementUtils.loadStoreProperties(m, true, + JoseConstants.RSSEC_ENCRYPTION_IN_PROPS, + JoseConstants.RSSEC_ENCRYPTION_PROPS); + KeyManagementUtils.validateCertificateChain(props, certs); + } + + public static void checkEncryptionKeySize(Key key) { + if (key instanceof RSAKey && ((RSAKey)key).getModulus().bitLength() < 2048) { + LOG.fine("A key of size: " + ((RSAKey)key).getModulus().bitLength() + + " was used with an RSA encryption algorithm. 2048 is the minimum size that is accepted"); + throw new JweException(JweException.Error.KEY_DECRYPTION_FAILURE); + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyDecryptionProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyDecryptionProvider.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyDecryptionProvider.java new file mode 100644 index 0000000..1924e78 --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyDecryptionProvider.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm; + + +public interface KeyDecryptionProvider { + KeyAlgorithm getAlgorithm(); + byte[] getDecryptedContentEncryptionKey(JweDecryptionInput jweDecryptionInput); +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyEncryptionProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyEncryptionProvider.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyEncryptionProvider.java new file mode 100644 index 0000000..2f5c8db --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyEncryptionProvider.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm; + + +public interface KeyEncryptionProvider { + KeyAlgorithm getAlgorithm(); + byte[] getEncryptedContentEncryptionKey(JweHeaders headers, byte[] cek); +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java new file mode 100644 index 0000000..6893ea7 --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import org.apache.cxf.common.util.Base64UrlUtility; +import org.apache.cxf.rs.security.jose.common.JoseException; +import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils; +import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm; + +public class PbesHmacAesWrapKeyDecryptionAlgorithm implements KeyDecryptionProvider { + private byte[] password; + private KeyAlgorithm algo; + public PbesHmacAesWrapKeyDecryptionAlgorithm(String password) { + this(password, KeyAlgorithm.PBES2_HS256_A128KW, false); + } + public PbesHmacAesWrapKeyDecryptionAlgorithm(String password, KeyAlgorithm algo, boolean hashLargePasswords) { + this(PbesHmacAesWrapKeyEncryptionAlgorithm.stringToBytes(password), algo, hashLargePasswords); + } + public PbesHmacAesWrapKeyDecryptionAlgorithm(char[] password) { + this(password, KeyAlgorithm.PBES2_HS256_A128KW, false); + } + public PbesHmacAesWrapKeyDecryptionAlgorithm(char[] password, KeyAlgorithm algo, boolean hashLargePasswords) { + this(PbesHmacAesWrapKeyEncryptionAlgorithm.charsToBytes(password), algo, hashLargePasswords); + } + public PbesHmacAesWrapKeyDecryptionAlgorithm(byte[] password) { + this(password, KeyAlgorithm.PBES2_HS256_A128KW, false); + } + public PbesHmacAesWrapKeyDecryptionAlgorithm(byte[] password, KeyAlgorithm algo, boolean hashLargePasswords) { + this.password = + PbesHmacAesWrapKeyEncryptionAlgorithm.validatePassword(password, algo.getJwaName(), hashLargePasswords); + this.algo = algo; + } + @Override + public byte[] getDecryptedContentEncryptionKey(JweDecryptionInput jweDecryptionInput) { + JweHeaders jweHeaders = jweDecryptionInput.getJweHeaders(); + byte[] saltInput = getDecodedBytes(jweHeaders.getHeader("p2s")); + int pbesCount = jweHeaders.getIntegerHeader("p2c"); + String keyAlgoJwt = jweHeaders.getKeyEncryptionAlgorithm().getJwaName(); + int keySize = PbesHmacAesWrapKeyEncryptionAlgorithm.getKeySize(keyAlgoJwt); + byte[] derivedKey = PbesHmacAesWrapKeyEncryptionAlgorithm + .createDerivedKey(keyAlgoJwt, keySize, password, saltInput, pbesCount); + KeyDecryptionProvider aesWrap = new AesWrapKeyDecryptionAlgorithm(derivedKey, algo) { + protected boolean isValidAlgorithmFamily(String wrapAlgo) { + return AlgorithmUtils.isPbesHsWrap(wrapAlgo); + } + }; + return aesWrap.getDecryptedContentEncryptionKey(jweDecryptionInput); + } + private byte[] getDecodedBytes(Object p2sHeader) { + try { + return Base64UrlUtility.decode(p2sHeader.toString()); + } catch (Exception ex) { + throw new JoseException(ex); + } + } + @Override + public KeyAlgorithm getAlgorithm() { + return algo; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyEncryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyEncryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyEncryptionAlgorithm.java new file mode 100644 index 0000000..0a17be5 --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyEncryptionAlgorithm.java @@ -0,0 +1,192 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.common.util.Base64UrlUtility; +import org.apache.cxf.common.util.StringUtils; +import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils; +import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm; +import org.apache.cxf.rt.security.crypto.CryptoUtils; +import org.apache.cxf.rt.security.crypto.MessageDigestUtils; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.bouncycastle.crypto.params.KeyParameter; + +public class PbesHmacAesWrapKeyEncryptionAlgorithm implements KeyEncryptionProvider { + protected static final Logger LOG = LogUtils.getL7dLogger(PbesHmacAesWrapKeyEncryptionAlgorithm.class); + private static final Map PBES_HMAC_MAP; + private static final Map PBES_AES_MAP; + private static final Map DERIVED_KEY_SIZE_MAP; + static { + PBES_HMAC_MAP = new HashMap(); + PBES_HMAC_MAP.put(KeyAlgorithm.PBES2_HS256_A128KW.getJwaName(), 256); + PBES_HMAC_MAP.put(KeyAlgorithm.PBES2_HS384_A192KW.getJwaName(), 384); + PBES_HMAC_MAP.put(KeyAlgorithm.PBES2_HS512_A256KW.getJwaName(), 512); + + PBES_AES_MAP = new HashMap(); + PBES_AES_MAP.put(KeyAlgorithm.PBES2_HS256_A128KW.getJwaName(), KeyAlgorithm.A128KW.getJwaName()); + PBES_AES_MAP.put(KeyAlgorithm.PBES2_HS384_A192KW.getJwaName(), KeyAlgorithm.A192KW.getJwaName()); + PBES_AES_MAP.put(KeyAlgorithm.PBES2_HS512_A256KW.getJwaName(), KeyAlgorithm.A256KW.getJwaName()); + + DERIVED_KEY_SIZE_MAP = new HashMap(); + DERIVED_KEY_SIZE_MAP.put(KeyAlgorithm.PBES2_HS256_A128KW.getJwaName(), 16); + DERIVED_KEY_SIZE_MAP.put(KeyAlgorithm.PBES2_HS384_A192KW.getJwaName(), 24); + DERIVED_KEY_SIZE_MAP.put(KeyAlgorithm.PBES2_HS512_A256KW.getJwaName(), 32); + } + + + private byte[] password; + private int pbesCount; + private KeyAlgorithm keyAlgoJwt; + public PbesHmacAesWrapKeyEncryptionAlgorithm(String password, KeyAlgorithm keyAlgoJwt) { + this(stringToBytes(password), keyAlgoJwt); + } + public PbesHmacAesWrapKeyEncryptionAlgorithm(String password, int pbesCount, + KeyAlgorithm keyAlgoJwt, + boolean hashLargePasswords) { + this(stringToBytes(password), pbesCount, keyAlgoJwt, hashLargePasswords); + } + public PbesHmacAesWrapKeyEncryptionAlgorithm(char[] password, KeyAlgorithm keyAlgoJwt) { + this(password, 4096, keyAlgoJwt, false); + } + public PbesHmacAesWrapKeyEncryptionAlgorithm(char[] password, int pbesCount, + KeyAlgorithm keyAlgoJwt, + boolean hashLargePasswords) { + this(charsToBytes(password), pbesCount, keyAlgoJwt, hashLargePasswords); + } + public PbesHmacAesWrapKeyEncryptionAlgorithm(byte[] password, KeyAlgorithm keyAlgoJwt) { + this(password, 4096, keyAlgoJwt, false); + } + public PbesHmacAesWrapKeyEncryptionAlgorithm(byte[] password, int pbesCount, + KeyAlgorithm keyAlgoJwt, + boolean hashLargePasswords) { + this.keyAlgoJwt = validateKeyAlgorithm(keyAlgoJwt); + this.password = validatePassword(password, keyAlgoJwt.getJwaName(), hashLargePasswords); + this.pbesCount = validatePbesCount(pbesCount); + } + + static byte[] validatePassword(byte[] p, String keyAlgoJwt, boolean hashLargePasswords) { + int minLen = DERIVED_KEY_SIZE_MAP.get(keyAlgoJwt); + if (p.length < minLen || p.length > 128) { + LOG.warning("Invalid password length: " + p.length); + throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE); + } + if (p.length > minLen && hashLargePasswords) { + try { + return MessageDigestUtils.createDigest(p, MessageDigestUtils.ALGO_SHA_256); + } catch (Exception ex) { + LOG.warning("Password hash calculation error"); + throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE, ex); + } + } else { + return p; + } + } + @Override + public byte[] getEncryptedContentEncryptionKey(JweHeaders headers, byte[] cek) { + int keySize = getKeySize(keyAlgoJwt.getJwaName()); + byte[] saltInput = CryptoUtils.generateSecureRandomBytes(keySize); + byte[] derivedKey = createDerivedKey(keyAlgoJwt.getJwaName(), + keySize, password, saltInput, pbesCount); + + headers.setHeader("p2s", Base64UrlUtility.encode(saltInput)); + headers.setIntegerHeader("p2c", pbesCount); + + KeyEncryptionProvider aesWrap = new AesWrapKeyEncryptionAlgorithm(derivedKey, keyAlgoJwt) { + protected void checkAlgorithms(JweHeaders headers) { + // complete + } + protected String getKeyEncryptionAlgoJava(JweHeaders headers) { + return AlgorithmUtils.AES_WRAP_ALGO_JAVA; + } + }; + return aesWrap.getEncryptedContentEncryptionKey(headers, cek); + + + } + static int getKeySize(String keyAlgoJwt) { + return DERIVED_KEY_SIZE_MAP.get(keyAlgoJwt); + } + static byte[] createDerivedKey(String keyAlgoJwt, int keySize, + byte[] password, byte[] saltInput, int pbesCount) { + byte[] saltValue = createSaltValue(keyAlgoJwt, saltInput); + Digest digest = null; + int macSigSize = PBES_HMAC_MAP.get(keyAlgoJwt); + if (macSigSize == 256) { + digest = new SHA256Digest(); + } else if (macSigSize == 384) { + digest = new SHA384Digest(); + } else { + digest = new SHA512Digest(); + } + PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(digest); + gen.init(password, saltValue, pbesCount); + return ((KeyParameter) gen.generateDerivedParameters(keySize * 8)).getKey(); + } + + + private static byte[] createSaltValue(String keyAlgoJwt, byte[] saltInput) { + byte[] algoBytes = stringToBytes(keyAlgoJwt); + byte[] saltValue = new byte[algoBytes.length + 1 + saltInput.length]; + System.arraycopy(algoBytes, 0, saltValue, 0, algoBytes.length); + saltValue[algoBytes.length] = 0; + System.arraycopy(saltInput, 0, saltValue, algoBytes.length + 1, saltInput.length); + return saltValue; + } + static KeyAlgorithm validateKeyAlgorithm(KeyAlgorithm algo) { + if (!AlgorithmUtils.isPbesHsWrap(algo.getJwaName())) { + LOG.warning("Invalid key encryption algorithm"); + throw new JweException(JweException.Error.INVALID_KEY_ALGORITHM); + } + return algo; + } + static int validatePbesCount(int count) { + if (count < 1000) { + LOG.warning("Iteration count is too low"); + throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE); + } + return count; + } + + static byte[] stringToBytes(String str) { + return StringUtils.toBytesUTF8(str); + } + static byte[] charsToBytes(char[] chars) { + ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)); + byte[] b = new byte[bb.remaining()]; + bb.get(b); + return b; + } + @Override + public KeyAlgorithm getAlgorithm() { + return keyAlgoJwt; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyDecryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyDecryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyDecryptionAlgorithm.java new file mode 100644 index 0000000..6950b3d --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyDecryptionAlgorithm.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import java.security.interfaces.RSAPrivateKey; + +import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils; +import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm; + +public class RSAKeyDecryptionAlgorithm extends WrappedKeyDecryptionAlgorithm { + public RSAKeyDecryptionAlgorithm(RSAPrivateKey privateKey) { + this(privateKey, KeyAlgorithm.RSA_OAEP); + } + public RSAKeyDecryptionAlgorithm(RSAPrivateKey privateKey, KeyAlgorithm supportedAlgo) { + this(privateKey, supportedAlgo, true); + } + public RSAKeyDecryptionAlgorithm(RSAPrivateKey privateKey, KeyAlgorithm supportedAlgo, boolean unwrap) { + super(privateKey, supportedAlgo, unwrap); + JweUtils.checkEncryptionKeySize(privateKey); + } + protected int getKeyCipherBlockSize() { + return ((RSAPrivateKey)getCekDecryptionKey()).getModulus().toByteArray().length; + } + @Override + protected void validateKeyEncryptionAlgorithm(String keyAlgo) { + super.validateKeyEncryptionAlgorithm(keyAlgo); + if (!AlgorithmUtils.isRsaKeyWrap(keyAlgo)) { + reportInvalidKeyAlgorithm(keyAlgo); + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyEncryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyEncryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyEncryptionAlgorithm.java new file mode 100644 index 0000000..b820cdd --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/RSAKeyEncryptionAlgorithm.java @@ -0,0 +1,34 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import java.security.interfaces.RSAPublicKey; + +import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils; +import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm; + +public class RSAKeyEncryptionAlgorithm extends AbstractWrapKeyEncryptionAlgorithm { + public RSAKeyEncryptionAlgorithm(RSAPublicKey publicKey, KeyAlgorithm jweAlgo) { + this(publicKey, jweAlgo, true); + } + public RSAKeyEncryptionAlgorithm(RSAPublicKey publicKey, KeyAlgorithm jweAlgo, boolean wrap) { + super(publicKey, jweAlgo, wrap, AlgorithmUtils.RSA_CEK_SET); + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/WrappedKeyDecryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/WrappedKeyDecryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/WrappedKeyDecryptionAlgorithm.java new file mode 100644 index 0000000..0787886 --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/WrappedKeyDecryptionAlgorithm.java @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwe; + +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.logging.Logger; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils; +import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm; +import org.apache.cxf.rt.security.crypto.CryptoUtils; +import org.apache.cxf.rt.security.crypto.KeyProperties; + +public class WrappedKeyDecryptionAlgorithm implements KeyDecryptionProvider { + protected static final Logger LOG = LogUtils.getL7dLogger(WrappedKeyDecryptionAlgorithm.class); + private Key cekDecryptionKey; + private boolean unwrap; + private KeyAlgorithm supportedAlgo; + public WrappedKeyDecryptionAlgorithm(Key cekDecryptionKey, KeyAlgorithm supportedAlgo) { + this(cekDecryptionKey, supportedAlgo, true); + } + public WrappedKeyDecryptionAlgorithm(Key cekDecryptionKey, KeyAlgorithm supportedAlgo, boolean unwrap) { + this.cekDecryptionKey = cekDecryptionKey; + this.supportedAlgo = supportedAlgo; + this.unwrap = unwrap; + } + public byte[] getDecryptedContentEncryptionKey(JweDecryptionInput jweDecryptionInput) { + KeyProperties keyProps = new KeyProperties(getKeyEncryptionAlgorithm(jweDecryptionInput)); + AlgorithmParameterSpec spec = getAlgorithmParameterSpec(jweDecryptionInput); + if (spec != null) { + keyProps.setAlgoSpec(spec); + } + if (!unwrap) { + keyProps.setBlockSize(getKeyCipherBlockSize()); + return CryptoUtils.decryptBytes(getEncryptedContentEncryptionKey(jweDecryptionInput), + getCekDecryptionKey(), keyProps); + } else { + return CryptoUtils.unwrapSecretKey(getEncryptedContentEncryptionKey(jweDecryptionInput), + getContentEncryptionAlgorithm(jweDecryptionInput), + getCekDecryptionKey(), + keyProps).getEncoded(); + } + } + + protected Key getCekDecryptionKey() { + return cekDecryptionKey; + } + protected int getKeyCipherBlockSize() { + return -1; + } + protected String getKeyEncryptionAlgorithm(JweDecryptionInput jweDecryptionInput) { + String keyAlgo = jweDecryptionInput.getJweHeaders().getKeyEncryptionAlgorithm().getJwaName(); + validateKeyEncryptionAlgorithm(keyAlgo); + return AlgorithmUtils.toJavaName(keyAlgo); + } + protected void validateKeyEncryptionAlgorithm(String keyAlgo) { + if (keyAlgo == null + || !supportedAlgo.getJwaName().equals(keyAlgo)) { + reportInvalidKeyAlgorithm(keyAlgo); + } + } + protected void reportInvalidKeyAlgorithm(String keyAlgo) { + LOG.warning("Invalid key encryption algorithm: " + keyAlgo); + throw new JweException(JweException.Error.INVALID_KEY_ALGORITHM); + } + protected String getContentEncryptionAlgorithm(JweDecryptionInput jweDecryptionInput) { + return AlgorithmUtils.toJavaName( + jweDecryptionInput.getJweHeaders().getContentEncryptionAlgorithm().getJwaName()); + } + protected AlgorithmParameterSpec getAlgorithmParameterSpec(JweDecryptionInput jweDecryptionInput) { + return null; + } + protected byte[] getEncryptedContentEncryptionKey(JweDecryptionInput jweDecryptionInput) { + return jweDecryptionInput.getEncryptedCEK(); + } + @Override + public KeyAlgorithm getAlgorithm() { + return supportedAlgo; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/DefaultJwkReaderWriter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/DefaultJwkReaderWriter.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/DefaultJwkReaderWriter.java new file mode 100644 index 0000000..dec8006 --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/DefaultJwkReaderWriter.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwk; + +import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter; + + + + + +public class DefaultJwkReaderWriter extends JsonMapObjectReaderWriter + implements JwkReaderWriter { + @Override + public String jwkSetToJson(JsonWebKeys jwks) { + return toJson(jwks); + } + @Override + public JsonWebKeys jsonToJwkSet(String jwksJson) { + JsonWebKeys jwks = new JsonWebKeys(); + fromJson(jwks, jwksJson); + return jwks; + } + @Override + public String jwkToJson(JsonWebKey jwk) { + return toJson(jwk); + } + @Override + public JsonWebKey jsonToJwk(String jwkJson) { + JsonWebKey jwk = new JsonWebKey(); + fromJson(jwk, jwkJson); + return jwk; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKey.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKey.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKey.java new file mode 100644 index 0000000..6a064e8 --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKey.java @@ -0,0 +1,180 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwk; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.jaxrs.json.basic.JsonMapObject; +import org.apache.cxf.rs.security.jose.common.JoseConstants; + + +public class JsonWebKey extends JsonMapObject { + + public static final String KEY_TYPE = "kty"; + public static final String PUBLIC_KEY_USE = "use"; + public static final String KEY_OPERATIONS = "key_ops"; + public static final String KEY_ALGO = JoseConstants.HEADER_ALGORITHM; + public static final String KEY_ID = JoseConstants.HEADER_KEY_ID; + public static final String X509_URL = JoseConstants.HEADER_X509_URL; + public static final String X509_CHAIN = JoseConstants.HEADER_X509_CHAIN; + public static final String X509_THUMBPRINT = JoseConstants.HEADER_X509_THUMBPRINT; + public static final String X509_THUMBPRINT_SHA256 = JoseConstants.HEADER_X509_THUMBPRINT_SHA256; + + public static final String KEY_TYPE_RSA = "RSA"; + public static final String RSA_MODULUS = "n"; + public static final String RSA_PUBLIC_EXP = "e"; + public static final String RSA_PRIVATE_EXP = "d"; + public static final String RSA_FIRST_PRIME_FACTOR = "p"; + public static final String RSA_SECOND_PRIME_FACTOR = "q"; + public static final String RSA_FIRST_PRIME_CRT = "dp"; + public static final String RSA_SECOND_PRIME_CRT = "dq"; + public static final String RSA_FIRST_CRT_COEFFICIENT = "qi"; + + public static final String KEY_TYPE_OCTET = "oct"; + public static final String OCTET_KEY_VALUE = "k"; + + public static final String KEY_TYPE_ELLIPTIC = "EC"; + public static final String EC_CURVE = "crv"; + public static final String EC_CURVE_P256 = "P-256"; + public static final String EC_CURVE_P384 = "P-384"; + public static final String EC_CURVE_P521 = "P-521"; + public static final String EC_X_COORDINATE = "x"; + public static final String EC_Y_COORDINATE = "y"; + public static final String EC_PRIVATE_KEY = "d"; + + public static final String PUBLIC_KEY_USE_SIGN = "sig"; + public static final String PUBLIC_KEY_USE_ENCRYPT = "enc"; + + public static final String KEY_OPER_SIGN = "sign"; + public static final String KEY_OPER_VERIFY = "verify"; + public static final String KEY_OPER_ENCRYPT = "encrypt"; + public static final String KEY_OPER_DECRYPT = "decrypt"; + public static final String KEY_OPER_WRAP_KEY = "wrapKey"; + public static final String KEY_OPER_UNWRAP_KEY = "unwrapKey"; + public static final String KEY_OPER_DERIVE_KEY = "deriveKey"; + public static final String KEY_OPER_DERIVE_BITS = "deriveBits"; + + public JsonWebKey() { + + } + + public JsonWebKey(Map values) { + super(values); + } + + public void setKeyType(KeyType keyType) { + setProperty(KEY_TYPE, keyType.toString()); + } + + public KeyType getKeyType() { + Object prop = getProperty(KEY_TYPE); + return prop == null ? null : KeyType.getKeyType(prop.toString()); + } + + public void setPublicKeyUse(PublicKeyUse use) { + setProperty(PUBLIC_KEY_USE, use.toString()); + } + + public PublicKeyUse getPublicKeyUse() { + Object prop = getProperty(PUBLIC_KEY_USE); + return prop == null ? null : PublicKeyUse.getPublicKeyUse(prop.toString()); + } + + public void setKeyOperation(List keyOperation) { + List ops = new ArrayList(keyOperation.size()); + for (KeyOperation op : keyOperation) { + ops.add(op.toString()); + } + setProperty(KEY_OPERATIONS, ops); + } + + public List getKeyOperation() { + List ops = CastUtils.cast((List)getProperty(KEY_OPERATIONS)); + if (ops == null) { + return null; + } + List keyOps = new ArrayList(ops.size()); + for (Object op : ops) { + keyOps.add(KeyOperation.getKeyOperation(op.toString())); + } + return keyOps; + } + + public void setAlgorithm(String algorithm) { + setProperty(KEY_ALGO, algorithm); + } + + public String getAlgorithm() { + return (String)getProperty(KEY_ALGO); + } + + public void setKeyId(String kid) { + setProperty(KEY_ID, kid); + } + + public String getKeyId() { + return (String)getProperty(KEY_ID); + } + + public void setX509Url(String x509Url) { + setProperty(X509_URL, x509Url); + } + + public String getX509Url() { + return (String)getProperty(X509_URL); + } + + public void setX509Chain(List x509Chain) { + setProperty(X509_CHAIN, x509Chain); + } + + public List getX509Chain() { + return CastUtils.cast((List)getProperty(X509_CHAIN)); + } + + public void setX509Thumbprint(String x509Thumbprint) { + setProperty(X509_THUMBPRINT, x509Thumbprint); + } + + public String getX509Thumbprint() { + return (String)getProperty(X509_THUMBPRINT); + } + + public void setX509ThumbprintSHA256(String x509Thumbprint) { + setProperty(X509_THUMBPRINT_SHA256, x509Thumbprint); + } + + public String getX509ThumbprintSHA256() { + return (String)getProperty(X509_THUMBPRINT_SHA256); + } + + public JsonWebKey setKeyProperty(String name, Object value) { + setProperty(name, value); + return this; + } + public Object getKeyProperty(String name) { + return getProperty(name); + } + + + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java new file mode 100644 index 0000000..28011b3 --- /dev/null +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java @@ -0,0 +1,130 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.jose.jwk; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.jaxrs.json.basic.JsonMapObject; + +public class JsonWebKeys extends JsonMapObject { + public static final String KEYS_PROPERTY = "keys"; + public List getKeys() { + List list = (List)super.getProperty(KEYS_PROPERTY); + if (list != null && !list.isEmpty()) { + Object first = list.get(0); + if (first instanceof JsonWebKey) { + return CastUtils.cast(list); + } else { + List keys = new LinkedList(); + List> listOfMaps = + CastUtils.cast((List)super.getProperty(KEYS_PROPERTY)); + for (Map map : listOfMaps) { + keys.add(new JsonWebKey(map)); + } + return keys; + } + } else { + return null; + } + } + + public void setKeys(List keys) { + super.setProperty(KEYS_PROPERTY, keys); + } + + public Map getKeyIdMap() { + List keys = getKeys(); + if (keys == null) { + return Collections.emptyMap(); + } + Map map = new LinkedHashMap(); + for (JsonWebKey key : keys) { + String kid = key.getKeyId(); + if (kid != null) { + map.put(kid, key); + } + } + return map; + } + public JsonWebKey getKey(String kid) { + return getKeyIdMap().get(kid); + } + public Map> getKeyTypeMap() { + List keys = getKeys(); + if (keys == null) { + return Collections.emptyMap(); + } + Map> map = new LinkedHashMap>(); + for (JsonWebKey key : keys) { + KeyType type = key.getKeyType(); + if (type != null) { + List list = map.get(type); + if (list == null) { + list = new LinkedList(); + map.put(type, list); + } + list.add(key); + } + } + return map; + } + + public Map> getKeyOperationMap() { + List keys = getKeys(); + if (keys == null) { + return Collections.emptyMap(); + } + Map> map = new LinkedHashMap>(); + for (JsonWebKey key : keys) { + List ops = key.getKeyOperation(); + if (ops != null) { + for (KeyOperation op : ops) { + List list = map.get(op); + if (list == null) { + list = new LinkedList(); + map.put(op, list); + } + list.add(key); + } + } + } + return map; + } + public List getKeys(String keyType) { + KeyType kt = KeyType.getKeyType(keyType); + if (kt == null) { + return null; + } + return getKeyTypeMap().get(kt); + } + public List getRsaKeys() { + return getKeyTypeMap().get(KeyType.RSA); + } + public List getEllipticKeys() { + return getKeyTypeMap().get(KeyType.EC); + } + public List getSecretKeys() { + return getKeyTypeMap().get(KeyType.OCTET); + } +}