Skip to content

Commit 6ed7c6c

Browse files
authored
Return an ExtendSSLSession whenever possible to allow more strict checking when using OpenSSL (netty#8281)
Motivation: When an ExtendedSSLSession is used its possible to do more strict checking of the keys during handshake. We should do this whenever possible. Modification: - Return an ExtendedSSLSession when using client-mode and Java7+ - Add unit test - Simplify unit tests Result: More consistent behaviour.
1 parent 9eb124b commit 6ed7c6c

File tree

7 files changed

+511
-82
lines changed

7 files changed

+511
-82
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
* Copyright 2018 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.ssl;
17+
18+
import io.netty.util.internal.EmptyArrays;
19+
20+
import javax.net.ssl.ExtendedSSLSession;
21+
import javax.net.ssl.SSLException;
22+
import javax.net.ssl.SSLPeerUnverifiedException;
23+
import javax.net.ssl.SSLSessionContext;
24+
import javax.security.cert.X509Certificate;
25+
import java.security.Principal;
26+
import java.security.cert.Certificate;
27+
import java.util.List;
28+
29+
/**
30+
* Delegates all operations to a wrapped {@link OpenSslSession} except the methods defined by {@link ExtendedSSLSession}
31+
* itself.
32+
*/
33+
abstract class ExtendedOpenSslSession extends ExtendedSSLSession implements OpenSslSession {
34+
35+
// TODO: use OpenSSL API to actually fetch the real data but for now just do what Conscrypt does:
36+
// https://github.com/google/conscrypt/blob/1.2.0/common/
37+
// src/main/java/org/conscrypt/Java7ExtendedSSLSession.java#L32
38+
private static final String[] LOCAL_SUPPORTED_SIGNATURE_ALGORITHMS = {
39+
"SHA512withRSA", "SHA512withECDSA", "SHA384withRSA", "SHA384withECDSA", "SHA256withRSA",
40+
"SHA256withECDSA", "SHA224withRSA", "SHA224withECDSA", "SHA1withRSA", "SHA1withECDSA",
41+
};
42+
43+
private final OpenSslSession wrapped;
44+
45+
ExtendedOpenSslSession(OpenSslSession wrapped) {
46+
assert !(wrapped instanceof ExtendedSSLSession);
47+
this.wrapped = wrapped;
48+
}
49+
50+
// Use rawtypes an unchecked override to be able to also work on java7.
51+
@SuppressWarnings({ "unchecked", "rawtypes" })
52+
public abstract List getRequestedServerNames();
53+
54+
@Override
55+
public void handshakeFinished() throws SSLException {
56+
wrapped.handshakeFinished();
57+
}
58+
59+
@Override
60+
public void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
61+
wrapped.tryExpandApplicationBufferSize(packetLengthDataOnly);
62+
}
63+
64+
@Override
65+
public String[] getLocalSupportedSignatureAlgorithms() {
66+
return LOCAL_SUPPORTED_SIGNATURE_ALGORITHMS.clone();
67+
}
68+
69+
@Override
70+
public String[] getPeerSupportedSignatureAlgorithms() {
71+
// Always return empty for now.
72+
return EmptyArrays.EMPTY_STRINGS;
73+
}
74+
75+
@Override
76+
public byte[] getId() {
77+
return wrapped.getId();
78+
}
79+
80+
@Override
81+
public SSLSessionContext getSessionContext() {
82+
return wrapped.getSessionContext();
83+
}
84+
85+
@Override
86+
public long getCreationTime() {
87+
return wrapped.getCreationTime();
88+
}
89+
90+
@Override
91+
public long getLastAccessedTime() {
92+
return wrapped.getLastAccessedTime();
93+
}
94+
95+
@Override
96+
public void invalidate() {
97+
wrapped.invalidate();
98+
}
99+
100+
@Override
101+
public boolean isValid() {
102+
return wrapped.isValid();
103+
}
104+
105+
@Override
106+
public void putValue(String s, Object o) {
107+
wrapped.putValue(s, o);
108+
}
109+
110+
@Override
111+
public Object getValue(String s) {
112+
return wrapped.getValue(s);
113+
}
114+
115+
@Override
116+
public void removeValue(String s) {
117+
wrapped.removeValue(s);
118+
}
119+
120+
@Override
121+
public String[] getValueNames() {
122+
return wrapped.getValueNames();
123+
}
124+
125+
@Override
126+
public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
127+
return wrapped.getPeerCertificates();
128+
}
129+
130+
@Override
131+
public Certificate[] getLocalCertificates() {
132+
return wrapped.getLocalCertificates();
133+
}
134+
135+
@Override
136+
public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
137+
return wrapped.getPeerCertificateChain();
138+
}
139+
140+
@Override
141+
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
142+
return wrapped.getPeerPrincipal();
143+
}
144+
145+
@Override
146+
public Principal getLocalPrincipal() {
147+
return wrapped.getLocalPrincipal();
148+
}
149+
150+
@Override
151+
public String getCipherSuite() {
152+
return wrapped.getCipherSuite();
153+
}
154+
155+
@Override
156+
public String getProtocol() {
157+
return wrapped.getProtocol();
158+
}
159+
160+
@Override
161+
public String getPeerHost() {
162+
return wrapped.getPeerHost();
163+
}
164+
165+
@Override
166+
public int getPeerPort() {
167+
return wrapped.getPeerPort();
168+
}
169+
170+
@Override
171+
public int getPacketBufferSize() {
172+
return wrapped.getPacketBufferSize();
173+
}
174+
175+
@Override
176+
public int getApplicationBufferSize() {
177+
return wrapped.getApplicationBufferSize();
178+
}
179+
}

