#9397 add quiche_conn_peer_cert() API mapping
Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
parent
07a1c124f2
commit
b3b1d93152
|
@ -483,6 +483,31 @@ public class ForeignIncubatorQuicheConnection extends QuicheConnection
|
|||
}
|
||||
}
|
||||
|
||||
public byte[] getPeerCertificate()
|
||||
{
|
||||
try (AutoLock ignore = lock.lock())
|
||||
{
|
||||
if (quicheConn == null)
|
||||
throw new IllegalStateException("connection was released");
|
||||
|
||||
try (ResourceScope scope = ResourceScope.newConfinedScope())
|
||||
{
|
||||
MemorySegment outSegment = MemorySegment.allocateNative(CLinker.C_POINTER, scope);
|
||||
MemorySegment outLenSegment = MemorySegment.allocateNative(CLinker.C_LONG, scope);
|
||||
quiche_h.quiche_conn_peer_cert(quicheConn, outSegment.address(), outLenSegment.address());
|
||||
|
||||
long outLen = getLong(outLenSegment);
|
||||
if (outLen == 0L)
|
||||
return null;
|
||||
byte[] out = new byte[(int)outLen];
|
||||
// dereference outSegment pointer
|
||||
MemoryAddress memoryAddress = MemoryAddress.ofLong(getLong(outSegment));
|
||||
memoryAddress.asSegment(outLen, ResourceScope.globalScope()).asByteBuffer().get(out);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Long> iterableStreamIds(boolean write)
|
||||
{
|
||||
|
|
|
@ -250,6 +250,12 @@ public class quiche_h
|
|||
FunctionDescriptor.of(C_CHAR, C_POINTER)
|
||||
);
|
||||
|
||||
private static final MethodHandle quiche_conn_peer_cert$MH = downcallHandle(
|
||||
"quiche_conn_peer_cert",
|
||||
"(Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;)V",
|
||||
FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_POINTER)
|
||||
);
|
||||
|
||||
private static final MethodHandle quiche_conn_peer_error$MH = downcallHandle(
|
||||
"quiche_conn_peer_error",
|
||||
"(Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;Ljdk/incubator/foreign/MemoryAddress;)B",
|
||||
|
@ -688,6 +694,18 @@ public class quiche_h
|
|||
}
|
||||
}
|
||||
|
||||
public static void quiche_conn_peer_cert(MemoryAddress conn, MemoryAddress out, MemoryAddress out_len)
|
||||
{
|
||||
try
|
||||
{
|
||||
quiche_conn_peer_cert$MH.invokeExact(conn, out, out_len);
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
throw new AssertionError("should not reach here", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte quiche_conn_peer_error(MemoryAddress conn, MemoryAddress is_app, MemoryAddress error_code, MemoryAddress reason, MemoryAddress reason_len)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -20,19 +20,19 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.quic.quiche.QuicheConfig;
|
||||
import org.eclipse.jetty.quic.quiche.QuicheConnection;
|
||||
import org.eclipse.jetty.quic.quiche.SSLKeyPair;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -57,6 +57,7 @@ public class LowLevelQuicheTest
|
|||
private QuicheConfig serverQuicheConfig;
|
||||
private ForeignIncubatorQuicheConnection.TokenMinter tokenMinter;
|
||||
private ForeignIncubatorQuicheConnection.TokenValidator tokenValidator;
|
||||
private Certificate[] serverCertificateChain;
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception
|
||||
|
@ -82,6 +83,7 @@ public class LowLevelQuicheTest
|
|||
{
|
||||
keyStore.load(is, "storepwd".toCharArray());
|
||||
}
|
||||
serverCertificateChain = keyStore.getCertificateChain("mykey");
|
||||
SSLKeyPair serverKeyPair = new SSLKeyPair(keyStore, "mykey", "storepwd".toCharArray());
|
||||
Path[] pemFiles = serverKeyPair.export(workDir.getEmptyPathDir());
|
||||
serverQuicheConfig = new QuicheConfig();
|
||||
|
@ -147,6 +149,11 @@ public class LowLevelQuicheTest
|
|||
|
||||
// assert that stream 0 is finished on server
|
||||
assertThat(serverQuicheConnection.isStreamFinished(0), is(true));
|
||||
|
||||
// assert that the server certificate was correctly received by the client
|
||||
byte[] peerCertificate = clientQuicheConnection.getPeerCertificate();
|
||||
byte[] serverCert = serverCertificateChain[0].getEncoded();
|
||||
assertThat(Arrays.equals(serverCert, peerCertificate), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -180,6 +187,11 @@ public class LowLevelQuicheTest
|
|||
|
||||
// assert that stream 0 is finished on server
|
||||
assertThat(serverQuicheConnection.isStreamFinished(0), is(true));
|
||||
|
||||
// assert that the server certificate was correctly received by the client
|
||||
byte[] peerCertificate = clientQuicheConnection.getPeerCertificate();
|
||||
byte[] serverCert = serverCertificateChain[0].getEncoded();
|
||||
assertThat(Arrays.equals(serverCert, peerCertificate), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -195,6 +207,11 @@ public class LowLevelQuicheTest
|
|||
|
||||
assertThat(clientQuicheConnection.getNegotiatedProtocol(), is("€"));
|
||||
assertThat(serverQuicheConnection.getNegotiatedProtocol(), is("€"));
|
||||
|
||||
// assert that the server certificate was correctly received by the client
|
||||
byte[] peerCertificate = clientQuicheConnection.getPeerCertificate();
|
||||
byte[] serverCert = serverCertificateChain[0].getEncoded();
|
||||
assertThat(Arrays.equals(serverCert, peerCertificate), is(true));
|
||||
}
|
||||
|
||||
private void drainServerToFeedClient(Map.Entry<ForeignIncubatorQuicheConnection, ForeignIncubatorQuicheConnection> entry, int expectedSize) throws IOException
|
||||
|
|
|
@ -385,8 +385,29 @@ public class JnaQuicheConnection extends QuicheConnection
|
|||
|
||||
public void enableQlog(String filename, String title, String desc) throws IOException
|
||||
{
|
||||
if (!LibQuiche.INSTANCE.quiche_conn_set_qlog_path(quicheConn, filename, title, desc))
|
||||
throw new IOException("unable to set qlog path to " + filename);
|
||||
try (AutoLock ignore = lock.lock())
|
||||
{
|
||||
if (quicheConn == null)
|
||||
throw new IllegalStateException("connection was released");
|
||||
|
||||
if (!LibQuiche.INSTANCE.quiche_conn_set_qlog_path(quicheConn, filename, title, desc))
|
||||
throw new IOException("unable to set qlog path to " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getPeerCertificate()
|
||||
{
|
||||
try (AutoLock ignore = lock.lock())
|
||||
{
|
||||
if (quicheConn == null)
|
||||
throw new IllegalStateException("connection was released");
|
||||
|
||||
char_pointer out = new char_pointer();
|
||||
size_t_pointer out_len = new size_t_pointer();
|
||||
LibQuiche.INSTANCE.quiche_conn_peer_cert(quicheConn, out, out_len);
|
||||
int len = out_len.getPointee().intValue();
|
||||
return out.getValueAsBytes(len);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -425,6 +425,9 @@ public interface LibQuiche extends Library
|
|||
// Returns true if the connection was closed due to the idle timeout.
|
||||
boolean quiche_conn_is_timed_out(quiche_conn conn);
|
||||
|
||||
// Returns the peer's leaf certificate (if any) as a DER-encoded buffer.
|
||||
void quiche_conn_peer_cert(quiche_conn conn, char_pointer out, size_t_pointer out_len);
|
||||
|
||||
// Returns true if a connection error was received, and updates the provided
|
||||
// parameters accordingly.
|
||||
boolean quiche_conn_peer_error(quiche_conn conn,
|
||||
|
|
|
@ -23,4 +23,9 @@ public class char_pointer extends PointerByReference
|
|||
{
|
||||
return new String(getValue().getByteArray(0, len), charset);
|
||||
}
|
||||
|
||||
public byte[] getValueAsBytes(int len)
|
||||
{
|
||||
return getValue().getByteArray(0, len);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,19 +19,19 @@ import java.net.InetSocketAddress;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.quic.quiche.QuicheConfig;
|
||||
import org.eclipse.jetty.quic.quiche.QuicheConnection;
|
||||
import org.eclipse.jetty.quic.quiche.SSLKeyPair;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -56,6 +56,7 @@ public class LowLevelQuicheTest
|
|||
private QuicheConfig serverQuicheConfig;
|
||||
private JnaQuicheConnection.TokenMinter tokenMinter;
|
||||
private JnaQuicheConnection.TokenValidator tokenValidator;
|
||||
private Certificate[] serverCertificateChain;
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp() throws Exception
|
||||
|
@ -81,6 +82,7 @@ public class LowLevelQuicheTest
|
|||
{
|
||||
keyStore.load(is, "storepwd".toCharArray());
|
||||
}
|
||||
serverCertificateChain = keyStore.getCertificateChain("mykey");
|
||||
SSLKeyPair serverKeyPair = new SSLKeyPair(keyStore, "mykey", "storepwd".toCharArray());
|
||||
Path[] pemFiles = serverKeyPair.export(workDir.getEmptyPathDir());
|
||||
serverQuicheConfig = new QuicheConfig();
|
||||
|
@ -146,6 +148,11 @@ public class LowLevelQuicheTest
|
|||
|
||||
// assert that stream 0 is finished on server
|
||||
assertThat(serverQuicheConnection.isStreamFinished(0), is(true));
|
||||
|
||||
// assert that the server certificate was correctly received by the client
|
||||
byte[] peerCertificate = clientQuicheConnection.getPeerCertificate();
|
||||
byte[] serverCert = serverCertificateChain[0].getEncoded();
|
||||
assertThat(Arrays.equals(serverCert, peerCertificate), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -179,6 +186,11 @@ public class LowLevelQuicheTest
|
|||
|
||||
// assert that stream 0 is finished on server
|
||||
assertThat(serverQuicheConnection.isStreamFinished(0), is(true));
|
||||
|
||||
// assert that the server certificate was correctly received by the client
|
||||
byte[] peerCertificate = clientQuicheConnection.getPeerCertificate();
|
||||
byte[] serverCert = serverCertificateChain[0].getEncoded();
|
||||
assertThat(Arrays.equals(serverCert, peerCertificate), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -194,6 +206,11 @@ public class LowLevelQuicheTest
|
|||
|
||||
assertThat(clientQuicheConnection.getNegotiatedProtocol(), is("€"));
|
||||
assertThat(serverQuicheConnection.getNegotiatedProtocol(), is("€"));
|
||||
|
||||
// assert that the server certificate was correctly received by the client
|
||||
byte[] peerCertificate = clientQuicheConnection.getPeerCertificate();
|
||||
byte[] serverCert = serverCertificateChain[0].getEncoded();
|
||||
assertThat(Arrays.equals(serverCert, peerCertificate), is(true));
|
||||
}
|
||||
|
||||
private void drainServerToFeedClient(Map.Entry<JnaQuicheConnection, JnaQuicheConnection> entry, int expectedSize) throws IOException
|
||||
|
|
Loading…
Reference in New Issue