Skip to content

Commit e300d82

Browse files
Jesse WilsonAndroid (Google) Code Review
authored andcommitted
Merge "Add an API to expose Next Protocol Negotiation (NPN)."
2 parents 6af84f6 + f5fb5e8 commit e300d82

File tree

3 files changed

+98
-8
lines changed

3 files changed

+98
-8
lines changed

api/current.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11924,8 +11924,10 @@ package android.net {
1192411924
method public java.lang.String[] getDefaultCipherSuites();
1192511925
method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
1192611926
method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
11927+
method public byte[] getNpnSelectedProtocol(java.net.Socket);
1192711928
method public java.lang.String[] getSupportedCipherSuites();
1192811929
method public void setKeyManagers(javax.net.ssl.KeyManager[]);
11930+
method public void setNpnProtocols(byte[][]);
1192911931
method public void setTrustManagers(javax.net.ssl.TrustManager[]);
1193011932
}
1193111933

core/java/android/net/SSLCertificateSocketFactory.java

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@
1818

1919
import android.os.SystemProperties;
2020
import android.util.Log;
21-
2221
import java.io.IOException;
2322
import java.net.InetAddress;
2423
import java.net.Socket;
2524
import java.security.KeyManagementException;
2625
import java.security.cert.X509Certificate;
27-
2826
import javax.net.SocketFactory;
2927
import javax.net.ssl.HostnameVerifier;
3028
import javax.net.ssl.HttpsURLConnection;
@@ -36,7 +34,6 @@
3634
import javax.net.ssl.SSLSocketFactory;
3735
import javax.net.ssl.TrustManager;
3836
import javax.net.ssl.X509TrustManager;
39-
4037
import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
4138
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
4239
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
@@ -89,6 +86,7 @@ public void checkServerTrusted(X509Certificate[] certs, String authType) { }
8986
private SSLSocketFactory mSecureFactory = null;
9087
private TrustManager[] mTrustManagers = null;
9188
private KeyManager[] mKeyManagers = null;
89+
private byte[] mNpnProtocols = null;
9290

9391
private final int mHandshakeTimeoutMillis;
9492
private final SSLClientSessionCache mSessionCache;
@@ -250,6 +248,60 @@ public void setTrustManagers(TrustManager[] trustManager) {
250248
// be cleared out here.
251249
}
252250

