Skip to content

Commit

Permalink
IosSslSocket: allow to specify the TLS version when creating the cont…
Browse files Browse the repository at this point in the history
…ext.

	Change on 2018/10/08 by antoniocortes <antoniocortes@google.com>

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=216297168
  • Loading branch information
antonio-cortes-perez authored and Tom Ball committed Oct 9, 2018
1 parent ede271d commit 5f98a9e
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 13 deletions.
58 changes: 56 additions & 2 deletions jre_emul/Classes/com/google/j2objc/net/ssl/IosSslContextSpi.java
Expand Up @@ -14,6 +14,7 @@

package com.google.j2objc.net.ssl;

import com.google.j2objc.security.IosSecurityProvider.SslProtocol;
import java.security.KeyManagementException;
import java.security.SecureRandom;
import javax.net.ssl.KeyManager;
Expand All @@ -28,15 +29,23 @@
/** Returns factories that use Apple's SecureTransport API. */
public class IosSslContextSpi extends SSLContextSpi {

private final SslProtocol protocol;

private IosSslContextSpi(SslProtocol protocol) {
this.protocol = protocol;
}

@Override
protected void engineInit(KeyManager[] km, TrustManager[] tm, SecureRandom sr)
throws KeyManagementException {
throw new UnsupportedOperationException();
if (km != null || tm != null || sr != null) {
throw new UnsupportedOperationException();
}
}

@Override
protected SSLSocketFactory engineGetSocketFactory() {
return new IosSslSocketFactory();
return new IosSslSocketFactory(protocol);
}

@Override
Expand Down Expand Up @@ -73,4 +82,49 @@ protected SSLParameters engineGetDefaultSSLParameters() {
protected SSLParameters engineGetSupportedSSLParameters() {
return super.engineGetSupportedSSLParameters();
}

/**
* Public to allow construction via the provider framework.
*/
public static final class Default extends IosSslContextSpi {
public Default() {
super(SslProtocol.DEFAULT);
}
}

/**
* Public to allow construction via the provider framework.
*/
public static final class Tls extends IosSslContextSpi {
public Tls() {
super(SslProtocol.TLS);
}
}

/**
* Public to allow construction via the provider framework.
*/
public static final class TlsV1 extends IosSslContextSpi {
public TlsV1() {
super(SslProtocol.TLS_V1);
}
}

/**
* Public to allow construction via the provider framework.
*/
public static final class TlsV11 extends IosSslContextSpi {
public TlsV11() {
super(SslProtocol.TLS_V11);
}
}

/**
* Public to allow construction via the provider framework.
*/
public static final class TlsV12 extends IosSslContextSpi {
public TlsV12() {
super(SslProtocol.TLS_V12);
}
}
}
39 changes: 36 additions & 3 deletions jre_emul/Classes/com/google/j2objc/net/ssl/IosSslSocket.m
Expand Up @@ -15,9 +15,11 @@
#import <Security/Security.h>

#import "J2ObjC_source.h"
#import "com/google/j2objc/security/IosSecurityProvider.h"
#import "java/io/InputStream.h"
#import "java/io/OutputStream.h"
#import "java/lang/Exception.h"
#import "java/lang/IllegalArgumentException.h"
#import "java/lang/UnsupportedOperationException.h"
#import "java/net/InetAddress.h"
#import "java/net/SocketException.h"
Expand All @@ -32,6 +34,9 @@
static void setUpContext(ComGoogleJ2objcNetSslIosSslSocket *self);
static void tearDownContext(ComGoogleJ2objcNetSslIosSslSocket *self);

// Maps from Java SSL constants to the SSLProtocol enumeration.
static NSDictionary *protocolMapping;

// The users of this class perform I/O via the two stream specializations: SslInputStream and
// SslOutputStream. The actual network I/O operations are perfomed by the inherited java streams.
// Expected data flow:
Expand All @@ -43,6 +48,7 @@ @interface ComGoogleJ2objcNetSslIosSslSocket() {
SSLContextRef _sslContext;
SslInputStream *_sslInputStream;
SslOutputStream *_sslOutputStream;
IOSObjectArray *enabledProtocols;
BOOL handshakeCompleted;

// Used to forward exceptions from the plain streams to the SSL streams.
Expand Down Expand Up @@ -176,6 +182,22 @@ - (void)flush {

@implementation ComGoogleJ2objcNetSslIosSslSocket

+ (void)initialize {
NSMutableDictionary *temp = [[[NSMutableDictionary alloc] init] autorelease];
NSString *key;
key = [ComGoogleJ2objcSecurityIosSecurityProvider_SslProtocol_get_DEFAULT() description];
temp[key] = @(kTLSProtocol1);
key = [ComGoogleJ2objcSecurityIosSecurityProvider_SslProtocol_get_TLS() description];
temp[key] = @(kTLSProtocol1);
key = [ComGoogleJ2objcSecurityIosSecurityProvider_SslProtocol_get_TLS_V1() description];
temp[key] = @(kTLSProtocol1);
key = [ComGoogleJ2objcSecurityIosSecurityProvider_SslProtocol_get_TLS_V11() description];
temp[key] = @(kTLSProtocol11);
key = [ComGoogleJ2objcSecurityIosSecurityProvider_SslProtocol_get_TLS_V12() description];
temp[key] = @(kTLSProtocol12);
protocolMapping = [[NSDictionary alloc] initWithDictionary:temp];
}

- (JavaIoInputStream *)plainInputStream {
return [super getInputStream];
}
Expand Down Expand Up @@ -225,15 +247,24 @@ - (void)setEnabledCipherSuitesWithNSStringArray:(IOSObjectArray *)suites {
}

- (IOSObjectArray *)getSupportedProtocols {
return [IOSObjectArray arrayWithLength:0 type:NSString_class_()];
return [IOSObjectArray arrayWithArray:enabledProtocols];
}

- (IOSObjectArray *)getEnabledProtocols {
return [IOSObjectArray arrayWithLength:0 type:NSString_class_()];
return [IOSObjectArray arrayWithArray:enabledProtocols];
}

- (void)setEnabledProtocolsWithNSStringArray:(IOSObjectArray *)protocols {
J2ObjCThrowByName(JavaLangUnsupportedOperationException, @"");
if (!protocols) {
J2ObjCThrowByName(JavaLangIllegalArgumentException, @"Null argument");
}
for (NSString *p in protocols) {
if (!protocolMapping[p]) {
NSString *msg = [NSString stringWithFormat:@"Invalid protocol: %@", p];
J2ObjCThrowByName(JavaLangIllegalArgumentException, msg);
}
}
JreStrongAssign(&enabledProtocols, [IOSObjectArray arrayWithArray:protocols]);
}

- (id<JavaxNetSslSSLSession>)getSession {
Expand Down Expand Up @@ -356,6 +387,8 @@ static void setUpContext(ComGoogleJ2objcNetSslIosSslSocket *self) {
checkStatus(SSLSetConnection(self->_sslContext, self));
NSString *hostName = [[self getInetAddress] getHostName];
checkStatus(SSLSetPeerDomainName(self->_sslContext, [hostName UTF8String], [hostName length]));
SSLProtocol protocol = [protocolMapping[[self->enabledProtocols objectAtIndex:0]] intValue];
checkStatus(SSLSetProtocolVersionMin(self->_sslContext, protocol));
}

static void tearDownContext(ComGoogleJ2objcNetSslIosSslSocket *self) {
Expand Down
Expand Up @@ -14,6 +14,7 @@

package com.google.j2objc.net.ssl;

import com.google.j2objc.security.IosSecurityProvider.SslProtocol;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
Expand All @@ -23,6 +24,12 @@
/** Creates SSL sockets that use Apple's SecureTransport API. */
public class IosSslSocketFactory extends SSLSocketFactory {

private final String[] enabledProtocols;

public IosSslSocketFactory(SslProtocol protocol) {
enabledProtocols = new String[] {protocol.toString()};
}

@Override
public String[] getDefaultCipherSuites() {
return new String[0];
Expand All @@ -35,7 +42,9 @@ public String[] getSupportedCipherSuites() {

@Override
public Socket createSocket() throws IOException {
return new IosSslSocket();
IosSslSocket socket = new IosSslSocket();
socket.setEnabledProtocols(enabledProtocols);
return socket;
}

@Override
Expand All @@ -46,23 +55,31 @@ public Socket createSocket(Socket s, String host, int port, boolean autoClose)

@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return new IosSslSocket(host, port);
IosSslSocket socket = new IosSslSocket(host, port);
socket.setEnabledProtocols(enabledProtocols);
return socket;
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException {
return new IosSslSocket(host, port, localHost, localPort);
IosSslSocket socket = new IosSslSocket(host, port, localHost, localPort);
socket.setEnabledProtocols(enabledProtocols);
return socket;
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return new IosSslSocket(host, port);
IosSslSocket socket = new IosSslSocket(host, port);
socket.setEnabledProtocols(enabledProtocols);
return socket;
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
throws IOException {
return new IosSslSocket(address, port, localAddress, localPort);
IosSslSocket socket = new IosSslSocket(address, port, localAddress, localPort);
socket.setEnabledProtocols(enabledProtocols);
return socket;
}
}
Expand Up @@ -33,6 +33,8 @@ public class IosSecurityProvider extends Provider {

private static final String PREFIX = "com.google.j2objc.security.";

private static final String SSL_PREFIX = "com.google.j2objc.net.ssl.IosSslContextSpi";

private static final long serialVersionUID = 1L;

public IosSecurityProvider() {
Expand Down Expand Up @@ -111,7 +113,11 @@ public IosSecurityProvider() {
put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1",
"SHA512WithRSA");

put("SSLContext.Default", "com.google.j2objc.net.ssl.IosSslContextSpi");
put("SSLContext." + SslProtocol.DEFAULT, SSL_PREFIX + "$Default");
put("SSLContext." + SslProtocol.TLS, SSL_PREFIX + "$Tls");
put("SSLContext." + SslProtocol.TLS_V1, SSL_PREFIX + "$TlsV1");
put("SSLContext." + SslProtocol.TLS_V11, SSL_PREFIX + "$TlsV11");
put("SSLContext." + SslProtocol.TLS_V12, SSL_PREFIX + "$TlsV12");
}

// Reference all dynamically loaded classes, so they are linked into apps.
Expand All @@ -125,4 +131,25 @@ public IosSecurityProvider() {
IosSecureRandomImpl.class,
IosSHAMessageDigest.class
};

/** SSL protocols supported by the Android platform. */
public enum SslProtocol {
DEFAULT("Default"),
SSL("SSL"),
SSLv3("SSLv3"),
TLS("TLS"),
TLS_V1("TLSv1"),
TLS_V11("TLSv1.1"),
TLS_V12 ("TLSv1.2");

private final String name;
SslProtocol(String name) {
this.name = name;
}

@Override
public String toString() {
return name;
}
}
}
Expand Up @@ -301,7 +301,7 @@ public void j2objcNotImplemented_test_WantClientAuth()
/**
* javax.net.ssl.SSLSocket#getSupportedProtocols()
*/
public void j2objcNotImplemented_test_getSupportedProtocols() throws IOException {
public void test_getSupportedProtocols() throws IOException {
SSLSocket ssl = getSSLSocket();
String[] res = ssl.getSupportedProtocols();
assertTrue("No supported protocols found", res.length > 0);
Expand All @@ -312,7 +312,7 @@ public void j2objcNotImplemented_test_getSupportedProtocols() throws IOException
* javax.net.ssl.SSLSocket#getEnabledProtocols()
* javax.net.ssl.SSLSocket#setEnabledProtocols(String[] protocols)
*/
public void j2objcNotImplemented_test_EnabledProtocols() throws IOException {
public void test_EnabledProtocols() throws IOException {
SSLSocket ssl = getSSLSocket();
try {
ssl.setEnabledProtocols(null);
Expand Down

0 comments on commit 5f98a9e

Please sign in to comment.