Repository: cxf Updated Branches: refs/heads/master 903b25083 -> a46e5d411
[CXF-5311] Adding a signature test with EC keys Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/a46e5d41 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/a46e5d41 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/a46e5d41 Branch: refs/heads/master Commit: a46e5d4114a59763d550d1cc80a4b57a4d7bba82 Parents: 903b250 Author: Sergey Beryozkin <[email protected]> Authored: Tue Jul 22 18:22:08 2014 +0300 Committer: Sergey Beryozkin <[email protected]> Committed: Tue Jul 22 18:22:08 2014 +0300 ---------------------------------------------------------------------- .../oauth2/jws/EcDsaJwsSignatureProvider.java | 45 ++++++++++++++++ .../jws/PrivateKeyJwsSignatureProvider.java | 11 +++- .../cxf/rs/security/oauth2/jwt/Algorithm.java | 13 +++++ .../rs/security/oauth2/jwt/JwtConstants.java | 3 ++ .../oauth2/jws/JwsCompactReaderWriterTest.java | 27 +++++++++- .../oauth2/utils/crypto/CryptoUtils.java | 57 +++++++++++++++++++- 6 files changed, 152 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/a46e5d41/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/EcDsaJwsSignatureProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/EcDsaJwsSignatureProvider.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/EcDsaJwsSignatureProvider.java new file mode 100644 index 0000000..8077cf3 --- /dev/null +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/EcDsaJwsSignatureProvider.java @@ -0,0 +1,45 @@ +/** + * 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.oauth2.jws; + +import java.security.SecureRandom; +import java.security.interfaces.ECPrivateKey; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.apache.cxf.rs.security.oauth2.jwt.Algorithm; + +public class EcDsaJwsSignatureProvider extends PrivateKeyJwsSignatureProvider { + private static final Set<String> SUPPORTED_ALGORITHMS = new HashSet<String>( + Arrays.asList(Algorithm.SHA256withECDSA.getJwtName(), + Algorithm.SHA384withECDSA.getJwtName(), + Algorithm.SHA512withECDSA.getJwtName())); + + public EcDsaJwsSignatureProvider(ECPrivateKey key) { + this(key, null); + } + public EcDsaJwsSignatureProvider(ECPrivateKey key, AlgorithmParameterSpec spec) { + this(key, null, spec); + } + public EcDsaJwsSignatureProvider(ECPrivateKey key, SecureRandom random, AlgorithmParameterSpec spec) { + super(key, random, spec, SUPPORTED_ALGORITHMS); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/a46e5d41/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/PrivateKeyJwsSignatureProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/PrivateKeyJwsSignatureProvider.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/PrivateKeyJwsSignatureProvider.java index aebc1e4..62efdf0 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/PrivateKeyJwsSignatureProvider.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jws/PrivateKeyJwsSignatureProvider.java @@ -46,8 +46,15 @@ public class PrivateKeyJwsSignatureProvider extends AbstractJwsSignatureProvider public PrivateKeyJwsSignatureProvider(PrivateKey key, AlgorithmParameterSpec spec) { this(key, null, spec); } - public PrivateKeyJwsSignatureProvider(PrivateKey key, SecureRandom random, AlgorithmParameterSpec spec) { - super(SUPPORTED_ALGORITHMS); + public PrivateKeyJwsSignatureProvider(PrivateKey key, SecureRandom random, + AlgorithmParameterSpec spec) { + this(key, random, spec, SUPPORTED_ALGORITHMS); + } + protected PrivateKeyJwsSignatureProvider(PrivateKey key, + SecureRandom random, + AlgorithmParameterSpec spec, + Set<String> supportedAlgorithms) { + super(supportedAlgorithms); this.key = key; this.random = random; this.signatureSpec = spec; http://git-wip-us.apache.org/repos/asf/cxf/blob/a46e5d41/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java index c6c7afc..19382db 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java @@ -35,6 +35,10 @@ public enum Algorithm { SHA384withRSA(JwtConstants.RS_SHA_384_ALGO, 384), SHA512withRSA(JwtConstants.RS_SHA_512_ALGO, 512), + SHA256withECDSA(JwtConstants.ES_SHA_256_ALGO, 256), + SHA384withECDSA(JwtConstants.ES_SHA_384_ALGO, 384), + SHA512withECDSA(JwtConstants.ES_SHA_512_ALGO, 512), + // Key Encryption RSA_OAEP(JwtConstants.RSA_OAEP_ALGO, "RSA/ECB/OAEPWithSHA-1AndMGF1Padding", -1), // Content Encryption @@ -48,6 +52,9 @@ public enum Algorithm { public static final String RS_SHA_256_JAVA = "SHA256withRSA"; public static final String RS_SHA_384_JAVA = "SHA384withRSA"; public static final String RS_SHA_512_JAVA = "SHA512withRSA"; + public static final String ES_SHA_256_JAVA = "SHA256withECDSA"; + public static final String ES_SHA_384_JAVA = "SHA384withECDSA"; + public static final String ES_SHA_512_JAVA = "SHA512withECDSA"; public static final String RSA_OAEP_ALGO_JAVA = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; public static final String RSA_OAEP_256_ALGO_JAVA = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; public static final String RSA_1_5_ALGO_JAVA = "RSA/ECB/PKCS1Padding"; @@ -64,6 +71,9 @@ public enum Algorithm { JAVA_TO_JWT_NAMES.put(RS_SHA_256_JAVA, JwtConstants.RS_SHA_256_ALGO); JAVA_TO_JWT_NAMES.put(RS_SHA_384_JAVA, JwtConstants.RS_SHA_384_ALGO); JAVA_TO_JWT_NAMES.put(RS_SHA_512_JAVA, JwtConstants.RS_SHA_512_ALGO); + JAVA_TO_JWT_NAMES.put(ES_SHA_256_JAVA, JwtConstants.ES_SHA_256_ALGO); + JAVA_TO_JWT_NAMES.put(ES_SHA_384_JAVA, JwtConstants.ES_SHA_384_ALGO); + JAVA_TO_JWT_NAMES.put(ES_SHA_512_JAVA, JwtConstants.ES_SHA_512_ALGO); JAVA_TO_JWT_NAMES.put(RSA_OAEP_ALGO_JAVA, JwtConstants.RSA_OAEP_ALGO); JAVA_TO_JWT_NAMES.put(RSA_OAEP_256_ALGO_JAVA, JwtConstants.RSA_OAEP_256_ALGO); JAVA_TO_JWT_NAMES.put(RSA_1_5_ALGO_JAVA, JwtConstants.RSA_1_5_ALGO); @@ -74,6 +84,9 @@ public enum Algorithm { JWT_TO_JAVA_NAMES.put(JwtConstants.RS_SHA_256_ALGO, RS_SHA_256_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.RS_SHA_384_ALGO, RS_SHA_384_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.RS_SHA_512_ALGO, RS_SHA_512_JAVA); + JWT_TO_JAVA_NAMES.put(JwtConstants.ES_SHA_256_ALGO, ES_SHA_256_JAVA); + JWT_TO_JAVA_NAMES.put(JwtConstants.ES_SHA_384_ALGO, ES_SHA_384_JAVA); + JWT_TO_JAVA_NAMES.put(JwtConstants.ES_SHA_512_ALGO, ES_SHA_512_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.RSA_OAEP_ALGO, RSA_OAEP_ALGO_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.RSA_OAEP_256_ALGO, RSA_OAEP_256_ALGO_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.RSA_1_5_ALGO, RSA_1_5_ALGO_JAVA); http://git-wip-us.apache.org/repos/asf/cxf/blob/a46e5d41/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java index 25ab366..e6eee3d 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java @@ -57,6 +57,9 @@ public final class JwtConstants { public static final String RS_SHA_256_ALGO = "RS256"; public static final String RS_SHA_384_ALGO = "RS384"; public static final String RS_SHA_512_ALGO = "RS512"; + public static final String ES_SHA_256_ALGO = "ES256"; + public static final String ES_SHA_384_ALGO = "ES384"; + public static final String ES_SHA_512_ALGO = "ES512"; public static final String RSA_OAEP_ALGO = "RSA-OAEP"; public static final String RSA_OAEP_256_ALGO = "RSA-OAEP-256"; public static final String RSA_1_5_ALGO = "RSA1_5"; http://git-wip-us.apache.org/repos/asf/cxf/blob/a46e5d41/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jws/JwsCompactReaderWriterTest.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jws/JwsCompactReaderWriterTest.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jws/JwsCompactReaderWriterTest.java index 83e3c86..026575a 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jws/JwsCompactReaderWriterTest.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jws/JwsCompactReaderWriterTest.java @@ -19,6 +19,8 @@ package org.apache.cxf.rs.security.oauth2.jws; import java.security.PrivateKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; import java.util.Arrays; import java.util.LinkedHashMap; @@ -82,6 +84,12 @@ public class JwsCompactReaderWriterTest extends Assert { + "hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB" + "p0igcN_IoypGlUPQGe77Rw"; + private static final String EC_PRIVATE_KEY_ENCODED = + "jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"; + private static final String EC_X_POINT_ENCODED = + "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU"; + private static final String EC_Y_POINT_ENCODED = + "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"; @Test public void testWriteJwsSignedByMacSpecExample() throws Exception { JwtHeaders headers = new JwtHeaders(Algorithm.HmacSHA256.getJwtName()); @@ -186,7 +194,7 @@ public class JwsCompactReaderWriterTest extends Assert { } @Test - public void testWriteReadJwsSignedByPrivateKey() throws Exception { + public void testWriteJwsSignedByPrivateKey() throws Exception { JwtHeaders headers = new JwtHeaders(); headers.setAlgorithm(Algorithm.SHA256withRSA.getJwtName()); JwsCompactProducer jws = initSpecJwtTokenWriter(headers); @@ -197,6 +205,23 @@ public class JwsCompactReaderWriterTest extends Assert { } @Test + public void testWriteReadJwsSignedByESPrivateKey() throws Exception { + JwtHeaders headers = new JwtHeaders(); + headers.setAlgorithm(Algorithm.SHA256withECDSA.getJwtName()); + JwsCompactProducer jws = initSpecJwtTokenWriter(headers); + ECPrivateKey privateKey = CryptoUtils.getECPrivateKey(EC_PRIVATE_KEY_ENCODED); + jws.signWith(new EcDsaJwsSignatureProvider(privateKey)); + String signedJws = jws.getSignedEncodedJws(); + ECPublicKey publicKey = CryptoUtils.getECPublicKey(EC_X_POINT_ENCODED, EC_Y_POINT_ENCODED); + JwsJwtCompactConsumer jwsConsumer = new JwsJwtCompactConsumer(signedJws); + assertTrue(jwsConsumer.verifySignatureWith(new PublicKeyJwsSignatureVerifier(publicKey))); + JwtToken token = jwsConsumer.getJwtToken(); + JwtHeaders headersReceived = token.getHeaders(); + assertEquals(Algorithm.SHA256withECDSA.getJwtName(), headersReceived.getAlgorithm()); + validateSpecClaim(token.getClaims()); + } + + @Test public void testReadJwsSignedByPrivateKey() throws Exception { JwsJwtCompactConsumer jws = new JwsJwtCompactConsumer(ENCODED_TOKEN_SIGNED_BY_PRIVATE_KEY); RSAPublicKey key = CryptoUtils.getRSAPublicKey(RSA_MODULUS_ENCODED, RSA_PUBLIC_EXPONENT_ENCODED); http://git-wip-us.apache.org/repos/asf/cxf/blob/a46e5d41/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/crypto/CryptoUtils.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/crypto/CryptoUtils.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/crypto/CryptoUtils.java index 23cc8b7..69edbfc 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/crypto/CryptoUtils.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/crypto/CryptoUtils.java @@ -25,6 +25,7 @@ import java.lang.reflect.Method; import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; +import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.Principal; import java.security.PrivateKey; @@ -32,9 +33,16 @@ import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; import java.security.cert.Certificate; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.util.Properties; @@ -284,7 +292,54 @@ public final class CryptoUtils { throw new SecurityException(ex); } } - + public static ECPrivateKey getECPrivateKey(String encodedPrivateKey) { + try { + return getECPrivateKey(Base64UrlUtility.decode(encodedPrivateKey)); + } catch (Exception ex) { + throw new SecurityException(ex); + } + } + public static ECPrivateKey getECPrivateKey(byte[] privateKey) { + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + ECGenParameterSpec kpgparams = new ECGenParameterSpec("secp256r1"); + kpg.initialize(kpgparams); + ECParameterSpec params = ((ECPublicKey) kpg.generateKeyPair().getPublic()).getParams(); + + ECPrivateKeySpec keySpec = new ECPrivateKeySpec( + new BigInteger(1, privateKey), params); + KeyFactory kf = KeyFactory.getInstance("EC"); + return (ECPrivateKey) kf.generatePrivate(keySpec); + + } catch (Exception ex) { + throw new SecurityException(ex); + } + } + public static ECPublicKey getECPublicKey(String encodedXPoint, String encodedYPoint) { + try { + return getECPublicKey(Base64UrlUtility.decode(encodedXPoint), + Base64UrlUtility.decode(encodedYPoint)); + } catch (Exception ex) { + throw new SecurityException(ex); + } + } + public static ECPublicKey getECPublicKey(byte[] xPoint, byte[] yPoint) { + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + ECGenParameterSpec kpgparams = new ECGenParameterSpec("secp256r1"); + kpg.initialize(kpgparams); + ECParameterSpec params = ((ECPublicKey) kpg.generateKeyPair().getPublic()).getParams(); + + ECPoint ecPoint = new ECPoint(new BigInteger(1, xPoint), + new BigInteger(1, yPoint)); + ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, params); + KeyFactory kf = KeyFactory.getInstance("EC"); + return (ECPublicKey) kf.generatePublic(keySpec); + + } catch (Exception ex) { + throw new SecurityException(ex); + } + } public static AlgorithmParameterSpec getContentEncryptionCipherSpec(int authTagLength, byte[] iv) { // this can be overridden if needed if (authTagLength > 0) {