251+
/**
252+
* Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
253+
* Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
254+
*
255+
* <p>For servers this is the sequence of protocols to advertise as
256+
* supported, in order of preference. This list is sent unencrypted to
257+
* all clients that support NPN.
258+
*
259+
* <p>For clients this is a list of supported protocols to match against the
260+
* server's list. If there is no protocol supported by both client and
261+
* server then the first protocol in the client's list will be selected.
262+
* The order of the client's protocols is otherwise insignificant.
263+
*
264+
* @param npnProtocols a possibly-empty list of protocol byte arrays. All
265+
* arrays must be non-empty and of length less than 256.
266+
*/
267+
public void setNpnProtocols(byte[][] npnProtocols) {
268+
this.mNpnProtocols = toNpnProtocolsList(npnProtocols);
269+
}
270+
271+
/**
272+
* Returns an array containing the concatenation of length-prefixed byte
273+
* strings.
274+
*/
275+
static byte[] toNpnProtocolsList(byte[]... npnProtocols) {
276+
int totalLength = 0;
277+
for (byte[] s : npnProtocols) {
278+
if (s.length == 0 || s.length > 255) {
279+
throw new IllegalArgumentException("s.length == 0 || s.length > 255: " + s.length);
280+
}
281+
totalLength += 1 + s.length;
282+
}
283+
byte[] result = new byte[totalLength];
284+
int pos = 0;
285+
for (byte[] s : npnProtocols) {
286+
result[pos++] = (byte) s.length;
287+
for (byte b : s) {
288+
result[pos++] = b;
289+
}
290+
}
291+
return result;
292+
}
293+
294+
/**
295+
* Returns the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
296+
* Protocol Negotiation (NPN)</a> protocol selected by client and server, or
297+
* null if no protocol was negotiated.
298+
*
299+
* @param socket a socket created by this factory.
300+
*/
301+
public byte[] getNpnSelectedProtocol(Socket socket) {
302+
return ((OpenSSLSocketImpl) socket).getNpnSelectedProtocol();
303+
}
304+
253305
/**
254306
* Sets the {@link KeyManager}s to be used for connections made by this factory.
255307
*/
@@ -271,6 +323,7 @@ public void setKeyManagers(KeyManager[] keyManagers) {
271323
@Override
272324
public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
273325
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
326+
s.setNpnProtocols(mNpnProtocols);
274327
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
275328
if (mSecure) {
276329
verifyHostname(s, host);
@@ -289,6 +342,7 @@ public Socket createSocket(Socket k, String host, int port, boolean close) throw
289342
@Override
290343
public Socket createSocket() throws IOException {
291344
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
345+
s.setNpnProtocols(mNpnProtocols);
292346
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
293347
return s;
294348
}
@@ -305,6 +359,7 @@ public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, in
305359
throws IOException {
306360
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
307361
addr, port, localAddr, localPort);
362+
s.setNpnProtocols(mNpnProtocols);
308363
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
309364
return s;
310365
}
@@ -319,6 +374,7 @@ public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, in
319374
@Override
320375
public Socket createSocket(InetAddress addr, int port) throws IOException {
321376
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
377+
s.setNpnProtocols(mNpnProtocols);
322378
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
323379
return s;
324380
}
@@ -334,6 +390,7 @@ public Socket createSocket(String host, int port, InetAddress localAddr, int loc
334390
throws IOException {
335391
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
336392
host, port, localAddr, localPort);
393+
s.setNpnProtocols(mNpnProtocols);
337394
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
338395
if (mSecure) {
339396
verifyHostname(s, host);
@@ -350,6 +407,7 @@ public Socket createSocket(String host, int port, InetAddress localAddr, int loc
350407
@Override
351408
public Socket createSocket(String host, int port) throws IOException {
352409
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
410+
s.setNpnProtocols(mNpnProtocols);
353411
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
354412
if (mSecure) {
355413
verifyHostname(s, host);

core/tests/coretests/src/android/net/SSLTest.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,16 @@
1616

1717
package android.net;
1818

19-
import android.net.SSLCertificateSocketFactory;
2019
import android.test.suitebuilder.annotation.Suppress;
21-
import junit.framework.TestCase;
22-
2320
import java.io.InputStream;
2421
import java.io.OutputStream;
2522
import java.net.Socket;
23+
import java.util.Arrays;
24+
import junit.framework.TestCase;
2625

27-
//This test relies on network resources.
28-
@Suppress
2926
public class SSLTest extends TestCase {
27+
//This test relies on network resources.
28+
@Suppress
3029
public void testCertificate() throws Exception {
3130
// test www.fortify.net/sslcheck.html
3231
Socket ssl = SSLCertificateSocketFactory.getDefault().createSocket("www.fortify.net",443);
@@ -49,4 +48,35 @@ public void testCertificate() throws Exception {
4948

5049
// System.out.println(new String(b));
5150
}
51+
52+
public void testStringsToNpnBytes() {
53+
byte[] expected = {
54+
6, 's', 'p', 'd', 'y', '/', '2',
55+
8, 'h', 't', 't', 'p', '/', '1', '.', '1',
56+
};
57+
assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList(
58+
new byte[] { 's', 'p', 'd', 'y', '/', '2' },
59+
new byte[] { 'h', 't', 't', 'p', '/', '1', '.', '1' })));
60+
}
61+
62+
public void testStringsToNpnBytesEmptyByteArray() {
63+
try {
64+
SSLCertificateSocketFactory.toNpnProtocolsList(new byte[0]);
65+
fail();
66+
} catch (IllegalArgumentException expected) {
67+
}
68+
}
69+
70+
public void testStringsToNpnBytesEmptyArray() {
71+
byte[] expected = {};
72+
assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList()));
73+
}
74+
75+
public void testStringsToNpnBytesOversizedInput() {
76+
try {
77+
SSLCertificateSocketFactory.toNpnProtocolsList(new byte[256]);
78+
fail();
79+
} catch (IllegalArgumentException expected) {
80+
}
81+
}
5282
}

0 commit comments

Comments
 (0)