handler/src/main/java/io/netty/handler/ssl/Java8SslUtils.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,18 @@ static List<String> getSniHostNames(SSLParameters sslParameters) {
4848
}
4949

5050
static void setSniHostNames(SSLParameters sslParameters, List<String> names) {
51+
sslParameters.setServerNames(getSniHostNames(names));
52+
}
53+
54+
static List getSniHostNames(List<String> names) {
55+
if (names == null || names.isEmpty()) {
56+
return Collections.emptyList();
57+
}
5158
List<SNIServerName> sniServerNames = new ArrayList<SNIServerName>(names.size());
5259
for (String name: names) {
5360
sniServerNames.add(new SNIHostName(name));
5461
}
55-
sslParameters.setServerNames(sniServerNames);
62+
return sniServerNames;
5663
}
5764

5865
static boolean getUseCipherSuitesOrder(SSLParameters sslParameters) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2018 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.ssl;
17+
18+
import javax.net.ssl.SSLException;
19+
import javax.net.ssl.SSLSession;
20+
21+
interface OpenSslSession extends SSLSession {
22+
23+
/**
24+
* Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
25+
* the user.
26+
*/
27+
void handshakeFinished() throws SSLException;
28+
29+
/**
30+
* Expand (or increase) the value returned by {@link #getApplicationBufferSize()} if necessary.
31+
* <p>
32+
* This is only called in a synchronized block, so no need to use atomic operations.
33+
* @param packetLengthDataOnly The packet size which exceeds the current {@link #getApplicationBufferSize()}.
34+
*/
35+
void tryExpandApplicationBufferSize(int packetLengthDataOnly);
36+
}

handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,17 @@ protected void deallocate() {
244244
OpenSsl.ensureAvailability();
245245
this.alloc = checkNotNull(alloc, "alloc");
246246
apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator();
247-
session = new OpenSslSession(context.sessionContext());
248247
clientMode = context.isClient();
248+
if (PlatformDependent.javaVersion() >= 7 && context.isClient()) {
249+
session = new ExtendedOpenSslSession(new DefaultOpenSslSession(context.sessionContext())) {
250+
@Override
251+
public List getRequestedServerNames() {
252+
return Java8SslUtils.getSniHostNames(sniHostNames);
253+
}
254+
};
255+
} else {
256+
session = new DefaultOpenSslSession(context.sessionContext());
257+
}
249258
engineMap = context.engineMap;
250259
localCerts = context.keyCertChain;
251260
keyMaterialManager = context.keyMaterialManager();
@@ -1839,7 +1848,7 @@ private static long bufferAddress(ByteBuffer b) {
18391848
return Buffer.address(b);
18401849
}
18411850

1842-
private final class OpenSslSession implements SSLSession {
1851+
private final class DefaultOpenSslSession implements OpenSslSession {
18431852
private final OpenSslSessionContext sessionContext;
18441853

18451854
// These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
@@ -1855,10 +1864,14 @@ private final class OpenSslSession implements SSLSession {
18551864
// lazy init for memory reasons
18561865
private Map<String, Object> values;
18571866

1858-
OpenSslSession(OpenSslSessionContext sessionContext) {
1867+
DefaultOpenSslSession(OpenSslSessionContext sessionContext) {
18591868
this.sessionContext = sessionContext;
18601869
}
18611870

1871+
private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) {
1872+
return new SSLSessionBindingEvent(session, name);
1873+
}
1874+
18621875
@Override
18631876
public byte[] getId() {
18641877
synchronized (ReferenceCountedOpenSslEngine.this) {
@@ -1925,7 +1938,8 @@ public void putValue(String name, Object value) {
19251938
}
19261939
Object old = values.put(name, value);
19271940
if (value instanceof SSLSessionBindingListener) {
1928-
((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
1941+
// Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
1942+
((SSLSessionBindingListener) value).valueBound(newSSLSessionBindingEvent(name));
19291943
}
19301944
notifyUnbound(old, name);
19311945
}
@@ -1965,15 +1979,17 @@ public String[] getValueNames() {
19651979

19661980
private void notifyUnbound(Object value, String name) {
19671981
if (value instanceof SSLSessionBindingListener) {
1968-
((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name));
1982+
// Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
1983+
((SSLSessionBindingListener) value).valueUnbound(newSSLSessionBindingEvent(name));
19691984
}
19701985
}
19711986

19721987
/**
19731988
* Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
19741989
* the user.
19751990
*/
1976-
void handshakeFinished() throws SSLException {
1991+
@Override
1992+
public void handshakeFinished() throws SSLException {
19771993
synchronized (ReferenceCountedOpenSslEngine.this) {
19781994
if (!isDestroyed()) {
19791995
id = SSL.getSessionId(ssl);
@@ -2191,13 +2207,8 @@ public int getApplicationBufferSize() {
21912207
return applicationBufferSize;
21922208
}
21932209

2194-
/**
2195-
* Expand (or increase) the value returned by {@link #getApplicationBufferSize()} if necessary.
2196-
* <p>
2197-
* This is only called in a synchronized block, so no need to use atomic operations.
2198-
* @param packetLengthDataOnly The packet size which exceeds the current {@link #getApplicationBufferSize()}.
2199-
*/
2200-
void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
2210+
@Override
2211+
public void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
22012212
if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH && applicationBufferSize != MAX_RECORD_SIZE) {
22022213
applicationBufferSize = MAX_RECORD_SIZE;
22032214
}

0 commit comments

Comments
 (0)