[CXF-7005] Supporting a blinding with adding a public exp to RSAPrivateKey JWK representation
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/683bcabd Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/683bcabd Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/683bcabd Branch: refs/heads/master-jaxrs-2.1 Commit: 683bcabd76e5c05131263115695f5c71b496951a Parents: cf461e4 Author: Sergey Beryozkin <[email protected]> Authored: Wed Aug 10 14:00:31 2016 +0100 Committer: Sergey Beryozkin <[email protected]> Committed: Wed Aug 10 14:00:31 2016 +0100 ---------------------------------------------------------------------- .../jose/common/KeyManagementUtils.java | 41 ++++++++++++++++--- .../cxf/rs/security/jose/jwk/JwkUtils.java | 42 +++++++++++++++++--- .../cxf/rs/security/jose/jwk/JwkUtilsTest.java | 36 +++++++++++++++++ 3 files changed, 108 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/683bcabd/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java index b5fe267..ddc2225 100644 --- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java @@ -138,6 +138,19 @@ public final class KeyManagementUtils { throw new JoseException(ex); } } + + public static PublicKey loadPublicKey(String keyStoreLoc, + String keyStorePassword, + String keyAlias, + Bus bus) { + try { + KeyStore keyStore = loadKeyStore(keyStoreLoc, null, keyStorePassword, bus); + return CryptoUtils.loadPublicKey(keyStore, keyAlias); + } catch (Exception ex) { + throw new SecurityException(ex); + } + } + private static String getMessageProperty(Message m, String keyStoreLocPropPreferred, String keyStoreLocPropDefault) { String propLoc = @@ -181,14 +194,26 @@ public final class KeyManagementUtils { throw new SecurityException(ex); } } - public static PrivateKey loadPrivateKey(String keyStorePropLoc, - char[] keyPassword, + public static PrivateKey loadPrivateKey(String keyStoreLoc, + String keyStorePassword, String keyAlias, + String keyPassword, + Bus bus) { + try { + KeyStore keyStore = loadKeyStore(keyStoreLoc, null, keyStorePassword, bus); + return CryptoUtils.loadPrivateKey(keyStore, + keyPassword == null ? new char[]{} : keyPassword.toCharArray(), + keyAlias); + } catch (Exception ex) { + throw new SecurityException(ex); + } + } + + public static PrivateKey loadPrivateKey(String keyStorePropLoc, Bus bus) { try { Properties props = JoseUtils.loadProperties(keyStorePropLoc, bus); - KeyStore keyStore = loadPersistKeyStore(null, props); - return CryptoUtils.loadPrivateKey(keyStore, keyPassword, keyAlias); + return loadPrivateKey(null, props, null); } catch (Exception ex) { throw new SecurityException(ex); } @@ -275,10 +300,16 @@ public final class KeyManagementUtils { return keyStore; } public static KeyStore loadKeyStore(Properties props, Bus bus) { - String keyStoreType = props.getProperty(JoseConstants.RSSEC_KEY_STORE_TYPE); String keyStoreLoc = props.getProperty(JoseConstants.RSSEC_KEY_STORE_FILE); + String keyStoreType = props.getProperty(JoseConstants.RSSEC_KEY_STORE_TYPE); String keyStorePswd = props.getProperty(JoseConstants.RSSEC_KEY_STORE_PSWD); + return loadKeyStore(keyStoreLoc, keyStoreType, keyStorePswd, bus); + } + public static KeyStore loadKeyStore(String keyStoreLoc, + String keyStoreType, + String keyStorePswd, + Bus bus) { if (keyStorePswd == null) { throw new JoseException("No keystore password was defined"); } http://git-wip-us.apache.org/repos/asf/cxf/blob/683bcabd/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java index 4248663..ffe3223 100644 --- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java +++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java @@ -52,6 +52,7 @@ 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; @@ -357,7 +358,10 @@ public final class JwkUtils { return KeyManagementUtils.toX509CertificateChain(base64EncodedChain); } public static JsonWebKey fromECPublicKey(ECPublicKey pk, String curve) { - JsonWebKey jwk = prepareECJwk(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, @@ -365,13 +369,19 @@ public final class JwkUtils { return jwk; } public static JsonWebKey fromECPrivateKey(ECPrivateKey pk, String curve) { - JsonWebKey jwk = prepareECJwk(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) { - JsonWebKey jwk = prepareRSAJwk(pk.getModulus(), 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; @@ -407,6 +417,9 @@ public final class JwkUtils { 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); @@ -422,11 +435,16 @@ public final class JwkUtils { } } public static JsonWebKey fromRSAPrivateKey(RSAPrivateKey pk, String algo) { - JsonWebKey jwk = prepareRSAJwk(pk.getModulus(), 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, @@ -458,11 +476,17 @@ public final class JwkUtils { 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); @@ -479,7 +503,7 @@ public final class JwkUtils { KeyDecryptionProvider keyDecryption = new PbesHmacAesWrapKeyDecryptionAlgorithm(password); return new AesCbcHmacJweDecryption(keyDecryption); } - private static JsonWebKey prepareRSAJwk(BigInteger modulus, String algo) { + private static JsonWebKey prepareRSAJwk(BigInteger modulus, String algo, String kid) { JsonWebKey jwk = new JsonWebKey(); jwk.setKeyType(KeyType.RSA); if (algo != null) { @@ -488,6 +512,9 @@ public final class JwkUtils { } jwk.setAlgorithm(algo); } + if (kid != null) { + jwk.setKeyId(kid); + } byte[] modulusBytes = modulus.toByteArray(); int extraBytesLength = modulusBytes.length - modulus.bitLength() / 8; if (extraBytesLength > 0) { @@ -497,9 +524,12 @@ public final class JwkUtils { jwk.setProperty(JsonWebKey.RSA_MODULUS, encodedModulus); return jwk; } - private static JsonWebKey prepareECJwk(String curve) { + 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; } http://git-wip-us.apache.org/repos/asf/cxf/blob/683bcabd/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java index b71b6f7..762f7f8 100644 --- a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java +++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java @@ -18,9 +18,13 @@ */ package org.apache.cxf.rs.security.jose.jwk; +import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; +import org.apache.cxf.rs.security.jose.common.JoseException; 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.KeyAlgorithm; import org.junit.Assert; import org.junit.Test; @@ -77,6 +81,38 @@ public class JwkUtilsTest extends Assert { assertEquals(modulus2, modulus); } @Test + public void testFromToPrivateRsaKey() throws Exception { + RSAPrivateKey privateKey1 = + (RSAPrivateKey)KeyManagementUtils.loadPrivateKey("org/apache/cxf/rs/security/jose/jws/alice.jks", + "password", + "alice", + "password", + null); + JsonWebKey jwk1 = JwkUtils.fromRSAPrivateKey(privateKey1, KeyAlgorithm.RSA_OAEP_256.getJwaName()); + assertNotNull(jwk1.getProperty(JsonWebKey.RSA_PUBLIC_EXP)); + RSAPrivateKey privateKey2 = JwkUtils.toRSAPrivateKey(jwk1); + assertEquals(privateKey2, privateKey1); + + } + @Test + public void testToPrivateRsaKeyWithoutE() throws Exception { + RSAPrivateKey privateKey1 = + (RSAPrivateKey)KeyManagementUtils.loadPrivateKey("org/apache/cxf/rs/security/jose/jws/alice.jks", + "password", + "alice", + "password", + null); + JsonWebKey jwk1 = JwkUtils.fromRSAPrivateKey(privateKey1, KeyAlgorithm.RSA_OAEP_256.getJwaName()); + assertNotNull(jwk1.getProperty(JsonWebKey.RSA_PUBLIC_EXP)); + jwk1.asMap().remove(JsonWebKey.RSA_PUBLIC_EXP); + try { + JwkUtils.toRSAPrivateKey(jwk1); + fail("JWK without the public exponent can not be converted to RSAPrivateKey"); + } catch (JoseException ex) { + // expected + } + } + @Test public void testRsaKeyThumbprint() throws Exception { String thumbprint = JwkUtils.getThumbprint(RSA_KEY); assertEquals("NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs", thumbprint);
