/**
* 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.InputStream;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import org.apache.cxf.helpers.IOUtils;
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.jwe.JweCompactConsumer;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Assert;
import org.junit.Test;
public class JsonWebKeyTest extends Assert {
private static final String RSA_MODULUS_VALUE = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt"
+ "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf"
+ "0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt"
+ "-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw";
private static final String RSA_PUBLIC_EXP_VALUE = "AQAB";
private static final String RSA_PRIVATE_EXP_VALUE = "X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7d"
+ "x5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ4"
+ "6pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66"
+ "jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q";
private static final String RSA_FIRST_PRIME_FACTOR_VALUE = "83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQ"
+ "BQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9"
+ "RzzOGVQzXvNEvn7O0nVbfs";
private static final String RSA_SECOND_PRIME_FACTOR_VALUE = "3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3"
+ "vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfA"
+ "ITAG9LUnADun4vIcb6yelxk";
private static final String RSA_FIRST_PRIME_CRT_VALUE = "G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0o"
+ "imYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUm"
+ "s6rY3Ob8YeiKkTiBj0";
private static final String RSA_SECOND_PRIME_CRT_VALUE = "s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6hu"
+ "UUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvW"
+ "rX-L18txXw494Q_cgk";
private static final String RSA_FIRST_CRT_COEFFICIENT_VALUE = "GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfm"
+ "t0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKF"
+ "YItdldUKGzO6Ia6zTKhAVRU";
private static final String RSA_KID_VALUE = "2011-04-29";
private static final String EC_CURVE_VALUE = JsonWebKey.EC_CURVE_P256;
private static final String EC_X_COORDINATE_VALUE = "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4";
private static final String EC_Y_COORDINATE_VALUE = "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM";
private static final String EC_PRIVATE_KEY_VALUE = "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE";
private static final String EC_KID_VALUE = "1";
private static final String AES_SECRET_VALUE = "GawgguFyGrWKav7AX4VKUg";
private static final String AES_KID_VALUE = "AesWrapKey";
private static final String HMAC_SECRET_VALUE = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3"
+ "Yj0iPS4hcgUuTwjAzZr1Z9CAow";
private static final String HMAC_KID_VALUE = "HMACKey";
@Test
public void testPublicSetAsList() throws Exception {
JsonWebKeys jwks = readKeySet("jwkPublicSet.txt");
List<JsonWebKey> keys = jwks.getKeys();
assertEquals(3, keys.size());
JsonWebKey ecKey = keys.get(0);
assertEquals(6, ecKey.asMap().size());
validatePublicEcKey(ecKey);
JsonWebKey rsaKey = keys.get(1);
assertEquals(5, rsaKey.asMap().size());
validatePublicRsaKey(rsaKey);
JsonWebKey rsaKeyCert = keys.get(2);
assertEquals(3, rsaKeyCert.asMap().size());
assertEquals(3, rsaKeyCert.getX509Chain().size());
List<X509Certificate> certs = JwkUtils.toX509CertificateChain(rsaKeyCert);
assertEquals(3, certs.size());
}
@Test
public void testPublicSetAsMap() throws Exception {
JsonWebKeys jwks = readKeySet("jwkPublicSet.txt");
Map<String, JsonWebKey> keysMap = jwks.getKeyIdMap();
assertEquals(3, keysMap.size());
JsonWebKey rsaKey = keysMap.get(RSA_KID_VALUE);
assertEquals(5, rsaKey.asMap().size());
validatePublicRsaKey(rsaKey);
JsonWebKey ecKey = keysMap.get(EC_KID_VALUE);
assertEquals(6, ecKey.asMap().size());
validatePublicEcKey(ecKey);
}
@Test
public void testPrivateSetAsList() throws Exception {
JsonWebKeys jwks = readKeySet("jwkPrivateSet.txt");
validatePrivateSet(jwks);
}
private void validatePrivateSet(JsonWebKeys jwks) throws Exception {
List<JsonWebKey> keys = jwks.getKeys();
assertEquals(2, keys.size());
JsonWebKey ecKey = keys.get(0);
assertEquals(7, ecKey.asMap().size());
validatePrivateEcKey(ecKey);
JsonWebKey rsaKey = keys.get(1);
assertEquals(11, rsaKey.asMap().size());
validatePrivateRsaKey(rsaKey);
}
@Test
public void testEncryptDecryptPrivateSet() throws Exception {
final String password = "Thus from my lips, by yours, my sin is purged.";
Security.addProvider(new BouncyCastleProvider());
try {
JsonWebKeys jwks = readKeySet("jwkPrivateSet.txt");
validatePrivateSet(jwks);
String encryptedKeySet = JwkUtils.encryptJwkSet(jwks, password.toCharArray());
JweCompactConsumer c = new JweCompactConsumer(encryptedKeySet);
assertEquals("jwk-set+json", c.getJweHeaders().getContentType());
assertEquals(KeyAlgorithm.PBES2_HS256_A128KW, c.getJweHeaders().getKeyEncryptionAlgorithm());
assertEquals(ContentAlgorithm.A128CBC_HS256, c.getJweHeaders().getContentEncryptionAlgorithm());
assertNotNull(c.getJweHeaders().getHeader("p2s"));
assertNotNull(c.getJweHeaders().getHeader("p2c"));
jwks = JwkUtils.decryptJwkSet(encryptedKeySet, password.toCharArray());
validatePrivateSet(jwks);
} finally {
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
}
}
@Test
public void testEncryptDecryptPrivateKey() throws Exception {
final String password = "Thus from my lips, by yours, my sin is purged.";
final String key = "{\"kty\":\"oct\","
+ "\"alg\":\"A128KW\","
+ "\"k\":\"GawgguFyGrWKav7AX4VKUg\","
+ "\"kid\":\"AesWrapKey\"}";
Security.addProvider(new BouncyCastleProvider());
try {
JsonWebKey jwk = readKey(key);
validateSecretAesKey(jwk);
String encryptedKey = JwkUtils.encryptJwkKey(jwk, password.toCharArray());
JweCompactConsumer c = new JweCompactConsumer(encryptedKey);
assertEquals("jwk+json", c.getJweHeaders().getContentType());
assertEquals(KeyAlgorithm.PBES2_HS256_A128KW, c.getJweHeaders().getKeyEncryptionAlgorithm());
assertEquals(ContentAlgorithm.A128CBC_HS256, c.getJweHeaders().getContentEncryptionAlgorithm());
assertNotNull(c.getJweHeaders().getHeader("p2s"));
assertNotNull(c.getJweHeaders().getHeader("p2c"));
jwk = JwkUtils.decryptJwkKey(encryptedKey, password.toCharArray());
validateSecretAesKey(jwk);
} finally {
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
}
}
@Test
public void testSecretSetAsList() throws Exception {
JsonWebKeys jwks = readKeySet("jwkSecretSet.txt");
List<JsonWebKey> keys = jwks.getKeys();
assertEquals(2, keys.size());
JsonWebKey aesKey = keys.get(0);
assertEquals(4, aesKey.asMap().size());
validateSecretAesKey(aesKey);
JsonWebKey hmacKey = keys.get(1);
assertEquals(4, hmacKey.asMap().size());
validateSecretHmacKey(hmacKey);
}
private void validateSecretAesKey(JsonWebKey key) {
assertEquals(AES_SECRET_VALUE, key.getProperty(JsonWebKey.OCTET_KEY_VALUE));
assertEquals(AES_KID_VALUE, key.getKeyId());
assertEquals(KeyType.OCTET, key.getKeyType());
assertEquals(AlgorithmUtils.A128KW_ALGO, key.getAlgorithm());
}
private void validateSecretHmacKey(JsonWebKey key) {
assertEquals(HMAC_SECRET_VALUE, key.getProperty(JsonWebKey.OCTET_KEY_VALUE));
assertEquals(HMAC_KID_VALUE, key.getKeyId());
assertEquals(KeyType.OCTET, key.getKeyType());
assertEquals(AlgorithmUtils.HMAC_SHA_256_ALGO, key.getAlgorithm());
}
private void validatePublicRsaKey(JsonWebKey key) {
assertEquals(RSA_MODULUS_VALUE, key.getProperty(JsonWebKey.RSA_MODULUS));
assertEquals(RSA_PUBLIC_EXP_VALUE, key.getProperty(JsonWebKey.RSA_PUBLIC_EXP));
assertEquals(RSA_KID_VALUE, key.getKeyId());
assertEquals(KeyType.RSA, key.getKeyType());
assertEquals(AlgorithmUtils.RS_SHA_256_ALGO, key.getAlgorithm());
}
private void validatePrivateRsaKey(JsonWebKey key) {
validatePublicRsaKey(key);
assertEquals(RSA_PRIVATE_EXP_VALUE, key.getProperty(JsonWebKey.RSA_PRIVATE_EXP));
assertEquals(RSA_FIRST_PRIME_FACTOR_VALUE, key.getProperty(JsonWebKey.RSA_FIRST_PRIME_FACTOR));
assertEquals(RSA_SECOND_PRIME_FACTOR_VALUE, key.getProperty(JsonWebKey.RSA_SECOND_PRIME_FACTOR));
assertEquals(RSA_FIRST_PRIME_CRT_VALUE, key.getProperty(JsonWebKey.RSA_FIRST_PRIME_CRT));
assertEquals(RSA_SECOND_PRIME_CRT_VALUE, key.getProperty(JsonWebKey.RSA_SECOND_PRIME_CRT));
assertEquals(RSA_FIRST_CRT_COEFFICIENT_VALUE, key.getProperty(JsonWebKey.RSA_FIRST_CRT_COEFFICIENT));
}
private void validatePublicEcKey(JsonWebKey key) {
assertEquals(EC_X_COORDINATE_VALUE, key.getProperty(JsonWebKey.EC_X_COORDINATE));
assertEquals(EC_Y_COORDINATE_VALUE, key.getProperty(JsonWebKey.EC_Y_COORDINATE));
assertEquals(EC_KID_VALUE, key.getKeyId());
assertEquals(KeyType.EC, key.getKeyType());
assertEquals(EC_CURVE_VALUE, key.getProperty(JsonWebKey.EC_CURVE));
assertEquals(PublicKeyUse.ENCRYPT, key.getPublicKeyUse());
}
private void validatePrivateEcKey(JsonWebKey key) {
validatePublicEcKey(key);
assertEquals(EC_PRIVATE_KEY_VALUE, key.getProperty(JsonWebKey.EC_PRIVATE_KEY));
}
public JsonWebKeys readKeySet(String fileName) throws Exception {
InputStream is = JsonWebKeyTest.class.getResourceAsStream(fileName);
String s = IOUtils.readStringFromStream(is);
return JwkUtils.readJwkSet(s);
}
public JsonWebKey readKey(String key) throws Exception {
return JwkUtils.readJwkKey(key);
}
}