Skip to content

Commit c2bbcae

Browse files
committed
use HandshakeCertificates in TlsEndpoint
1 parent 094d5dd commit c2bbcae

35 files changed

+889
-533
lines changed

core/src/main/java/jayo/internal/RealTlsEndpoint.java

+43-15
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,26 @@
1111
package jayo.internal;
1212

1313
import jayo.*;
14+
import jayo.internal.tls.RealClientTlsEndpoint;
15+
import jayo.internal.tls.RealServerTlsEndpoint;
1416
import jayo.tls.Handshake;
1517
import jayo.tls.JayoTlsException;
1618
import jayo.tls.JayoTlsHandshakeCallbackException;
1719
import jayo.tls.TlsEndpoint;
1820
import org.jspecify.annotations.NonNull;
1921
import org.jspecify.annotations.Nullable;
2022

21-
import javax.net.ssl.SSLEngine;
22-
import javax.net.ssl.SSLEngineResult;
23+
import javax.net.ssl.*;
2324
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
2425
import javax.net.ssl.SSLEngineResult.Status;
25-
import javax.net.ssl.SSLException;
26-
import javax.net.ssl.SSLSession;
2726
import java.io.Serial;
2827
import java.nio.ByteBuffer;
2928
import java.util.Arrays;
3029
import java.util.Objects;
3130
import java.util.concurrent.locks.Lock;
3231
import java.util.concurrent.locks.ReentrantLock;
3332
import java.util.function.Consumer;
33+
import java.util.function.Function;
3434

