diff options
7 files changed, 204 insertions, 11 deletions
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECGroupContext.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECGroupContext.java index 3d9e138..0ca4272 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECGroupContext.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECGroupContext.java @@ -26,10 +26,10 @@ import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; import java.security.spec.EllipticCurve; -final class OpenSSLECGroupContext { +public final class OpenSSLECGroupContext { private final int groupCtx; - OpenSSLECGroupContext(int groupCtx) { + public OpenSSLECGroupContext(int groupCtx) { this.groupCtx = groupCtx; } diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECKeyFactory.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECKeyFactory.java new file mode 100644 index 0000000..13b1203 --- /dev/null +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECKeyFactory.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed 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.harmony.xnet.provider.jsse; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class OpenSSLECKeyFactory extends KeyFactorySpi { + + @Override + protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { + if (keySpec instanceof ECPublicKeySpec) { + ECPublicKeySpec ecKeySpec = (ECPublicKeySpec) keySpec; + + return new OpenSSLECPublicKey(ecKeySpec); + } else if (keySpec instanceof X509EncodedKeySpec) { + X509EncodedKeySpec x509KeySpec = (X509EncodedKeySpec) keySpec; + + try { + final OpenSSLKey key = new OpenSSLKey( + NativeCrypto.d2i_PUBKEY(x509KeySpec.getEncoded())); + return new OpenSSLECPublicKey(key); + } catch (Exception e) { + throw new InvalidKeySpecException(e); + } + } + throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was " + + keySpec.getClass().getName()); + } + + @Override + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { + if (keySpec instanceof ECPrivateKeySpec) { + ECPrivateKeySpec ecKeySpec = (ECPrivateKeySpec) keySpec; + + return new OpenSSLECPrivateKey(ecKeySpec); + } else if (keySpec instanceof PKCS8EncodedKeySpec) { + PKCS8EncodedKeySpec pkcs8KeySpec = (PKCS8EncodedKeySpec) keySpec; + + try { + final OpenSSLKey key = new OpenSSLKey( + NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(pkcs8KeySpec.getEncoded())); + return new OpenSSLECPrivateKey(key); + } catch (Exception e) { + throw new InvalidKeySpecException(e); + } + } + throw new InvalidKeySpecException("Must use ECPublicKeySpec or PKCS8EncodedKeySpec; was " + + keySpec.getClass().getName()); + } + + @Override + protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) + throws InvalidKeySpecException { + if (key == null) { + throw new InvalidKeySpecException("key == null"); + } + + if (keySpec == null) { + throw new InvalidKeySpecException("keySpec == null"); + } + + if (key instanceof ECPublicKey) { + ECPublicKey ecKey = (ECPublicKey) key; + + if (ECPublicKeySpec.class.equals(keySpec)) { + ECParameterSpec params = ecKey.getParams(); + + ECPoint w = ecKey.getW(); + + return (T) new ECPublicKeySpec(w, params); + } else if (PKCS8EncodedKeySpec.class.equals(keySpec)) { + return (T) new PKCS8EncodedKeySpec(key.getEncoded()); + } else { + throw new InvalidKeySpecException("Must be ECPublicKeySpec or PKCS8EncodedKeySpec"); + } + } else if (key instanceof ECPrivateKey) { + ECPrivateKey ecKey = (ECPrivateKey) key; + + if (ECPrivateKeySpec.class.equals(keySpec)) { + ECParameterSpec params = ecKey.getParams(); + + BigInteger s = ecKey.getS(); + + return (T) new ECPrivateKeySpec(s, params); + } else if (X509EncodedKeySpec.class.equals(keySpec)) { + return (T) new X509EncodedKeySpec(ecKey.getEncoded()); + } else { + throw new InvalidKeySpecException("Must be ECPrivateKeySpec or X509EncodedKeySpec"); + } + } else { + throw new InvalidKeySpecException("Must be ECPublicKey or ECPrivateKey"); + } + } + + @Override + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + if (key == null) { + throw new InvalidKeyException("key == null"); + } + + if (key instanceof ECPublicKey) { + ECPublicKey ecKey = (ECPublicKey) key; + + ECPoint w = ecKey.getW(); + + ECParameterSpec params = ecKey.getParams(); + + try { + return engineGeneratePublic(new ECPublicKeySpec(w, params)); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException(e); + } + } else if (key instanceof ECPrivateKey) { + ECPrivateKey ecKey = (ECPrivateKey) key; + + BigInteger s = ecKey.getS(); + + ECParameterSpec params = ecKey.getParams(); + + try { + return engineGeneratePublic(new ECPrivateKeySpec(s, params)); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException(e); + } + } else { + throw new InvalidKeyException("Key is not ECPublicKey or ECPrivateKey"); + } + } + +} diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPrivateKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPrivateKey.java index f80fbeb..508354e 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPrivateKey.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPrivateKey.java @@ -25,6 +25,8 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.interfaces.ECPrivateKey; import java.security.spec.ECParameterSpec; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.InvalidKeySpecException; import java.util.Arrays; public final class OpenSSLECPrivateKey implements ECPrivateKey, OpenSSLKeyHolder { @@ -47,6 +49,18 @@ public final class OpenSSLECPrivateKey implements ECPrivateKey, OpenSSLKeyHolder this.key = key; } + public OpenSSLECPrivateKey(ECPrivateKeySpec ecKeySpec) throws InvalidKeySpecException { + try { + OpenSSLECGroupContext group = OpenSSLECGroupContext.getInstance(ecKeySpec + .getParams()); + final BigInteger privKey = ecKeySpec.getS(); + key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 0, + privKey.toByteArray())); + } catch (Exception e) { + throw new InvalidKeySpecException(e); + } + } + public static OpenSSLKey getInstance(ECPrivateKey ecPrivateKey) throws InvalidKeyException { try { OpenSSLECGroupContext group = OpenSSLECGroupContext.getInstance(ecPrivateKey diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPublicKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPublicKey.java index 118df67..951ee0b 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPublicKey.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLECPublicKey.java @@ -26,6 +26,8 @@ import java.security.InvalidKeyException; import java.security.interfaces.ECPublicKey; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; import java.util.Arrays; public final class OpenSSLECPublicKey implements ECPublicKey, OpenSSLKeyHolder { @@ -48,6 +50,18 @@ public final class OpenSSLECPublicKey implements ECPublicKey, OpenSSLKeyHolder { this.key = key; } + public OpenSSLECPublicKey(ECPublicKeySpec ecKeySpec) throws InvalidKeySpecException { + try { + OpenSSLECGroupContext group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams()); + OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance( + NativeCrypto.get_EC_GROUP_type(group.getContext()), group, ecKeySpec.getW()); + key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), + pubKey.getContext(), null)); + } catch (Exception e) { + throw new InvalidKeySpecException(e); + } + } + public static OpenSSLKey getInstance(ECPublicKey ecPublicKey) throws InvalidKeyException { try { OpenSSLECGroupContext group = OpenSSLECGroupContext diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java index 8aab3bb..1c6a86e 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java @@ -79,11 +79,12 @@ public final class OpenSSLProvider extends Provider { put("KeyPairGenerator.EC", OpenSSLECKeyPairGenerator.class.getName()); /* == KeyFactory == */ - put("KeyFactory.RSA", OpenSSLRSAKeyFactory.class.getName()); put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.1", "RSA"); - // put("KeyFactory.DSA", OpenSSLDSAKeyFactory.class.getName()); + put("KeyFactory.DSA", OpenSSLDSAKeyFactory.class.getName()); + + put("KeyFactory.EC", OpenSSLECKeyFactory.class.getName()); /* == Signatures == */ put("Signature.MD5WithRSA", OpenSSLSignature.MD5RSA.class.getName()); diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyFactory.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyFactory.java index 49d31d3..60be4da 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyFactory.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyFactory.java @@ -33,7 +33,7 @@ import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; -public class OpenSSLRSAKeyFactory<T, S> extends KeyFactorySpi { +public class OpenSSLRSAKeyFactory extends KeyFactorySpi { @Override protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java index 1502520..5434702 100644 --- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java +++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java @@ -135,17 +135,16 @@ public class NativeCryptoTest extends TestCase { } private static synchronized void initChannelIdKey() throws Exception { + if (CHANNEL_ID_PRIVATE_KEY != null) { + return; + } + // NIST P-256 aka SECG secp256r1 aka X9.62 prime256v1 OpenSSLECGroupContext openSslSpec = OpenSSLECGroupContext.getCurveByName("prime256v1"); BigInteger s = new BigInteger( "229cdbbf489aea584828a261a23f9ff8b0f66f7ccac98bf2096ab3aee41497c5", 16); - KeyFactory keyFactory = KeyFactory.getInstance("EC"); - CHANNEL_ID_PRIVATE_KEY = (ECPrivateKey) keyFactory.generatePrivate( - new ECPrivateKeySpec(s, openSslSpec.getECParameterSpec())); - // Since OpenSSL-backed EC KeyFactory is not yet implemented, we manually convert - // the private key (most likely a BouncyCastle one) to an OpenSSL-backed one. CHANNEL_ID_PRIVATE_KEY = new OpenSSLECPrivateKey( - openSslSpec, OpenSSLECPrivateKey.getInstance(CHANNEL_ID_PRIVATE_KEY)); + new ECPrivateKeySpec(s, openSslSpec.getECParameterSpec())); // Channel ID is the concatenation of the X and Y coordinates of the public key. CHANNEL_ID = new BigInteger( @@ -1045,6 +1044,8 @@ public class NativeCryptoTest extends TestCase { } public void test_SSL_do_handshake_with_channel_id_normal() throws Exception { + initChannelIdKey(); + // Normal handshake with TLS Channel ID. final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks(); @@ -1069,6 +1070,8 @@ public class NativeCryptoTest extends TestCase { } public void test_SSL_do_handshake_with_channel_id_not_supported_by_server() throws Exception { + initChannelIdKey(); + // Client tries to use TLS Channel ID but the server does not enable/offer the extension. final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks(); @@ -1093,6 +1096,8 @@ public class NativeCryptoTest extends TestCase { } public void test_SSL_do_handshake_with_channel_id_not_enabled_by_client() throws Exception { + initChannelIdKey(); + // Client does not use TLS Channel ID when the server has the extension enabled/offered. final ServerSocket listener = new ServerSocket(0); Hooks cHooks = new Hooks(); |