/** * 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.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.net.URI; import java.nio.charset.StandardCharsets; 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.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import javax.crypto.SecretKey; import org.apache.cxf.Bus; import org.apache.cxf.common.util.Base64UrlUtility; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter; 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.common.JoseException; 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.common.PrivateKeyPasswordProvider; 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.jwa.SignatureAlgorithm; import org.apache.cxf.rs.security.jose.jwe.AesCbcHmacJweDecryption; import org.apache.cxf.rs.security.jose.jwe.AesCbcHmacJweEncryption; import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider; 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.JweUtils; import org.apache.cxf.rs.security.jose.jwe.KeyDecryptionProvider; import org.apache.cxf.rs.security.jose.jwe.KeyEncryptionProvider; import org.apache.cxf.rs.security.jose.jwe.PbesHmacAesWrapKeyDecryptionAlgorithm; import org.apache.cxf.rs.security.jose.jwe.PbesHmacAesWrapKeyEncryptionAlgorithm; import org.apache.cxf.rs.security.jose.jws.JwsUtils; import org.apache.cxf.rt.security.crypto.CryptoUtils; import org.apache.cxf.rt.security.crypto.MessageDigestUtils; public final class JwkUtils { private static final Map<KeyType, List<String>> JWK_REQUIRED_FIELDS_MAP; static { JWK_REQUIRED_FIELDS_MAP = new HashMap<>(); JWK_REQUIRED_FIELDS_MAP.put(KeyType.RSA, Arrays.asList( JsonWebKey.RSA_PUBLIC_EXP, JsonWebKey.KEY_TYPE, JsonWebKey.RSA_MODULUS)); JWK_REQUIRED_FIELDS_MAP.put(KeyType.EC, Arrays.asList( JsonWebKey.EC_CURVE, JsonWebKey.KEY_TYPE, JsonWebKey.EC_X_COORDINATE, JsonWebKey.EC_Y_COORDINATE)); JWK_REQUIRED_FIELDS_MAP.put(KeyType.OCTET, Arrays.asList( JsonWebKey.OCTET_KEY_VALUE, JsonWebKey.KEY_TYPE)); } private JwkUtils() { } public static String getThumbprint(String keySequence) { return getThumbprint(readJwkKey(keySequence)); } public static String getThumbprint(JsonWebKey key) { List<String> fields = getRequiredFields(key.getKeyType()); JsonWebKey thumbprintKey = new JsonWebKey(); for (String f : fields) { thumbprintKey.setProperty(f, key.getProperty(f)); } String json = new JsonMapObjectReaderWriter().toJson(thumbprintKey); byte[] digest = MessageDigestUtils.createDigest(json, MessageDigestUtils.ALGO_SHA_256); return Base64UrlUtility.encode(digest); } public static List<String> getRequiredFields(KeyType keyType) { return JWK_REQUIRED_FIELDS_MAP.get(keyType); } public static JsonWebKey readJwkKey(URI uri) throws IOException { return readJwkKey(uri.toURL().openStream()); } public static JsonWebKeys readJwkSet(URI uri) throws IOException { return readJwkSet(uri.toURL().openStream()); } public static JsonWebKey readJwkKey(InputStream is) throws IOException { return readJwkKey(IOUtils.readStringFromStream(is)); } public static JsonWebKeys readJwkSet(InputStream is) throws IOException { return readJwkSet(IOUtils.readStringFromStream(is)); } public static JsonWebKey readJwkKey(String jwkJson) { return new JwkReaderWriter().jsonToJwk(jwkJson); } public static JsonWebKeys readJwkSet(String jwksJson) { return new JwkReaderWriter().jsonToJwkSet(jwksJson); } public static String jwkKeyToJson(JsonWebKey jwkKey) { return new JwkReaderWriter().jwkToJson(jwkKey); } public static void jwkKeyToJson(JsonWebKey jwkKey, OutputStream os) throws IOException { IOUtils.copy(new ByteArrayInputStream(StringUtils.toBytesUTF8(jwkKeyToJson(jwkKey))), os); } public static String jwkSetToJson(JsonWebKeys jwkSet) { return new JwkReaderWriter().jwkSetToJson(jwkSet); } public static void jwkSetToJson(JsonWebKeys jwkSet, OutputStream os) throws IOException { IOUtils.copy(new ByteArrayInputStream(StringUtils.toBytesUTF8(jwkSetToJson(jwkSet))), os); } public static String encodeJwkKey(JsonWebKey jwkKey) { return Base64UrlUtility.encode(jwkKeyToJson(jwkKey)); } public static String encodeJwkSet(JsonWebKeys jwkSet) { return Base64UrlUtility.encode(jwkSetToJson(jwkSet)); } public static JsonWebKey decodeJwkKey(String jwkJson) { return readJwkKey(JoseUtils.decodeToString(jwkJson)); } public static JsonWebKeys decodeJwkSet(String jwksJson) { return readJwkSet(JoseUtils.decodeToString(jwksJson)); } public static String encryptJwkSet(JsonWebKeys jwkSet, char[] password) { return encryptJwkSet(jwkSet, createDefaultEncryption(password)); } public static String encryptJwkSet(JsonWebKeys jwkSet, JweEncryptionProvider jwe) { return jwe.encrypt(StringUtils.toBytesUTF8(new JwkReaderWriter().jwkSetToJson(jwkSet)), toJweHeaders("jwk-set+json")); } public static String encryptJwkSet(JsonWebKeys jwkSet, PublicKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo) { return JweUtils.encrypt(key, keyAlgo, contentAlgo, StringUtils.toBytesUTF8(jwkSetToJson(jwkSet)), "jwk-set+json"); } public static String signJwkSet(JsonWebKeys jwkSet, PrivateKey key, SignatureAlgorithm algo) { return JwsUtils.sign(key, algo, jwkSetToJson(jwkSet), "jwk-set+json"); } public static String encryptJwkSet(JsonWebKeys jwkSet, SecretKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo) { return JweUtils.encrypt(key, keyAlgo, contentAlgo, StringUtils.toBytesUTF8(jwkSetToJson(jwkSet)), "jwk-set+json"); } public static JsonWebKeys decryptJwkSet(String jsonJwkSet, char[] password) { return decryptJwkSet(jsonJwkSet, createDefaultDecryption(password)); } public static JsonWebKeys decryptJwkSet(String jsonJwkSet, JweDecryptionProvider jwe) { return new JwkReaderWriter().jsonToJwkSet(jwe.decrypt(jsonJwkSet).getContentText()); } public static JsonWebKeys decryptJwkSet(PrivateKey key, KeyAlgorithm keyAlgo, ContentAlgorithm ctAlgo, String jsonJwkSet) { return readJwkSet(toString(JweUtils.decrypt(key, keyAlgo, ctAlgo, jsonJwkSet))); } public static JsonWebKeys verifyJwkSet(PublicKey key, SignatureAlgorithm keyAlgo, String jsonJwk) { return readJwkSet(JwsUtils.verify(key, keyAlgo, jsonJwk)); } public static JsonWebKeys decryptJwkSet(SecretKey key, KeyAlgorithm keyAlgo, ContentAlgorithm ctAlgo, String jsonJwkSet) { return readJwkSet(toString(JweUtils.decrypt(key, keyAlgo, ctAlgo, jsonJwkSet))); } public static JsonWebKeys decryptJwkSet(InputStream is, char[] password) throws IOException { return decryptJwkSet(is, createDefaultDecryption(password)); } public static JsonWebKeys decryptJwkSet(InputStream is, JweDecryptionProvider jwe) throws IOException { return new JwkReaderWriter().jsonToJwkSet( jwe.decrypt(IOUtils.readStringFromStream(is)).getContentText()); } public static String encryptJwkKey(JsonWebKey jwkKey, char[] password) { return encryptJwkKey(jwkKey, createDefaultEncryption(password)); } public static String encryptJwkKey(JsonWebKey jwkKey, JweEncryptionProvider jwe) { return jwe.encrypt(StringUtils.toBytesUTF8(new JwkReaderWriter().jwkToJson(jwkKey)), toJweHeaders("jwk+json")); } public static String encryptJwkKey(JsonWebKey jwkKey, PublicKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo) { return JweUtils.encrypt(key, keyAlgo, contentAlgo, StringUtils.toBytesUTF8(jwkKeyToJson(jwkKey)), "jwk+json"); } public static String encryptJwkKey(JsonWebKey jwkKey, SecretKey key, KeyAlgorithm keyAlgo, ContentAlgorithm contentAlgo) { return JweUtils.encrypt(key, keyAlgo, contentAlgo, StringUtils.toBytesUTF8(jwkKeyToJson(jwkKey)), "jwk+json"); } public static String signJwkKey(JsonWebKey jwkKey, PrivateKey key, SignatureAlgorithm algo) { return JwsUtils.sign(key, algo, jwkKeyToJson(jwkKey), "jwk+json"); } public static JsonWebKey decryptJwkKey(String jsonJwkKey, char[] password) { return decryptJwkKey(jsonJwkKey, createDefaultDecryption(password)); } public static JsonWebKey decryptJwkKey(PrivateKey key, KeyAlgorithm keyAlgo, ContentAlgorithm ctAlgo, String jsonJwk) { return readJwkKey(toString(JweUtils.decrypt(key, keyAlgo, ctAlgo, jsonJwk))); } public static JsonWebKey verifyJwkKey(PublicKey key, SignatureAlgorithm keyAlgo, String jsonJwk) { return readJwkKey(JwsUtils.verify(key, keyAlgo, jsonJwk)); } public static JsonWebKey decryptJwkKey(SecretKey key, KeyAlgorithm keyAlgo, ContentAlgorithm ctAlgo, String jsonJwk) { return readJwkKey(toString(JweUtils.decrypt(key, keyAlgo, ctAlgo, jsonJwk))); } public static JsonWebKey decryptJwkKey(String jsonJwkKey, JweDecryptionProvider jwe) { return new JwkReaderWriter().jsonToJwk(jwe.decrypt(jsonJwkKey).getContentText()); } public static JsonWebKey decryptJwkKey(InputStream is, char[] password) throws IOException { return decryptJwkKey(is, createDefaultDecryption(password)); } public static JsonWebKey decryptJwkKey(InputStream is, JweDecryptionProvider jwe) throws IOException { return new JwkReaderWriter().jsonToJwk( jwe.decrypt(IOUtils.readStringFromStream(is)).getContentText()); } public static JsonWebKeys loadPublicJwkSet(Message m, Properties props) { return loadJwkSet(m, props, null); } public static JsonWebKeys loadJwkSet(Message m, Properties props, PrivateKeyPasswordProvider cb) { String key = (String)props.get(JoseConstants.RSSEC_KEY_STORE_FILE); JsonWebKeys jwkSet = key != null ? (JsonWebKeys)m.getExchange().get(key) : null; if (jwkSet == null) { jwkSet = loadJwkSet(props, m.getExchange().getBus(), cb); if (key != null) { m.getExchange().put(key, jwkSet); } } return jwkSet; } public static JsonWebKeys loadJwkSet(Properties props, Bus bus, PrivateKeyPasswordProvider cb) { JweDecryptionProvider decryption = cb != null ? new AesCbcHmacJweDecryption(new PbesHmacAesWrapKeyDecryptionAlgorithm( cb.getPassword(props))) : null; return loadJwkSet(props, bus, decryption); } public static JsonWebKeys loadJwkSet(Properties props, Bus bus, JweDecryptionProvider jwe) { String keyContent = null; String keyStoreLoc = props.getProperty(JoseConstants.RSSEC_KEY_STORE_FILE); if (keyStoreLoc != null) { try { InputStream is = JoseUtils.getResourceStream(keyStoreLoc, bus); if (is == null) { throw new JwkException("Error in loading keystore location: " + keyStoreLoc); } keyContent = IOUtils.readStringFromStream(is); } catch (Exception ex) { throw new JwkException(ex); } } else { keyContent = props.getProperty(JoseConstants.RSSEC_KEY_STORE_JWKSET); if (keyContent == null) { keyContent = props.getProperty(JoseConstants.RSSEC_KEY_STORE_JWKKEY); } } if (jwe != null) { keyContent = jwe.decrypt(keyContent).getContentText(); } JwkReaderWriter reader = new JwkReaderWriter(); if (props.getProperty(JoseConstants.RSSEC_KEY_STORE_JWKKEY) == null) { return reader.jsonToJwkSet(keyContent); } else { JsonWebKey jwk = reader.jsonToJwk(keyContent); return new JsonWebKeys(jwk); } } public static JsonWebKey loadJsonWebKey(Message m, Properties props, KeyOperation keyOper) { return loadJsonWebKey(m, props, keyOper, null); } public static JsonWebKey loadJsonWebKey(Message m, Properties props, KeyOperation keyOper, String inHeaderKid) { PrivateKeyPasswordProvider cb = KeyManagementUtils.loadPasswordProvider(m, props, keyOper); JsonWebKeys jwkSet = loadJwkSet(m, props, cb); String kid = null; if (inHeaderKid != null && MessageUtils.getContextualBoolean(m, JoseConstants.RSSEC_ACCEPT_PUBLIC_KEY, false)) { kid = inHeaderKid; } else { kid = KeyManagementUtils.getKeyId(m, props, JoseConstants.RSSEC_KEY_STORE_ALIAS, keyOper); } if (kid != null) { return jwkSet.getKey(kid); } else if (keyOper != null) { List<JsonWebKey> keys = jwkSet.getKeyOperationMap().get(keyOper); if (keys != null && keys.size() == 1) { return keys.get(0); } } return null; } public static List<JsonWebKey> loadJsonWebKeys(Message m, Properties props, KeyOperation keyOper) { PrivateKeyPasswordProvider cb = KeyManagementUtils.loadPasswordProvider(m, props, keyOper); JsonWebKeys jwkSet = loadJwkSet(m, props, cb); String kid = KeyManagementUtils.getKeyId(m, props, JoseConstants.RSSEC_KEY_STORE_ALIAS, keyOper); if (kid != null) { return Collections.singletonList(jwkSet.getKey(kid)); } String kids = KeyManagementUtils.getKeyId(m, props, JoseConstants.RSSEC_KEY_STORE_ALIASES, keyOper); if (kids != null) { String[] values = kids.split(","); List<JsonWebKey> keys = new ArrayList<>(values.length); for (String value : values) { keys.add(jwkSet.getKey(value)); } return keys; } if (keyOper != null) { List<JsonWebKey> keys = jwkSet.getKeyOperationMap().get(keyOper); if (keys != null && keys.size() == 1) { return Collections.singletonList(keys.get(0)); } } return null; } public static RSAPublicKey toRSAPublicKey(JsonWebKey jwk) { return toRSAPublicKey(jwk, false); } public static RSAPublicKey toRSAPublicKey(JsonWebKey jwk, boolean checkX509) { String encodedModulus = (String)jwk.getProperty(JsonWebKey.RSA_MODULUS); String encodedPublicExponent = (String)jwk.getProperty(JsonWebKey.RSA_PUBLIC_EXP); if (encodedModulus != null) { return CryptoUtils.getRSAPublicKey(encodedModulus, encodedPublicExponent); } else if (checkX509) { List<X509Certificate> chain = toX509CertificateChain(jwk); return (RSAPublicKey)chain.get(0).getPublicKey(); } return null; } public static List<X509Certificate> toX509CertificateChain(JsonWebKey jwk) { List<String> base64EncodedChain = jwk.getX509Chain(); return KeyManagementUtils.toX509CertificateChain(base64EncodedChain); } public static JsonWebKey fromECPublicKey(ECPublicKey pk, String curve) { return fromECPublicKey(pk, curve, null); } public static JsonWebKey fromECPublicKey(ECPublicKey pk, String curve, String kid) { JsonWebKey jwk = prepareECJwk(curve, kid); jwk.setProperty(JsonWebKey.EC_X_COORDINATE, Base64UrlUtility.encode(pk.getW().getAffineX().toByteArray())); jwk.setProperty(JsonWebKey.EC_Y_COORDINATE, Base64UrlUtility.encode(pk.getW().getAffineY().toByteArray())); return jwk; } public static JsonWebKey fromECPrivateKey(ECPrivateKey pk, String curve) { return fromECPrivateKey(pk, curve, null); } public static JsonWebKey fromECPrivateKey(ECPrivateKey pk, String curve, String kid) { JsonWebKey jwk = prepareECJwk(curve, kid); jwk.setProperty(JsonWebKey.EC_PRIVATE_KEY, Base64UrlUtility.encode(pk.getS().toByteArray())); return jwk; } public static JsonWebKey fromRSAPublicKey(RSAPublicKey pk, String algo) { return fromRSAPublicKey(pk, algo, null); } public static JsonWebKey fromRSAPublicKey(RSAPublicKey pk, String algo, String kid) { JsonWebKey jwk = prepareRSAJwk(pk.getModulus(), algo, kid); String encodedPublicExponent = Base64UrlUtility.encode(pk.getPublicExponent().toByteArray()); jwk.setProperty(JsonWebKey.RSA_PUBLIC_EXP, encodedPublicExponent); return jwk; } public static JsonWebKey fromPublicKey(PublicKey key, Properties props, String algoProp) { JsonWebKey jwk = null; if (key instanceof RSAPublicKey) { String algo = props.getProperty(algoProp); jwk = JwkUtils.fromRSAPublicKey((RSAPublicKey)key, algo); } else { jwk = JwkUtils.fromECPublicKey((ECPublicKey)key, props.getProperty(JoseConstants.RSSEC_EC_CURVE)); } String kid = props.getProperty(JoseConstants.RSSEC_KEY_STORE_ALIAS); if (kid != null) { jwk.setKeyId(kid); } return jwk; } public static JsonWebKey fromX509CertificateChain(List<X509Certificate> chain, String algo) { JsonWebKey jwk = new JsonWebKey(); jwk.setAlgorithm(algo); List<String> encodedChain = KeyManagementUtils.encodeX509CertificateChain(chain); jwk.setX509Chain(encodedChain); return jwk; } public static RSAPrivateKey toRSAPrivateKey(JsonWebKey jwk) { String encodedModulus = (String)jwk.getProperty(JsonWebKey.RSA_MODULUS); String encodedPrivateExponent = (String)jwk.getProperty(JsonWebKey.RSA_PRIVATE_EXP); String encodedPrimeP = (String)jwk.getProperty(JsonWebKey.RSA_FIRST_PRIME_FACTOR); if (encodedPrimeP == null) { return CryptoUtils.getRSAPrivateKey(encodedModulus, encodedPrivateExponent); } else { String encodedPublicExponent = (String)jwk.getProperty(JsonWebKey.RSA_PUBLIC_EXP); if (encodedPublicExponent == null) { throw new JoseException("JWK without the public exponent can not be converted to RSAPrivateKey"); } String encodedPrimeQ = (String)jwk.getProperty(JsonWebKey.RSA_SECOND_PRIME_FACTOR); String encodedPrimeExpP = (String)jwk.getProperty(JsonWebKey.RSA_FIRST_PRIME_CRT); String encodedPrimeExpQ = (String)jwk.getProperty(JsonWebKey.RSA_SECOND_PRIME_CRT); String encodedCrtCoefficient = (String)jwk.getProperty(JsonWebKey.RSA_FIRST_CRT_COEFFICIENT); return CryptoUtils.getRSAPrivateKey(encodedModulus, encodedPublicExponent, encodedPrivateExponent, encodedPrimeP, encodedPrimeQ, encodedPrimeExpP, encodedPrimeExpQ, encodedCrtCoefficient); } } public static JsonWebKey fromRSAPrivateKey(RSAPrivateKey pk, String algo) { return fromRSAPrivateKey(pk, algo, null); } public static JsonWebKey fromRSAPrivateKey(RSAPrivateKey pk, String algo, String kid) { JsonWebKey jwk = prepareRSAJwk(pk.getModulus(), algo, kid); String encodedPrivateExponent = Base64UrlUtility.encode(pk.getPrivateExponent().toByteArray()); jwk.setProperty(JsonWebKey.RSA_PRIVATE_EXP, encodedPrivateExponent); if (pk instanceof RSAPrivateCrtKey) { RSAPrivateCrtKey pkCrt = (RSAPrivateCrtKey)pk; jwk.setProperty(JsonWebKey.RSA_PUBLIC_EXP, Base64UrlUtility.encode(pkCrt.getPublicExponent().toByteArray())); jwk.setProperty(JsonWebKey.RSA_FIRST_PRIME_FACTOR, Base64UrlUtility.encode(pkCrt.getPrimeP().toByteArray())); jwk.setProperty(JsonWebKey.RSA_SECOND_PRIME_FACTOR, Base64UrlUtility.encode(pkCrt.getPrimeQ().toByteArray())); jwk.setProperty(JsonWebKey.RSA_FIRST_PRIME_CRT, Base64UrlUtility.encode(pkCrt.getPrimeExponentP().toByteArray())); jwk.setProperty(JsonWebKey.RSA_SECOND_PRIME_CRT, Base64UrlUtility.encode(pkCrt.getPrimeExponentQ().toByteArray())); jwk.setProperty(JsonWebKey.RSA_FIRST_CRT_COEFFICIENT, Base64UrlUtility.encode(pkCrt.getCrtCoefficient().toByteArray())); } // "oth" can be populated too if needed return jwk; } public static ECPublicKey toECPublicKey(JsonWebKey jwk) { String eCurve = (String)jwk.getProperty(JsonWebKey.EC_CURVE); String encodedXCoord = (String)jwk.getProperty(JsonWebKey.EC_X_COORDINATE); String encodedYCoord = (String)jwk.getProperty(JsonWebKey.EC_Y_COORDINATE); return CryptoUtils.getECPublicKey(eCurve, encodedXCoord, encodedYCoord); } public static ECPrivateKey toECPrivateKey(JsonWebKey jwk) { String eCurve = (String)jwk.getProperty(JsonWebKey.EC_CURVE); String encodedPrivateKey = (String)jwk.getProperty(JsonWebKey.EC_PRIVATE_KEY); return CryptoUtils.getECPrivateKey(eCurve, encodedPrivateKey); } public static SecretKey toSecretKey(JsonWebKey jwk) { return CryptoUtils.createSecretKeySpec((String)jwk.getProperty(JsonWebKey.OCTET_KEY_VALUE), AlgorithmUtils.toJavaName(jwk.getAlgorithm())); } public static JsonWebKey fromSecretKey(SecretKey secretKey, String algo) { return fromSecretKey(secretKey, algo, null); } public static JsonWebKey fromSecretKey(SecretKey secretKey, String algo, String kid) { if (!AlgorithmUtils.isOctet(algo)) { throw new JwkException("Invalid algorithm"); } JsonWebKey jwk = new JsonWebKey(); jwk.setKeyType(KeyType.OCTET); if (kid != null) { jwk.setKeyId(kid); } jwk.setAlgorithm(algo); String encodedSecretKey = Base64UrlUtility.encode(secretKey.getEncoded()); jwk.setProperty(JsonWebKey.OCTET_KEY_VALUE, encodedSecretKey); return jwk; } private static JweEncryptionProvider createDefaultEncryption(char[] password) { KeyEncryptionProvider keyEncryption = new PbesHmacAesWrapKeyEncryptionAlgorithm(password, KeyAlgorithm.PBES2_HS256_A128KW); return new AesCbcHmacJweEncryption(ContentAlgorithm.A128CBC_HS256, keyEncryption); } private static JweDecryptionProvider createDefaultDecryption(char[] password) { KeyDecryptionProvider keyDecryption = new PbesHmacAesWrapKeyDecryptionAlgorithm(password); return new AesCbcHmacJweDecryption(keyDecryption); } private static JsonWebKey prepareRSAJwk(BigInteger modulus, String algo, String kid) { JsonWebKey jwk = new JsonWebKey(); jwk.setKeyType(KeyType.RSA); if (algo != null) { if (!AlgorithmUtils.isRsa(algo)) { throw new JwkException("Invalid algorithm"); } jwk.setAlgorithm(algo); } if (kid != null) { jwk.setKeyId(kid); } byte[] modulusBytes = modulus.toByteArray(); int extraBytesLength = modulusBytes.length - modulus.bitLength() / 8; if (extraBytesLength > 0) { modulusBytes = Arrays.copyOfRange(modulusBytes, extraBytesLength, modulusBytes.length); } String encodedModulus = Base64UrlUtility.encode(modulusBytes); jwk.setProperty(JsonWebKey.RSA_MODULUS, encodedModulus); return jwk; } private static JsonWebKey prepareECJwk(String curve, String kid) { JsonWebKey jwk = new JsonWebKey(); jwk.setKeyType(KeyType.EC); if (kid != null) { jwk.setKeyId(kid); } jwk.setProperty(JsonWebKey.EC_CURVE, curve); return jwk; } private static String toString(byte[] bytes) { try { return new String(bytes, StandardCharsets.UTF_8); } catch (Exception ex) { throw new RuntimeException(ex); } } private static JweHeaders toJweHeaders(String ct) { return new JweHeaders(Collections.<String, Object>singletonMap(JoseConstants.HEADER_CONTENT_TYPE, ct)); } public static void includeCertChain(JsonWebKey jwk, JoseHeaders headers, String algo) { if (KeyType.RSA.equals(jwk.getKeyType())) { List<String> chain = CastUtils.cast((List<?>)jwk.getProperty(JsonWebKey.X509_CHAIN)); if (chain != null) { headers.setX509Chain(chain); } } } public static void includePublicKey(JsonWebKey jwk, JoseHeaders headers, String algo) { if (KeyType.RSA.equals(jwk.getKeyType())) { JsonWebKey jwkPublic = JwkUtils.fromRSAPublicKey(JwkUtils.toRSAPublicKey(jwk), algo); if (jwk.getKeyId() != null) { jwkPublic.setKeyId(jwk.getKeyId()); } headers.setJsonWebKey(jwkPublic); } } }