3535
import static java.lang.System.Logger.Level.DEBUG;
3636
import static java.lang.System.Logger.Level.TRACE;
@@ -70,17 +70,17 @@ public final class RealTlsEndpoint {
7070
/**
7171
* Whether an IOException was received from the underlying endpoint or from the {@link SSLEngine}.
7272
*/
73-
volatile boolean invalid = false;
73+
private volatile boolean invalid = false;
7474

7575
/**
7676
* Whether a close_notify was already sent.
7777
*/
78-
volatile boolean shutdownSent = false;
78+
private volatile boolean shutdownSent = false;
7979

8080
/**
8181
* Whether a close_notify was already received.
8282
*/
83-
volatile boolean shutdownReceived = false;
83+
private volatile boolean shutdownReceived = false;
8484

8585
/**
8686
* Decrypted data from encryptedReader
@@ -101,7 +101,7 @@ public final class RealTlsEndpoint {
101101

102102
private int remainingBytesToRead;
103103

104-
RealTlsEndpoint(
104+
public RealTlsEndpoint(
105105
final @NonNull Endpoint encryptedEndpoint,
106106
final @NonNull SSLEngine engine,
107107
final @NonNull Consumer<@NonNull SSLSession> sessionInitCallback,
@@ -125,14 +125,14 @@ public final class RealTlsEndpoint {
125125
}
126126

127127
@NonNull
128-
Handshake getHandshake() {
128+
public Handshake getHandshake() {
129129
// on-demand Handshake creation, only if user calls it
130130
return Handshake.get(engine.getSession());
131131
}
132132

133133
// read
134134

135-
long readAtMostTo(final @NonNull Buffer writer, final long byteCount) {
135+
public long readAtMostTo(final @NonNull Buffer writer, final long byteCount) {
136136
Objects.requireNonNull(writer);
137137
if (byteCount < 0L) {
138138
throw new IllegalArgumentException("byteCount < 0: " + byteCount);
@@ -210,6 +210,7 @@ private void readAndUnwrap() throws TlsEOFException {
210210
}
211211
}
212212
if (result.getStatus() == Status.CLOSED) {
213+
System.out.println(this + " status closed, shutdown received");
213214
shutdownReceived = true;
214215
return;
215216
}
@@ -345,7 +346,7 @@ private int callReadFromReader() throws TlsEOFException {
345346

346347
// write
347348

348-
void write(final @NonNull Buffer reader, final long byteCount) {
349+
public void write(final @NonNull Buffer reader, final long byteCount) {
349350
Objects.requireNonNull(reader);
350351
checkOffsetAndCount(reader.bytesAvailable(), 0L, byteCount);
351352

@@ -628,6 +629,25 @@ public boolean shutdown() {
628629
}
629630
}
630631

632+
public boolean shutdownReceived() {
633+
readLock.lock();
634+
try {
635+
writeLock.lock();
636+
try {
637+
System.out.println(this + " Shutdown received : " + shutdownReceived);
638+
return shutdownReceived;
639+
} finally {
640+
writeLock.unlock();
641+
}
642+
} finally {
643+
readLock.unlock();
644+
}
645+
}
646+
647+
public boolean shutdownSent() {
648+
return shutdownSent;
649+
}
650+
631651
private void freeBuffer() {
632652
decryptedBuffer.clear();
633653
}
@@ -668,13 +688,21 @@ public Throwable fillInStackTrace() {
668688
* The base class for builders of {@link TlsEndpoint}.
669689
*/
670690
public static sealed abstract class Builder<T extends TlsEndpoint.Builder<T>> implements TlsEndpoint.Builder<T>
671-
permits ClientTlsEndpoint.Builder, ServerTlsEndpoint.Builder {
691+
permits RealClientTlsEndpoint.Builder, RealServerTlsEndpoint.Builder {
692+
protected @Nullable Function<@NonNull SSLContext, @NonNull SSLEngine> sslEngineFactory = null;
672693
// @formatter:off
673-
@NonNull Consumer<@NonNull SSLSession> sessionInitCallback = session -> {};
694+
protected @NonNull Consumer<@NonNull SSLSession> sessionInitCallback = session -> {};
674695
// @formatter:on
675-
boolean waitForCloseConfirmation = false;
696+
protected boolean waitForCloseConfirmation = false;
676697

677-
abstract @NonNull T getThis();
698+
protected abstract @NonNull T getThis();
699+
700+
@Override
701+
public @NonNull T engineFactory(
702+
final @NonNull Function<@NonNull SSLContext, @NonNull SSLEngine> sslEngineFactory) {
703+
this.sslEngineFactory = Objects.requireNonNull(sslEngineFactory);
704+
return getThis();
705+
}
678706

679707
@Override
680708
public final @NonNull T sessionInitCallback(final @NonNull Consumer<@NonNull SSLSession> sessionInitCallback) {

core/src/main/java/jayo/internal/ClientTlsEndpoint.java renamed to core/src/main/java/jayo/internal/tls/RealClientTlsEndpoint.java

+63-42
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,64 @@
88
* Licensed under the MIT License
99
*/
1010

11-
package jayo.internal;
11+
package jayo.internal.tls;
1212

1313
import jayo.*;
14-
import jayo.tls.Handshake;
15-
import jayo.tls.TlsEndpoint;
14+
import jayo.internal.RealTlsEndpoint;
15+
import jayo.tls.*;
1616
import org.jspecify.annotations.NonNull;
1717

1818
import javax.net.ssl.SSLContext;
1919
import javax.net.ssl.SSLEngine;
2020
import javax.net.ssl.SSLSession;
21-
import java.security.NoSuchAlgorithmException;
2221
import java.util.Objects;
2322
import java.util.function.Consumer;
23+
import java.util.function.Function;
24+
25+
import static java.lang.System.Logger.Level.DEBUG;
26+
import static java.lang.System.Logger.Level.TRACE;
2427

2528
/**
2629
* A client-side {@link TlsEndpoint}.
2730
*/
28-
public final class ClientTlsEndpoint implements TlsEndpoint {
31+
public final class RealClientTlsEndpoint implements ClientTlsEndpoint {
32+
private static final System.Logger LOGGER = System.getLogger("jayo.tls.ClientTlsEndpoint");
33+
2934
private final @NonNull Endpoint encryptedEndpoint;
35+
private final @NonNull ClientHandshakeCertificates handshakeCertificates;
3036
private final @NonNull RealTlsEndpoint impl;
3137

3238
private Reader reader = null;
3339
private Writer writer = null;
3440

35-
private ClientTlsEndpoint(
41+
private RealClientTlsEndpoint(
3642
final @NonNull Endpoint encryptedEndpoint,
37-
final @NonNull SSLEngine engine,
43+
final @NonNull ClientHandshakeCertificates handshakeCertificates,
44+
final @NonNull Function<@NonNull SSLContext, @NonNull SSLEngine> engineFactory,
3845
final @NonNull Consumer<@NonNull SSLSession> sessionInitCallback,
3946
final boolean waitForCloseConfirmation) {
4047
assert encryptedEndpoint != null;
48+
assert handshakeCertificates != null;
49+
assert engineFactory != null;
4150
assert sessionInitCallback != null;
42-
assert engine != null;
4351

4452
this.encryptedEndpoint = encryptedEndpoint;
53+
this.handshakeCertificates = handshakeCertificates;
54+
55+
final var context = ((RealHandshakeCertificates) handshakeCertificates).sslContext();
56+
// call client code
57+
final SSLEngine engine;
58+
try {
59+
engine = engineFactory.apply(context);
60+
} catch (Exception e) {
61+
if (LOGGER.isLoggable(TRACE)) {
62+
LOGGER.log(TRACE, "Client threw exception in SSLEngine factory.", e);
63+
} else if (LOGGER.isLoggable(DEBUG)) {
64+
LOGGER.log(DEBUG, "Client threw exception in SSLEngine factory: {0}.",
65+
e.getMessage());
66+
}
67+
throw new JayoTlsHandshakeCallbackException("SSLEngine creation callback failed", e);
68+
}
4569

4670
impl = new RealTlsEndpoint(
4771
encryptedEndpoint,
@@ -83,81 +107,78 @@ public boolean shutdown() {
83107

84108
@Override
85109
public boolean shutdownReceived() {
86-
return impl.shutdownReceived;
110+
return impl.shutdownReceived();
87111
}
88112

89113
@Override
90114
public boolean shutdownSent() {
91-
return impl.shutdownSent;
115+
return impl.shutdownSent();
92116
}
93117

94118
@Override
95119
public void close() {
96120
impl.close();
97121
}
98122

123+
@Override
124+
public @NonNull ClientHandshakeCertificates getHandshakeCertificates() {
125+
return handshakeCertificates;
126+
}
127+
128+
private static @NonNull SSLEngine defaultSSLEngineFactory(final @NonNull SSLContext sslContext) {
129+
assert sslContext != null;
130+
SSLEngine engine = sslContext.createSSLEngine();
131+
engine.setUseClientMode(true);
132+
return engine;
133+
}
134+
99135
/**
100-
* Builder of {@link ClientTlsEndpoint}
136+
* Builder of {@link RealClientTlsEndpoint}
101137
*/
102-
public static final class Builder extends RealTlsEndpoint.Builder<ClientBuilder> implements ClientBuilder {
103-
private final @NonNull SSLEngine engine;
104-
105-
public Builder() {
106-
// todo change this!
107-
try {
108-
engine = SSLContext.getDefault().createSSLEngine();
109-
} catch (NoSuchAlgorithmException e) {
110-
throw new RuntimeException(e);
111-
}
112-
engine.setUseClientMode(true);
113-
}
114-
115-
public Builder(final @NonNull SSLContext sslContext) {
116-
assert sslContext != null;
138+
public static final class Builder extends RealTlsEndpoint.Builder<ClientTlsEndpoint.Builder>
139+
implements ClientTlsEndpoint.Builder {
140+
private final @NonNull ClientHandshakeCertificates handshakeCertificates;
117141

118-
engine = sslContext.createSSLEngine();
119-
engine.setUseClientMode(true);
120-
}
121142

122-
public Builder(final @NonNull SSLEngine engine) {
123-
assert engine != null;
143+
public Builder(final @NonNull ClientHandshakeCertificates handshakeCertificates) {
144+
assert handshakeCertificates != null;
124145

125-
this.engine = engine;
146+
this.handshakeCertificates = handshakeCertificates;
126147
}
127148

128149
/**
129150
* The private constructor used by {@link #clone()}.
130151
*/
131-
private Builder(final @NonNull SSLEngine engine,
152+
private Builder(final @NonNull ClientHandshakeCertificates handshakeCertificates,
132153
final @NonNull Consumer<@NonNull SSLSession> sessionInitCallback,
133154
final boolean waitForCloseConfirmation) {
134-
assert engine != null;
155+
assert handshakeCertificates != null;
135156
assert sessionInitCallback != null;
136157

137-
this.engine = engine;
158+
this.handshakeCertificates = handshakeCertificates;
138159
this.sessionInitCallback = sessionInitCallback;
139160
this.waitForCloseConfirmation = waitForCloseConfirmation;
140161
}
141162

142163
@Override
143-
@NonNull
144-
Builder getThis() {
164+
protected @NonNull Builder getThis() {
145165
return this;
146166
}
147167

148168
@Override
149-
public @NonNull TlsEndpoint build(final @NonNull Endpoint encryptedEndpoint) {
169+
public @NonNull ClientTlsEndpoint build(final @NonNull Endpoint encryptedEndpoint) {
150170
Objects.requireNonNull(encryptedEndpoint);
151-
return new ClientTlsEndpoint(
171+
return new RealClientTlsEndpoint(
152172
encryptedEndpoint,
153-
engine,
173+
handshakeCertificates,
174+
(sslEngineFactory != null) ? sslEngineFactory : RealClientTlsEndpoint::defaultSSLEngineFactory,
154175
sessionInitCallback,
155176
waitForCloseConfirmation);
156177
}
157178

158179
@Override
159-
public @NonNull ClientBuilder clone() {
160-
return new Builder(engine, sessionInitCallback, waitForCloseConfirmation);
180+
public @NonNull Builder clone() {
181+
return new Builder(handshakeCertificates, sessionInitCallback, waitForCloseConfirmation);
161182
}
162183
}
163184

0 commit comments

Comments
 (0)